Exemplo n.º 1
0
    public void shoot(float delta, bool isPuppet)
    {
        if (reloadWeapon)
        {
            return;
        }
        if (!isPuppet)
        {
            return;
        }

        // Get bullet ray.
        RayCast bulletRay = (RayCast)camera.GetNode("bullet_ray");

        if (bullets > 0)
        {
            bullets -= 1;

            // Notify bullet update
            GameState.instance.EmitSignal(nameof(GameState.updateWeapon), weaponName, bullets, ammo);

            if (camera != null)
            {
                // Recoil
                camera.Rotation = new Vector3(
                    Mathf.Lerp(camera.Rotation.x, (float)GD.RandRange(1, 2), delta),
                    Mathf.Lerp(camera.Rotation.y, (float)GD.RandRange(-1, 1), delta),
                    camera.Rotation.z
                    );

                // Shake
                camera.Set("shakeForce", 0.002);
                camera.Set("shakeTime", 0.2);
            }

            // Audio
            AudioStreamPlayer3D shoot = ((AudioStreamPlayer3D)audioNode.GetNode("shoot"));
            shoot.PitchScale = (float)GD.RandRange(0.9, 1.1);
            shoot.Play();

            // Update crosshair
            crosshair.RectScale = crosshair.RectScale.LinearInterpolate(new Vector2(4, 4), 10 * delta);

            if (bulletRay.IsColliding())
            {
                // Object collision
                CollisionObject collisionObject = (CollisionObject)bulletRay.GetCollider();

                // Add spark to props.
                if (collisionObject.IsInGroup("props"))
                {
                    // Add Spark
                    Particles spark = (Particles)sparkScene.Instance();
                    ((Node)bulletRay.GetCollider()).AddChild(spark);

                    spark.GlobalTransform = new Transform(spark.GlobalTransform.basis, bulletRay.GetCollisionPoint());
                    spark.Emitting        = true;
                }

                // Add Muzzle
                Particles muzzle = (Particles)muzzleScene.Instance();
                barrelNode.AddChild(muzzle);
                muzzle.Emitting = true;

                if (collisionObject is KinematicBody)
                {
                    // Add Blood splatter
                    Particles splatter = (Particles)splatterScene.Instance();
                    ((Node)bulletRay.GetCollider()).AddChild(splatter);

                    splatter.GlobalTransform = new Transform(splatter.GlobalTransform.basis, bulletRay.GetCollisionPoint());
                    splatter.Emitting        = true;

                    int localDamage = 0;
                    if (collisionObject.IsInGroup("head"))
                    {
                        localDamage = (int)GD.RandRange(damage / 2, damage);
                    }
                    else
                    {
                        localDamage = (int)GD.RandRange(damage / 3, damage / 2);
                    }

                    int colliderId = Convert.ToInt32(collisionObject.Name);

                    // Send damage report.
                    GameState.instance.EmitSignal(nameof(GameState.takeDamage), colliderId, localDamage);
                    return;
                }
                else if (collisionObject.IsInGroup("props") || collisionObject.IsInGroup("walls"))
                {
                    // Apply force to rigid body other than hitbox
                    if (bulletRay.GetCollider() is RigidBody)
                    {
                        int localDamage = (int)GD.RandRange(damage / 1.5f, damage);
                        ((RigidBody)bulletRay.GetCollider()).ApplyCentralImpulse(-bulletRay.GetCollisionNormal() * (localDamage * 0.3f));
                    }

                    // Apply decal
                    Spatial decal = (Spatial)decalScene.Instance();
                    ((Node)bulletRay.GetCollider()).AddChild(decal);
                    decal.GlobalTransform = new Transform(
                        decal.GlobalTransform.basis,
                        bulletRay.GetCollisionPoint()
                        );

                    decal.LookAt(bulletRay.GetCollisionPoint() + bulletRay.GetCollisionNormal(), new Vector3(1, 1, 0));
                    return;
                }
            }
        }
        else
        {
            AudioStreamPlayer3D empty = ((AudioStreamPlayer3D)audioNode.GetNode("empty"));
            if (!empty.Playing)
            {
                empty.PitchScale = (float)GD.RandRange(0.9, 1.1);
                empty.Play();
            }
        }
    }
    public override void _PhysicsProcess(float delta)
    {
        base._PhysicsProcess(delta);

        // check if the wave nearest the player has passed the global z-axis zero point
        // At that point it is not longer cutable, and must be removed
        var nearestWave = WaveInstances.FirstOrDefault();

        if (nearestWave != null &&
            nearestWave.GlobalTransform.origin.z >= 1)
        {
            // wave should have faded-out by now, so remove it from the scene.
            WaveInstances.Remove(nearestWave);

            nearestWave.Remove();
            nearestWave.QueueFree();
        }
        else if (nearestWave != null &&
                 nearestWave.GlobalTransform.origin.z >= 0)
        {
            nearestWave.SetForRemoval();
        }

        // check for a collision with the ribbon
        // Check all waves within 1m of global origin for cuts
        foreach (var waveInstance in WaveInstances)
        {
            if (waveInstance.GlobalTransform.origin.z > -1)             // only check for cuts when wave is near player origin
            {
                waveInstance.SetActive();

                if (waveInstance.WaveCut(RibbonPoints))
                {
                    // todo - if all the segments are cut, play a special sound effect?
                }
            }
        }

        // check if it's time to emit another wave
        // Previously attempted to do this with a Timer, and also with OS.ticks() method, but both fell out of sync with audio over duration of track.
        // Using GetPlaybackPosition() to time wave emission seems to be effective
        // todo - investigate method here: https://docs.godotengine.org/en/stable/tutorials/audio/sync_with_audio.html#using-the-sound-hardware-clock-to-sync
        if (Active &&
            AudioStreamPlayer.GetPlaybackPosition() >= NextEmissionTime - WARP_TIME)
        {
            // Initialise a new wave
            var waveInstance = WaveScene.Instance() as Wave;
            WaveSpawnPoint.AddChild(waveInstance);

            waveInstance.Initialise(WaveSequence.GetNextWave());
            WaveInstances.Add(waveInstance);

            // "warp" the wave in quickly...
            WaveMovementTween.InterpolateProperty(waveInstance, "translation:z", -30, 0, WARP_TIME);

            // ...then move the wave towards the player at a reasonable speed (n.b. this tween starts after a delay)
            var animationDuration = 3f;
            WaveMovementTween.InterpolateProperty(waveInstance, "translation:z", 0, 3, animationDuration, delay: WARP_TIME);

            if (waveInstance.RotationRateRad != 0)
            {
                // some waves will also rotate as they move toward the player (n.b. this tween starts after a delay)
                var rotationStart = waveInstance.Rotation.z;
                var rotationEnd   = waveInstance.Rotation.z + (waveInstance.RotationRateRad * animationDuration);
                WaveMovementTween.InterpolateProperty(waveInstance, "rotation:z", rotationStart, rotationEnd, animationDuration, delay: WARP_TIME);
            }

            WaveMovementTween.Start();

            var nextWaveDelay = WaveSequence.GetNextWaveDelay();
            if (nextWaveDelay.HasValue)
            {
                NextEmissionTime += nextWaveDelay.Value;
            }
            else
            {
                // no waves left in sequence
                Active = false;
            }
        }
    }