적의 두뇌
Coddy Unity 여정의 Unity 게임 아키텍처 섹션에 포함된 레슨. 50개 중 31번째.
적의 두뇌는 동작마다 하나의 상태가 있는 상태 머신입니다. 이 기본 구조는 해골이 순찰 지점 사이를 오가고, 6 단위 이내로 다가온 플레이어를 추격하며, 가까이 있을 때 초당 한 번 검을 휘두르게 합니다. 각 상태는 자체적으로 다음 상태로 전환되는 조건을 결정하며, 해골은 상태들이 공유하는 도우미를 유지합니다:
public class Skeleton : MonoBehaviour
{
public Transform player;
public Transform[] posts;
public float speed = 2f;
public StateMachine machine = new StateMachine();
public IState patrol, chase, attack;
void Start()
{
patrol = new PatrolState(this);
chase = new ChaseState(this);
attack = new AttackState(this);
machine.ChangeState(patrol);
}
void Update() { machine.Tick(); }
public float PlayerDistance() { return Vector3.Distance(transform.position, player.position); }
public void WalkTo(Vector3 target)
{
target.y = transform.position.y;
transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
}
}
public class PatrolState : IState
{
private Skeleton skel;
private int next;
public PatrolState(Skeleton skel) { this.skel = skel; }
public void Enter() { }
public void Exit() { }
public void Tick()
{
if (skel.PlayerDistance() < 6f) { skel.machine.ChangeState(skel.chase); return; }
Vector3 post = skel.posts[next].position;
post.y = skel.transform.position.y;
skel.WalkTo(post);
if (skel.transform.position == post) next = (next + 1) % skel.posts.Length;
}
}
public class ChaseState : IState
{
private Skeleton skel;
public ChaseState(Skeleton skel) { this.skel = skel; }
public void Enter() { }
public void Exit() { }
public void Tick()
{
float d = skel.PlayerDistance();
if (d > 6f) { skel.machine.ChangeState(skel.patrol); return; }
if (d < 1.5f) { skel.machine.ChangeState(skel.attack); return; }
skel.WalkTo(skel.player.position);
}
}
public class AttackState : IState
{
private Skeleton skel;
private float cooldown;
public AttackState(Skeleton skel) { this.skel = skel; }
public void Enter() { cooldown = 0f; }
public void Exit() { }
public void Tick()
{
if (skel.PlayerDistance() > 1.5f) { skel.machine.ChangeState(skel.chase); return; }
cooldown -= Time.deltaTime;
if (cooldown <= 0f) { Debug.Log("Swing!"); cooldown = 1f; }
}
}상태는 한 번 생성되어 해골이 살아 있는 동안 유지되므로, 각 상태의 필드 값은 상태를 다시 방문해도 보존됩니다. PatrolState의 next는 추격 후에도 설정된 값으로 남아 있으므로, 해골은 원래 향하고 있던 순찰 지점으로 계속 이동합니다. Enter는 다시 초기화해야 하는 값만 재설정합니다. AttackState의 Enter는 cooldown을 0으로 설정하므로, 해골이 플레이어에게 도달하면 곧바로 첫 번째 공격을 합니다.
모든 이동은 WalkTo를 거칩니다. 여기서는 transform에 MoveTowards를 사용하며, 이 방법은 벽을 통과해 이동합니다. 대신 Rigidbody를 사용해 해골을 움직이려면 WalkTo에서 본체의 속도를 설정하고, 해골은 FixedUpdate에서 머신을 틱해야 합니다. 이때 Time.deltaTime은 물리 업데이트 간격입니다. 세 상태는 바뀌지 않습니다. 상태는 어디로 갈지 정하고, 소유 객체는 어떻게 이동할지 정합니다.
챌린지
중급기사가 성의 안뜰을 지킵니다. 화살표 키로 플레이어를 움직이며, 플레이어의 Health에는 TakeDamage(int amount)가 있습니다(둘 다 준비되어 있음). Knight.cs에는 Inspector에서 값을 설정할 필드(waypoints W0부터 W2까지, player, playerHealth, speed 3 및 아래의 범위)가 있으며, Rigidbody를 사용하는 도우미 함수도 있습니다. DistanceTo(point)와 PlayerDistance()는 지면을 따라 거리를 측정하고, WalkTo(target)는 한 지점을 향해 이동하며, Stop()은 제자리에 멈춥니다. 이제 여기에 두뇌를 달아 주세요:
Knight.cs에서 머신과 세 상태(필드patrol,chase,attack)를 만들고, 순찰을 시작한 다음 FixedUpdate에서 머신을 틱하세요.KnightStates.cs에서 각각 생성자에 기사를 받는PatrolState,ChaseState,AttackState를 작성하세요.- 순찰:
waypoints[next]로 이동하세요. 해당 지점까지의 거리가 0.3 이내면 다음 지점으로 향하고, 마지막 지점 다음에는 첫 지점으로 돌아가세요. 플레이어가sightRange(5)보다 가까우면 추격합니다. 추격이 끝나면 순찰은 향하고 있던 웨이포인트로 계속 이동합니다. - 추격: 플레이어에게 이동하세요.
attackRange(1.5)보다 가까우면 공격하고,loseRange(8)보다 멀면 순찰하세요. 5에서 8 사이에서는 추격을 계속하므로, 시야 범위의 경계에서 기사가 두 상태를 오가지 않습니다. - 공격: 제자리에 멈춰 플레이어가
attackRange이내에 있는 동안 즉시 1의 피해를 주고, 이후 매초마다 다시 공격하세요. 플레이어가 더 멀어지면 다시 추격합니다.
Play를 누르고, 기사가 당신을 발견하게 한 뒤 공격을 한 번 받고, 도망친 다음 Check를 누르세요.
직접 해보기
using UnityEngine;
// PatrolState, ChaseState 및 AttackState
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.