using System.Collections.Generic; using UnityEngine; public enum State { IDLE, MOVE, JUMP, Attack, Damaged, Dead } public class StateMachine { private IState _state; private State _currentState; private PlayerMove _player; // PlayerMove 인스턴스를 저장 private Dictionary _states = new Dictionary(); public StateMachine(State state, PlayerMove player) { _player = player; // PlayerMove 인스턴스 저장 _states.Add(State.IDLE, new IdleState(player)); _states.Add(State.MOVE, new MoveState(player)); _states.Add(State.JUMP, new JumpState(player)); _states.Add(State.Attack, new AttackState(player)); _states.Add(State.Dead, new DeadState(player)); _currentState = state; _state = _states[state]; _state.Enter(); } public void Update() { _state.Update(); State newState = _state.CheckTransition(); if (_currentState != newState) { _state.Exit(); SetTransition(newState); } } // 오버로드된 SetTransition 메서드 추가 public void SetTransition(State state, Vector2 targetPosition) { _currentState = state; _state = new DamagedState(_player, targetPosition); // _player 변수 사용 _state.Enter(); } public void SetTransition(State state) { _currentState = state; _state = _states[state]; _state.Enter(); } } public interface IState { void Enter(); void Update(); void Exit(); State CheckTransition(); } public class IdleState : IState { private PlayerMove _player; public IdleState(PlayerMove player) { _player = player; } public void Enter() { _player.Animator.SetBool("isMoving", false); _player.Animator.SetBool("isJumping", false); } public void Update() { } public void Exit() { } public State CheckTransition() { if (Input.GetButtonDown("Jump")) { return State.JUMP; } if (Mathf.Abs(Input.GetAxisRaw("Horizontal")) > 0) { return State.MOVE; } return State.IDLE; } } public class MoveState : IState { private PlayerMove _player; public MoveState(PlayerMove player) { _player = player; } public void Enter() { _player.Animator.SetBool("isMoving", true); } public void Update() { float horizontalInput = Input.GetAxisRaw("Horizontal"); if (horizontalInput != 0) { // transform.localScale.x를 사용하여 캐릭터와 자식 오브젝트를 함께 뒤집습니다. // 기본 스프라이트가 왼쪽을 바라보고 있으므로, 오른쪽 이동 시 x 스케일을 뒤집어야 합니다. Vector3 newScale = _player.transform.localScale; newScale.x = horizontalInput > 0 ? -1f : 1f; _player.transform.localScale = newScale; } _player.RigidBody.AddForce(Vector2.right * horizontalInput * _player.maxSpeed, ForceMode2D.Force); if (Mathf.Abs(_player.RigidBody.linearVelocity.x) > _player.maxSpeed) { _player.RigidBody.linearVelocity = new Vector2(Mathf.Sign(_player.RigidBody.linearVelocity.x) * _player.maxSpeed, _player.RigidBody.linearVelocity.y); } } public void Exit() { _player.Animator.SetBool("isMoving", false); } public State CheckTransition() { if (Input.GetButtonDown("Jump")) { return State.JUMP; } if (Mathf.Abs(Input.GetAxisRaw("Horizontal")) < 0.1f) { return State.IDLE; } return State.MOVE; } } public class JumpState : IState { private PlayerMove _player; public JumpState(PlayerMove player) { _player = player; } public void Enter() { _player.RigidBody.AddForce(Vector2.up * _player.jumpPower, ForceMode2D.Impulse); _player.Animator.SetBool("isJumping", true); } public void Update() { if (Input.GetButton("Horizontal")) { Vector3 newScale = _player.transform.localScale; newScale.x = Input.GetAxisRaw("Horizontal") > 0 ? -1f : 1f; _player.transform.localScale = newScale; } } public void Exit() { _player.Animator.SetBool("isJumping", false); } public State CheckTransition() { if (_player.RigidBody.linearVelocity.y < 0) { Debug.DrawRay(_player.RigidBody.position, Vector3.down, Color.green); RaycastHit2D rayHit = Physics2D.Raycast(_player.RigidBody.position, Vector3.down, 1, LayerMask.GetMask("Platform")); if (rayHit.collider != null && rayHit.distance < 0.7f) { return State.IDLE; } } return State.JUMP; } } public class AttackState : IState { private PlayerMove _player; public AttackState(PlayerMove player) { _player = player; } public void Enter() { _player.Animator.SetTrigger("Attack"); } public void Update() { } public void Exit() { } public State CheckTransition() { AnimatorStateInfo stateInfo = _player.Animator.GetCurrentAnimatorStateInfo(0); if (stateInfo.normalizedTime >= 1.0f && !stateInfo.IsTag("Attack")) { return State.IDLE; } return State.Attack; } } public class DamagedState : IState { private PlayerMove _player; private float _invincibilityTime = 1f; private float _damagedStartTime; private Vector2 _targetPosition; public DamagedState(PlayerMove player, Vector2 targetPosition) { _player = player; _targetPosition = targetPosition; } public void Enter() { _player.hp--; Debug.Log("플레이어가 맞았습니다. 현재 HP: " + _player.hp); _player.gameObject.layer = LayerMask.NameToLayer("PlayerDamaged"); _player.SpriteRenderer.color = new Color(1, 1, 1, 0.5f); _damagedStartTime = Time.time; int direction = (_player.transform.position.x - _targetPosition.x) > 0 ? 1 : -1; _player.RigidBody.AddForce(new Vector2(direction * 5f, 0f), ForceMode2D.Impulse); } public void Update() { } public void Exit() { _player.gameObject.layer = LayerMask.NameToLayer("Player"); _player.SpriteRenderer.color = new Color(1, 1, 1, 1); } public State CheckTransition() { if (_player.hp <= 0) { return State.Dead; } if (Time.time >= _damagedStartTime + _invincibilityTime) { return State.IDLE; } return State.Damaged; } } public class DeadState : IState { private PlayerMove _player; public DeadState(PlayerMove player) { _player = player; } public void Enter() { Debug.Log("플레이어 사망"); _player.Die(); } public void Update() { // 사망 상태에서는 어떤 로직도 수행하지 않습니다. } public void Exit() { } public State CheckTransition() { // 사망 상태에서는 전환이 없습니다. return State.Dead; } }