Пример #1
0
    public override void AEnterTree() //TODO Try moving everything non-visual to Physics Processing
    {
        PlayerSprite      = GetNodeOrNull(new NodePath("PlayerSprite")) as AnimatedSprite3D;
        ActorDetectorArea = GetNodeOrNull(new NodePath("ActorDetector")) as Area;

        if (PlayerSprite == null || ActorDetectorArea == null)
        {
            GD.PrintErr("One or multiple required child nodes could not be found!");
        }

        //Define states

        StandState = new ActorState(() =>
        { //Enter State
            PlayerSprite.SetAnimation("Idle");
            SnapToGround = true;
        }, (float delta) =>
        { //Process State
        }, (float delta) =>
        { //State Physics Processing
            //Switch to the walking state when directional input is given
            bool sideInput = Mathf.Abs(Input.GetActionStrength("p1_right") - Input.GetActionStrength("p1_left")) > 0;
            if (sideInput)
            {
                ChangeState(WalkState);
            }

            CanFall();
            CanJump();
        }, () =>
        { //Exit State
        });


        WalkState = new ActorState(() =>
        { //Enter State
            PlayerSprite.SetAnimation("Walk");
            SnapToGround = true;
        }, (float delta) =>
        { //Process State
        }, (float delta) =>
        { //State Physics Processing
            //Switch to the standing state when no directional input is given
            float sideInput = Input.GetActionStrength("p1_right") - Input.GetActionStrength("p1_left");
            if (sideInput == 0)
            {
                ChangeState(StandState);
            }

            //Check if the player should be running, if yes go to run state
            bool isRunPressed = Input.GetActionStrength("p1_run") > 0;
            if (isRunPressed)
            {
                ChangeState(RunState);
            }

            //Move the player
            Vector2 movement = new Vector2();
            movement.x       = sideInput * WalkAcceleration;
            //movement.x = Mathf.Abs(Velocity.x) + Mathf.Abs(movement.x) > MaxWalkSpeed ? (MaxWalkSpeed - Mathf.Abs(Velocity.x)) * Mathf.Sign(movement.x) : movement.x;
            ApplyForce2D(movement);

            //Update the walking animation speed
            PlayerSprite.Frames.SetAnimationSpeed("Walk", (Mathf.Abs(Velocity.x) / 2) + 8);

            CanFall();
            CanJump();

            //Enforce walk speed limit
            if (Math.Abs(Velocity.x) >= MaxWalkSpeed)
            {
                Velocity.x = ClampedInterpolation.Lerp(Velocity.x, MaxWalkSpeed * Mathf.Sign(Velocity.x), GetElapsedTimeInState());
            }
        }, () =>
        { //Exit State
        });


        RunState = new ActorState(() =>
        { //Enter State
            PlayerSprite.SetAnimation("Walk");
            SnapToGround = true;
        }, (float delta) =>
        { //Process State
        }, (float delta) =>
        { //State Physics Processing
            //Switch to the standing state when no directional input is given
            float sideInput = Input.GetActionStrength("p1_right") - Input.GetActionStrength("p1_left");
            if (sideInput == 0)
            {
                ChangeState(StandState);
            }

            //Check if the player should be running, if not go back to walk state
            bool isRunPressed = Input.GetActionStrength("p1_run") > 0;
            if (!isRunPressed)
            {
                ChangeState(WalkState);
            }

            //Move the player
            Vector2 movement = new Vector2();
            movement.x       = sideInput * RunAcceleration;
            //movement.x = Mathf.Abs(Velocity.x) + Mathf.Abs(movement.x) > MaxRunSpeed ? (MaxRunSpeed - Mathf.Abs(Velocity.x)) * Mathf.Sign(movement.x) : movement.x;
            ApplyForce2D(movement);

            //Update the walking animation speed
            PlayerSprite.Frames.SetAnimationSpeed("Walk", Mathf.Max((Mathf.Abs(Velocity.x)) + 2, (Mathf.Abs(Velocity.x) / 2) + 8));

            CanFall();
            CanJump();

            //Enforce walk speed limit
            if (Math.Abs(Velocity.x) >= MaxRunSpeed)
            {
                Velocity.x = ClampedInterpolation.Lerp(Velocity.x, MaxRunSpeed * Mathf.Sign(Velocity.x), GetElapsedTimeInState());
            }
        }, () =>
        { //Exit State
        });


        JumpState = new ActorState(() =>
        { //Enter State
            GD.Print("Jump");

            PlayerSprite.SetAnimation("Jump");
            SnapToGround = false;

            JumpSpeedBuffer = Velocity.x;

            //Add the initial force of the jump
            ApplyForce2D(new Vector2(0, JumpSpeed));
        }, (float delta) =>
        { //Process State
        }, (float delta) =>
        { //State Physics Processing
            float jumpTime = GetElapsedTimeInState();
            DebugText.Display("jumpTime", "Jump Time: " + jumpTime);

            //Add some force for extra air time if the jump button is held
            ApplyForce2D(Vector2.Up, Gravity.y * (1 - JumpSustainGravityMultiplier));

            //Allow slight player movement
            float sideInput  = Input.GetActionStrength("p1_right") - Input.GetActionStrength("p1_left");
            Vector2 movement = new Vector2();
            movement.x       = sideInput * (AirAcceleration);
            ApplyForce2D(movement);

            //Exit state if required
            bool jumpPressed = Input.GetActionStrength("p1_jump") > 0;
            if (!jumpPressed || jumpTime > MaxJumpTime)
            {
                ChangeState(FallState);
            }
            if (IsOnFloor())
            {
                ChangeState(StandState);
            }

            //Enforce air speed limit
            float speedLimit = Mathf.Min(Mathf.Abs(JumpSpeedBuffer), MaxRunSpeed);
            if (Mathf.Abs(Velocity.x) >= speedLimit)
            {
                Velocity.x = ClampedInterpolation.Lerp(Velocity.x, speedLimit * Mathf.Sign(Velocity.x), GetElapsedTimeInState());
            }
        }, () =>
        { //Exit State
            DebugText.Remove("jumpTime");
        });


        FallState = new ActorState(() =>
        { //Enter State
            GD.Print("Fall");

            SnapToGround = false;
            PlayerSprite.SetAnimation("Jump");

            JumpSpeedBuffer = Velocity.x;
        }, (float delta) =>
        { //Process State
        }, (float delta) =>
        { //State Physics Processing
            //Allow slight player movement
            float sideInput  = Input.GetActionStrength("p1_right") - Input.GetActionStrength("p1_left");
            Vector2 movement = new Vector2();
            movement.x       = sideInput * (AirAcceleration);
            ApplyForce2D(movement);

            if (IsOnFloor() == true)
            {
                ChangeState(StandState);
            }

            //Enforce air speed limit

            /* if(PreviousState == RunState) {
             *  if (Math.Abs(Velocity.x) > MaxRunSpeed) { Velocity.x = Interpolation.Lerp(Velocity.x, MaxRunSpeed * Mathf.Sign(Velocity.x), GetElapsedTimeInState()); }
             * } else {
             *  if (Math.Abs(Velocity.x) > MaxWalkSpeed) { Velocity.x = Interpolation.Lerp(Velocity.x, MaxWalkSpeed * Mathf.Sign(Velocity.x), GetElapsedTimeInState()); }
             * } */
            float speedLimit = Mathf.Min(Mathf.Abs(JumpSpeedBuffer), MaxRunSpeed);
            if (Mathf.Abs(Velocity.x) >= speedLimit)
            {
                Velocity.x = ClampedInterpolation.Lerp(Velocity.x, speedLimit * Mathf.Sign(Velocity.x), GetElapsedTimeInState());
            }
        }, () =>
        { //Exit State
        });
    }
