From cf41a64529082602658e25efb7fba4d3daed5c6d Mon Sep 17 00:00:00 2001 From: Mingu Kim Date: Fri, 22 Aug 2025 20:33:29 +0900 Subject: [PATCH] =?UTF-8?q?Player=20=3D=20DamagedState,=20DeadState=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/InputSystem_Actions.inputactions | 2 +- Assets/Scenes/SampleScene.unity | 4 +- Assets/Scripts/Player/PlayerMove.cs | 47 ++------ Assets/Scripts/Player/StateMachine.cs | 152 ++++++++++++++++++------ ProjectSettings/TagManager.asset | 2 +- 5 files changed, 125 insertions(+), 82 deletions(-) diff --git a/Assets/InputSystem_Actions.inputactions b/Assets/InputSystem_Actions.inputactions index 1a12cb91..8865bc65 100644 --- a/Assets/InputSystem_Actions.inputactions +++ b/Assets/InputSystem_Actions.inputactions @@ -27,7 +27,7 @@ "name": "Attack", "type": "Button", "id": "6c2ab1b8-8984-453a-af3d-a3c78ae1679a", - "expectedControlType": "Button", + "expectedControlType": "", "processors": "", "interactions": "", "initialStateCheck": false diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity index 49a8bcd6..eadea03b 100644 --- a/Assets/Scenes/SampleScene.unity +++ b/Assets/Scenes/SampleScene.unity @@ -5989,9 +5989,9 @@ GameObject: - component: {fileID: 2119498365} - component: {fileID: 2119498366} - component: {fileID: 2119498367} - m_Layer: 0 + m_Layer: 10 m_Name: The Knight main sprites - atlas0 #00000357_482 - m_TagString: Untagged + m_TagString: Player m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 diff --git a/Assets/Scripts/Player/PlayerMove.cs b/Assets/Scripts/Player/PlayerMove.cs index e14bef24..27891885 100644 --- a/Assets/Scripts/Player/PlayerMove.cs +++ b/Assets/Scripts/Player/PlayerMove.cs @@ -1,6 +1,5 @@ using System; using UnityEngine; - public class PlayerMove : MonoBehaviour { // 컴포넌트 프로퍼티 @@ -50,53 +49,21 @@ public class PlayerMove : MonoBehaviour void FixedUpdate() { - float h = Input.GetAxisRaw("Horizontal"); - RigidBody.AddForce(Vector2.right * h, ForceMode2D.Impulse); - - if (RigidBody.linearVelocity.x > maxSpeed) - { - RigidBody.linearVelocity = new Vector2(maxSpeed, RigidBody.linearVelocity.y); - } - else if (RigidBody.linearVelocity.x < -maxSpeed) - { - RigidBody.linearVelocity = new Vector2(-maxSpeed, RigidBody.linearVelocity.y); - } + // FixedUpdate 로직은 이제 사용하지 않습니다. } void OnCollisionEnter2D(Collision2D collision) { if (collision.gameObject.CompareTag("Enemy")) { - // FSM에 피격 로직 추가 - // _stateMachine.SetTransition(new DamagedState(this, collision.transform.position)); + // 중복 호출 제거, 피격 위치를 전달하는 메서드만 사용 + _stateMachine.SetTransition(State.Damaged, collision.transform.position); } } - - void OnDamaged(Vector2 targetPosition) - { - // OnDamaged 로직은 DamagedState의 Enter()로 이동 - // 기존 Invoke("OffDamaged", 1)는 DamagedState 내부에서 처리 - } - - void OffDamaged() - { - // OffDamaged 로직은 DamagedState의 Exit()로 이동 - } - // 공격 애니메이션 이벤트에서 호출될 함수 - public void StartAttackHitbox() + // 플레이어 오브젝트를 파괴하는 메서드 + public void Die() { - if (attackCollider != null) - { - attackCollider.enabled = true; - } + Destroy(gameObject); } - - public void EndAttackHitbox() - { - if (attackCollider != null) - { - attackCollider.enabled = false; - } - } -} +} \ No newline at end of file diff --git a/Assets/Scripts/Player/StateMachine.cs b/Assets/Scripts/Player/StateMachine.cs index adf30009..427802e7 100644 --- a/Assets/Scripts/Player/StateMachine.cs +++ b/Assets/Scripts/Player/StateMachine.cs @@ -3,23 +3,26 @@ using UnityEngine; public enum State { - IDLE, MOVE, JUMP, Attack + IDLE, MOVE, JUMP, Attack, Damaged, Dead } public class StateMachine { private IState _state; private State _currentState; - - //장점 : key 값을 바로 불러와서 value를 리턴할 수 있게 된다. (자료구조가 많은 데이터를 담았을 때 리턴하는 경우 속도의 효율) - //단점 : 자료구조의 데이터가 적을 때, 100개 혹은 10 이하의 데이터에서 Dictionary를 사용할 경우 속도가 오히려 느릴 수 있다. + 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]; @@ -29,9 +32,8 @@ public class StateMachine public void Update() { _state.Update(); - var newState = _state.CheckTransition(); + State newState = _state.CheckTransition(); - // 상태가 변경되었는지 확인 (참조가 다르면) if (_currentState != newState) { _state.Exit(); @@ -39,9 +41,16 @@ public class StateMachine } } + // 오버로드된 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(); @@ -51,18 +60,14 @@ public class StateMachine public interface IState { void Enter(); - void Update(); - void Exit(); - - // 트리거 조건일 경우 다음 상태로 전환 State CheckTransition(); } public class IdleState : IState { - private PlayerMove _player; // PlayerMove 객체에 대한 참조 + private PlayerMove _player; public IdleState(PlayerMove player) { @@ -71,17 +76,16 @@ public class IdleState : IState public void Enter() { - // _player.Animator.SetBool(PlayerMove.IsMoving, false); + _player.Animator.SetBool("isMoving", false); + _player.Animator.SetBool("isJumping", false); } public void Update() { - // 상태별 로직은 여기서는 필요 없음 } public void Exit() { - // Idle 상태에서 벗어날 때의 로직 } public State CheckTransition() @@ -100,8 +104,6 @@ public class IdleState : IState public class MoveState : IState { - private static int _isMoving = Animator.StringToHash("isMoving"); - private PlayerMove _player; public MoveState(PlayerMove player) @@ -111,7 +113,7 @@ public class MoveState : IState public void Enter() { - _player.Animator.SetBool(_isMoving, true); + _player.Animator.SetBool("isMoving", true); } public void Update() @@ -119,15 +121,20 @@ public class MoveState : IState float horizontalInput = Input.GetAxisRaw("Horizontal"); if (horizontalInput != 0) { - // 입력 방향에 따라 스프라이트를 뒤집음. _player.SpriteRenderer.flipX = horizontalInput > 0; } + + _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); + _player.Animator.SetBool("isMoving", false); } public State CheckTransition() @@ -138,7 +145,7 @@ public class MoveState : IState } if (Mathf.Abs(Input.GetAxisRaw("Horizontal")) < 0.1f) { - return State.IDLE; // Create new IdleState object + return State.IDLE; } return State.MOVE; } @@ -146,8 +153,6 @@ public class MoveState : IState public class JumpState : IState { - private static int _isJumping = Animator.StringToHash("isJumping"); - private PlayerMove _player; public JumpState(PlayerMove player) @@ -158,12 +163,11 @@ public class JumpState : IState public void Enter() { _player.RigidBody.AddForce(Vector2.up * _player.jumpPower, ForceMode2D.Impulse); - _player.Animator.SetBool(_isJumping, true); + _player.Animator.SetBool("isJumping", true); } public void Update() { - // 점프 중 스프라이트 방향 변경 if (Input.GetButton("Horizontal")) { _player.SpriteRenderer.flipX = Input.GetAxisRaw("Horizontal") > 0; @@ -172,13 +176,14 @@ public class JumpState : IState public void Exit() { - _player.Animator.SetBool(_isJumping, false); + _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) @@ -201,30 +206,19 @@ public class AttackState : IState public void Enter() { - // 공격 애니메이션 시작 _player.Animator.SetTrigger("Attack"); } public void Update() - { - // 공격 상태 로직 (예: 애니메이션 재생 중 다른 입력 무시) - } - - public void FixedUpdate() { } public void Exit() { - // 공격 상태 종료 } public State CheckTransition() { - // 공격 애니메이션이 끝나면 Idle 상태로 전환 - // Animator의 현재 상태를 확인하여 transition을 처리합니다. - // 예를 들어, GetCurrentAnimatorStateInfo(0).IsName("Attack")이 false가 되면 전환 - // 또는 애니메이션 이벤트로 상태 전환을 직접 호출할 수도 있습니다. AnimatorStateInfo stateInfo = _player.Animator.GetCurrentAnimatorStateInfo(0); if (stateInfo.normalizedTime >= 1.0f && !stateInfo.IsTag("Attack")) { @@ -232,4 +226,86 @@ public class AttackState : IState } 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; + } } \ No newline at end of file diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index 4cba3210..8d08a1f8 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -18,7 +18,7 @@ TagManager: - Platform - Enemy - Player - - PlayerDameged + - PlayerDamaged - - -