Enemy의 상태 패턴 구현:
State Pattern을 활용하여 적이 항상 플레이어를 추적하는 동작을 구현.
IdleState를 생략하고, 게임 시작 시 바로 ChaseState로 전환되도록 설정.
적이 플레이어를 계속해서 추적하도록 상태를 관리하여, 플레이어와 적의 상호작용을 더욱 직관적으로 구현.
ChaseState: 적이 플레이어를 향해 움직이는 상태로, Execute() 메서드에서 매 프레임마다 플레이어의 위치를 계산하여 적이 플레이어를 따라가는 로직을 구현.
상태 전환: Awake() 메서드에서 바로 ChaseState로 전환하도록 구현하여, 적이 플레이어를 감지하는 범위 없이 항상 추적하는 동작을 구현함.
Enemy
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
[SerializeField]
private float speed; // 적의 속도
public Rigidbody2D target; // 추적할 플레이어 또는 목표
private Rigidbody2D rigid; // 적의 Rigidbody2D
private SpriteRenderer sprite; // 스프라이트 제어
private StateMachine stateMachine; // 상태 머신
private Animator animator;
private bool isLive = true; // 적이 살아 있는지 여부
private void Awake()
{
rigid = GetComponent<Rigidbody2D>();
sprite = GetComponent<SpriteRenderer>();
animator = GetComponent<Animator>();
// 상태 머신 초기화
stateMachine = new StateMachine();
// 게임이 시작되면 바로 플레이어를 추적하는 ChaseState로 전환
stateMachine.SetState(new ChaseState(stateMachine, animator, speed, rigid));
}
private void Update()
{
// 상태 머신 업데이트
if (isLive)
{
Vector2 dirVec = target.position - rigid.position;
stateMachine.Update(dirVec); // 플레이어 방향을 상태에 전달
}
}
private void LateUpdate()
{
// 적의 스프라이트 방향 처리
sprite.flipX = target.position.x > rigid.position.x;
}
public void ChasePlayer()
{
if (isLive)
{
// ChaseState로 전환하여 플레이어 추적 시작
stateMachine.SetState(new ChaseState(stateMachine, animator, speed, rigid));
}
}
public void OnHit()
{
// 적이 피격되었을 때 피격 상태로 전환
//stateMachine.SetState(new HitState(stateMachine, stateMachine.CurrentState, animator));
}
}
ChaseState
using Unity.VisualScripting;
using UnityEngine;
public class ChaseState : Istate
{
private StateMachine stateMachine;
private Animator animator;
private float speed;
private Rigidbody2D rigid;
public ChaseState(StateMachine machine, Animator animator, float speed, Rigidbody2D rigid)
{
stateMachine = machine;
this.animator = animator;
this.speed = speed;
this.rigid = rigid;
}
public void Enter()
{
Debug.Log("Enter Chase State");
animator.Play("Run"); // 추적 애니메이션
}
public void Execute(Vector2 direction)
{
// 플레이어를 추적하는 로직
Vector2 nextVec = direction.normalized * speed * Time.fixedDeltaTime;
rigid.MovePosition(rigid.position + nextVec);
rigid.velocity = Vector2.zero;
}
public void Exit()
{
Debug.Log("Exit Chase State");
}
}
Reposition
using UnityEngine;
public class Reposition : MonoBehaviour
{
Collider2D coll;
private void Awake()
{
coll = GetComponent<Collider2D>();
}
private void OnTriggerExit2D(Collider2D collision)
{
if (!collision.CompareTag("Area"))
return;
Vector3 playerPos = GameManager.Instance.player.transform.position;
Vector3 myPos = transform.position;
float diffX = Mathf.Abs(playerPos.x - myPos.x);
float diffY = Mathf.Abs(playerPos.y - myPos.y);
Vector3 playerDir = GameManager.Instance.player.playerVector;
float dirX = playerDir.x < 0 ? -1 : 1;
float dirY = playerDir.y < 0 ? -1 : 1;
switch (transform.tag)
{
case "Ground":
if (diffX > diffY)
{
transform.Translate(Vector3.right * dirX * 40);
}
else if (diffX < diffY)
{
transform.Translate(Vector3.up * dirY * 40);
}
break;
case "Enemy":
if (coll.enabled)
{
transform.Translate(playerDir * 20 +
new Vector3(Random.Range(-3f, 3f), Random.Range(-3f, 3f), 0f));
}
break;
}
}
}
IdleState 필요 여부: 처음에는 적이 대기하는 IdleState에서 플레이어를 감지하는 로직을 고려했으나, 게임의 특성상 몬스터가 생성이되면 바로바로 플레이어를 쫓아가게 하기위해 필요가 없다고 판단하여 이를 통해 불필요한 상태를 제거하고 상태 패턴의 간결함을 유지.
