317 lines
7.4 KiB
C#
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;
|
|
}
|
|
} |