#nullable enable using JetBrains.Annotations; using UnityEngine; using UnityEngine.InputSystem; [RequireComponent(typeof(PlayerInput), typeof(Rigidbody2D))] public class PlayerMovement : MonoBehaviour { [SerializeField] PlayerStats playerStats; Rigidbody2D rb; PlayerInput playerInput; Vector2 moveDirection; BaseState currentState = new NormalMovementState(); void Awake() { rb = GetComponent(); playerInput = GetComponent(); } void FixedUpdate() { if (currentState.FixedUpdateState(this) is {} newState) SwitchState(newState); } public void OnMove(InputAction.CallbackContext ctx) { moveDirection = ctx.ReadValue(); if (moveDirection.sqrMagnitude > 1.0f) moveDirection.Normalize(); } public void OnJump(InputAction.CallbackContext ctx) { if (!ctx.ReadValueAsButton()) return; SwitchState(new JumpingMovementState()); } void SwitchState(BaseState newState) { currentState.LeaveState(this); currentState = newState; newState.EnterState(this); } class BaseState { //TODO If we never do anything before enter, replace with constructor? public virtual void EnterState(PlayerMovement playerMovement) {} public virtual void LeaveState(PlayerMovement playerMovement) {} [CanBeNull] public virtual BaseState UpdateState(PlayerMovement playerMovement) => null; [CanBeNull] public virtual BaseState FixedUpdateState(PlayerMovement playerMovement) => null; } class NormalMovementState : BaseState { public override BaseState FixedUpdateState(PlayerMovement playerMovement) { playerMovement.rb.velocity = (Vector3)playerMovement.moveDirection * playerMovement.playerStats.movementSpeed; return null; } } class JumpingMovementState : BaseState { Vector3 startPosition; float startTime; public override void EnterState(PlayerMovement playerMovement) { startPosition = playerMovement.transform.position; startTime = Time.time; } public override BaseState FixedUpdateState(PlayerMovement playerMovement) { float currentTime = Time.time - startTime; if (currentTime >= playerMovement.playerStats.safeZoneJumpDuration) return new NormalMovementState(); playerMovement.rb.MovePosition(Vector3.Lerp( startPosition, playerMovement.playerStats.safeZonePosition, currentTime / playerMovement.playerStats.safeZoneJumpDuration )); return null; } } }