Пример #2
0
    public override void AReady()
    {
        PlayerSprite      = GetNodeOrNull(new NodePath("PlayerSprite")) as AnimatedSprite3D;
        ActorDetectorArea = GetNodeOrNull(new NodePath("ActorDetector")) as Area;
        FloorRayCast      = GetNodeOrNull(new NodePath("FloorRayCast")) as RayCast;

        if (PlayerSprite == null || ActorDetectorArea == null || FloorRayCast == null)
        {
            GD.PrintErr("One or multiple required child nodes could not be found! Some features won't work!");
        }

        InputManager = new InputManager(PlayerNumber);

        StandState = new ActorState(() =>
        { //Enter State
            SnapToGround = true;
        }, (float delta) =>
        { //Process State
            if (Mathf.Abs(Velocity.x) > 0.5f)
            {
                PlayerSprite.SetAnimation(PlayerAnimation.WALK);
                PlayerSprite.Frames.SetAnimationSpeed(PlayerAnimation.WALK, (Mathf.Abs(Velocity.x)) + 5);
            }
            else
            {
                PlayerSprite.SetAnimation(PlayerAnimation.IDLE);
            }
        }, (float delta) =>
        { //State Physics Processing
            if (InputManager.DirectionalInput.x != 0)
            {
                ChangeState(WalkState);
            }
            CanFall();
            CanJump();
            CanCrouch();
        }, () =>
        { //Exit State
        });

        WalkState = new ActorState(() =>
        { //Enter State
            SetSpeedLimit(WalkSpeed);
            SnapToGround = true;
        }, (float delta) =>
        { //Process State
            if (Mathf.Sign(Velocity.x) == Mathf.Sign(InputManager.DirectionalInput.x) || Velocity.x == 0)
            {
                PlayerSprite.SetAnimation(PlayerAnimation.WALK);
                PlayerSprite.Frames.SetAnimationSpeed(PlayerAnimation.WALK, (Mathf.Abs(Velocity.x)) + 5);
            }
            else
            {
                PlayerSprite.SetAnimation(PlayerAnimation.TURN);
            }
        }, (float delta) =>
        { //State Physics Processing
            if (InputManager.DirectionalInput.x == 0)
            {
                ChangeState(StandState);
            }
            if (InputManager.RunPressed || InputManager.AltRunPressed)
            {
                ChangeState(RunState);
            }
            CanFall();
            CanJump();
            CanCrouch();

            float force = InputManager.DirectionalInput.x * WalkAcceleration;
            ApplyForce2D(new Vector2(force, 0));
        }, () =>
        { //Exit State
        });

        RunState = new ActorState(() =>
        { //Enter State
            SetSpeedLimit(RunSpeed);
            SnapToGround = true;
        }, (float delta) =>
        { //Process State
            if (Mathf.Sign(Velocity.x) == Mathf.Sign(InputManager.DirectionalInput.x) || Velocity.x == 0)
            {
                PlayerSprite.SetAnimation(PlayerAnimation.WALK);
                PlayerSprite.Frames.SetAnimationSpeed(PlayerAnimation.WALK, (Mathf.Abs(Velocity.x)) + 7);
            }
            else
            {
                PlayerSprite.SetAnimation(PlayerAnimation.TURN);
            }
        }, (float delta) =>
        { //State Physics Processing
            if (InputManager.DirectionalInput.x == 0)
            {
                ChangeState(StandState);
            }
            if (!InputManager.RunPressed && !InputManager.AltRunPressed)
            {
                ChangeState(WalkState);
            }
            if (GetElapsedTimeInState() > LongRunTime)
            {
                ChangeState(LongRunState);
            }
            CanFall();
            CanJump();
            CanCrouch();

            float force = InputManager.DirectionalInput.x * RunAcceleration;
            ApplyForce2D(new Vector2(force, 0));
        }, () =>
        { //Exit State
        });

        LongRunState = new ActorState(() =>
        { //Enter State
            PlayerSprite.SetAnimation(PlayerAnimation.LONG_RUN);
            SetSpeedLimit(LongRunSpeed);
            SnapToGround = true;
        }, (float delta) =>
        { //Process State
            if (Mathf.Sign(Velocity.x) == Mathf.Sign(InputManager.DirectionalInput.x) || Velocity.x == 0)
            {
                PlayerSprite.SetAnimation(PlayerAnimation.LONG_RUN);
                PlayerSprite.Frames.SetAnimationSpeed(PlayerAnimation.LONG_RUN, (Mathf.Abs(Velocity.x)) + 10);
            }
            else
            {
                PlayerSprite.SetAnimation(PlayerAnimation.TURN);
            }
        }, (float delta) =>
        { //State Physics Processing
            if (InputManager.DirectionalInput.x == 0)
            {
                ChangeState(StandState);
            }
            if (!InputManager.RunPressed && !InputManager.AltRunPressed || Mathf.Sign(Velocity.x) != Mathf.Sign(InputManager.DirectionalInput.x))
            {
                ChangeState(WalkState);
            }
            CanFall();
            CanJump();
            CanCrouch();

            float force = InputManager.DirectionalInput.x * LongRunAcceleration;
            ApplyForce2D(new Vector2(force, 0));
        }, () =>
        { //Exit State
        });

        JumpState = new ActorState(() =>
        { //Enter State
            SnapToGround = false;

            float speed = Mathf.Abs(Velocity.x);
            if (speed > RunSpeed)
            {
                ApplyForce2D(new Vector2(0, LongRunJumpForce));
                PlayerSprite.SetAnimation(PlayerAnimation.HIGH_JUMP);
            }
            else if (speed > 0.5f)
            {
                ApplyForce2D(new Vector2(0, WalkJumpForce));
                PlayerSprite.SetAnimation(PlayerAnimation.JUMP);
            }
            else if (PreviousState == CrouchState)
            {
                ApplyForce2D(new Vector2(0, IdleJumpForce));
                PlayerSprite.SetAnimation(PlayerAnimation.CROUCH);
                SetPlayerCollisionShape(PlayerCollisionShape.SMALL);
            }
            else
            {
                ApplyForce2D(new Vector2(0, IdleJumpForce));
                PlayerSprite.SetAnimation(PlayerAnimation.JUMP);
            }
        }, (float delta) =>
        { //Process State
          //DebugText.Display("P" + PlayerNumber + "_JumpSusTime", "P" + PlayerNumber + " Jump Sustain Time: " + (MaxJumpSustainTime - GetElapsedTimeInState()).ToString());
        }, (float delta) =>
        { //State Physics Processing
            if (IsOnFloor())
            {
                ChangeState(StandState);
            }
            if ((!InputManager.JumpPressed && !InputManager.AltJumpPressed) || GetElapsedTimeInState() > MaxJumpSustainTime)
            {
                ChangeState(FallState);
            }

            if (SpeedLimit >= LongRunSpeed && (InputManager.RunPressed || InputManager.AltRunPressed))
            {
                SetSpeedLimit(LongRunSpeed);
            }
            else if (InputManager.RunPressed || InputManager.AltRunPressed)
            {
                SetSpeedLimit(RunSpeed);
            }
            else
            {
                SetSpeedLimit(WalkSpeed);
            }

            //Add some force for extra air time if the jump button is held
            ApplyForce2D(Vector2.Up, Gravity.y * (1 - JumpSustainGravityMultiplier));

            float force = InputManager.DirectionalInput.x * AirHorizontalAcceleration;
            ApplyForce2D(new Vector2(force, 0));
        }, () =>
        { //Exit State
            //DebugText.Remove("P" + PlayerNumber + "_JumpSusTime");
            SetPlayerCollisionShape(GetDefaultCollisionShape());
        });

        SpinJumpState = new ActorState(() =>
        { //Enter State
            SnapToGround = false;
            PlayerSprite.SetAnimation(PlayerAnimation.SPIN_JUMP);

            float speed = Mathf.Abs(Velocity.x);
            if (speed > RunSpeed)
            {
                ApplyForce2D(new Vector2(0, LongRunJumpForce));
            }
            else if (speed > 0.5f)
            {
                ApplyForce2D(new Vector2(0, WalkJumpForce));
            }
            else if (PreviousState == CrouchState)
            {
                ApplyForce2D(new Vector2(0, IdleJumpForce));
            }
            else
            {
                ApplyForce2D(new Vector2(0, IdleJumpForce));
            }
        }, (float delta) =>
        { //Process State
          //DebugText.Display("P" + PlayerNumber + "_JumpSusTime", "P" + PlayerNumber + " Jump Sustain Time: " + (MaxJumpSustainTime - GetElapsedTimeInState()).ToString());
        }, (float delta) =>
        { //State Physics Processing
            if (IsOnFloor())
            {
                ChangeState(StandState);
            }
            if ((!InputManager.JumpPressed && !InputManager.AltJumpPressed) || GetElapsedTimeInState() > MaxJumpSustainTime)
            {
                ChangeState(FallState);
            }

            if (SpeedLimit >= LongRunSpeed && (InputManager.RunPressed || InputManager.AltRunPressed))
            {
                SetSpeedLimit(LongRunSpeed);
            }
            else if (InputManager.RunPressed || InputManager.AltRunPressed)
            {
                SetSpeedLimit(RunSpeed);
            }
            else
            {
                SetSpeedLimit(WalkSpeed);
            }

            //Add some force for extra air time if the jump button is held
            ApplyForce2D(Vector2.Up, Gravity.y * (1 - JumpSustainGravityMultiplier));

            float force = InputManager.DirectionalInput.x * AirHorizontalAcceleration;
            ApplyForce2D(new Vector2(force, 0));
        }, () =>
        { //Exit State
          //DebugText.Remove("P" + PlayerNumber + "_JumpSusTime");
        });

        FallState = new ActorState(() =>
        { //Enter State
            if (InputManager.DirectionalInput.y < CrouchInputThreshold)
            {
                PlayerSprite.SetAnimation(PlayerAnimation.CROUCH);
                SetPlayerCollisionShape(PlayerCollisionShape.SMALL);
            }
            else if (PreviousState == SpinJumpState)
            {
                PlayerSprite.SetAnimation(PlayerAnimation.SPIN_JUMP);
            }
            else
            {
                PlayerSprite.SetAnimation(PlayerAnimation.FALL);
            }
            SnapToGround = false;
        }, (float delta) =>
        { //Process State
        }, (float delta) =>
        { //State Physics Processing
            if (IsOnFloor())
            {
                if (InputManager.DirectionalInput.y < CrouchInputThreshold)
                {
                    ChangeState(CrouchState);
                }
                else
                {
                    ChangeState(StandState);
                }
            }

            if (SpeedLimit >= LongRunSpeed && (InputManager.RunPressed || InputManager.AltRunPressed))
            {
                SetSpeedLimit(LongRunSpeed);
            }
            else if (InputManager.RunPressed || InputManager.AltRunPressed)
            {
                SetSpeedLimit(RunSpeed);
            }
            else
            {
                SetSpeedLimit(WalkSpeed);
            }

            float force = InputManager.DirectionalInput.x * AirHorizontalAcceleration;
            ApplyForce2D(new Vector2(force, 0));
        }, () =>
        { //Exit State
            SetPlayerCollisionShape(GetDefaultCollisionShape());
        });

        CrouchState = new ActorState(() =>
        { //Enter State
            SnapToGround = true;

            var angle = Mathf.Rad2Deg(Mathf.Acos(FloorRayCast.GetCollisionNormal().Dot(FloorNormal)));
            if (angle >= SlideMinAngle)
            {
                ChangeState(SlideState);
                return;
            }

            PlayerSprite.SetAnimation(PlayerAnimation.CROUCH);
            SetPlayerCollisionShape(PlayerCollisionShape.SMALL);
        }, (float delta) =>
        { //Process State
        }, (float delta) =>
        { //State Physics Processing
            Transform slightlyRight;
            slightlyRight.origin    = Transform.origin;
            slightlyRight.basis     = Transform.basis;
            slightlyRight.origin.x += 0.4f;

            Transform slightlyLeft;
            slightlyLeft.origin    = Transform.origin;
            slightlyLeft.basis     = Transform.basis;
            slightlyLeft.origin.x -= 0.4f;

            if (!TestMove(Transform, new Vector3(0, 0.5f, 0)))
            {
                if (InputManager.DirectionalInput.y >= CrouchInputThreshold)
                {
                    ChangeState(StandState);
                }
                CanJump();
                CanFall();
            }
            else if (!TestMove(slightlyRight, new Vector3(0, 0.5f, 0)))
            {
                ApplyForce2D(new Vector2(0.4f, 0));
            }
            else if (!TestMove(slightlyLeft, new Vector3(0, 0.5f, 0)))
            {
                ApplyForce2D(new Vector2(-0.4f, 0));
            }
            else
            {
                if (InputManager.JumpJustPressed || InputManager.AltJumpJustPressed)
                {
                    ApplyForce2D(new Vector2(CrouchBoostForce.x * InputManager.DirectionalInput.x, CrouchBoostForce.y));
                }
            }
        }, () =>
        { //Exit State
            SetPlayerCollisionShape(GetDefaultCollisionShape());
        });

        SlideState = new ActorState(() =>
        { //Enter State
            SetSpeedLimit(SlideSpeed);
            SnapToGround = true;

            PlayerSprite.SetAnimation(PlayerAnimation.SLIDE);
            autoPlayerFacing = false;
        }, (float delta) =>
        { //Process State
            //Manually flip the sprite according to the movement direction
            if (Velocity.x > 0)
            {
                PlayerSprite.SetFlipH(false);
            }
            else if (Velocity.x < 0)
            {
                PlayerSprite.SetFlipH(true);
            }
        }, (float delta) =>
        { //State Physics Processing
            Vector3 normal = FloorRayCast.GetCollisionNormal();
            float angle    = Mathf.Rad2Deg(Mathf.Acos(normal.Dot(FloorNormal)));
            if (angle < SlideMinAngle)
            {
                ChangeState(InputManager.DirectionalInput.y < CrouchInputThreshold ? CrouchState : StandState);
            }
            CanFall();
            CanJump();

            float force = Mathf.Sign(normal.x) * SlideAcceleration;
            ApplyForce2D(new Vector2(force, 0));
        }, () =>
        { //Exit State
            autoPlayerFacing = true;
        });
    }