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 }); }
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; }); }