Files
Knight_Hollow/Assets/Scripts/Player/StateMachine.cs

317 lines
7.4 KiB
C#

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<State, IState> _states = new Dictionary<State, IState>();
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;
}
}