적과 플레이어 사이에 큐브를 하나 놓고 피격하면 좀비가 큐브에 걸려 움직이지 못합니다.
장애물 회피 방법은 좌선법, 우선법, 다익스트라, A*등이 있지만 유니티는 네비게이션메시를 준비해 놨습니다.
이부분은 교재방법이 업그레이드 되어서 새로운 방법을 찾아봤습니다.
빈오브젝트를 만들고 바닥과 장애물등 고정된 배경을 끌어다 자식으로 만듭니다. 이름은 Environment로 변경합니다.
Add Component > NavMesh Surface를 추가합니다.
이 상태에서 아래 Bake를 누르면 경로가 구워지지만 교재에서는 Agent의 속성을 바꿔주었는데
Windows의 AI>Navigation을 열어 바꿔주면 됩니다. 적의 직경 높이 경사를 오르는 능력등을 정합니다.
베이크하면 장애물을 제외한 곳은 파란색으로 표시됩니다. 새로운 배경이 추가되면 다시 베이크 해야합니다. 현재 씬파일이 있는곳에 NavMesh.asset이라는 파일이 저장됩니다.
이제 에너미에게 네브메시를 사용할수 있게 세팅해야 합니다.
에너미를 선택하고 NavMeshAgent를 추가합니다.
EnemyFSM.cs를 열어 NavMeshAgent 컴포넌트를 smith 변수에 연결해 줍니다.
using UnityEngine.AI;
public class EnemyFSM : MonoBehaviour
{
생략
NavMeshAgent smith;
void Start()
{ 생략
smith = GetComponent<NavMeshAgent>();
}
Move()함수에서 이동부분을 주석처리하고 네브에이전트에 목적지와 공격거리를 알켜주면 됩니다.
void Move()
{
// 만일 현재 위치가 초기 위치에서 이동 가능 범위를 넘어간다면...
if (Vector3.Distance(transform.position, originPos) > moveDistance)
{ //생략 }
// 만일, 플레이어와의 거리가 공격 범위 밖이라면 플레이어를 향해 이동한다.
else if (Vector3.Distance(transform.position, player.position) > attackDistance)
{
// 이동 방향 설정 Vector3 dir = (player.position - transform.position).normalized;
// 캐릭터 콘트롤러를 이용하여 이동하기 cc.Move(dir * moveSpeed * Time.deltaTime);
// 플레이어를 향하여 방향 전환한다. transform.forward = dir;
smith.stoppingDistance = attackDistance;
smith.destination = player.position;
}
이 상태로는 플레이어가 이동을 하면 적응못하거나 미끄러지듯 이동할수 있어 이동을 멈추고 패스를 리셋하겟습니다.
플레이어의 위치에 변경이 있을경우만 동작하게 하는게 더 효율적일것 같습니다.
smith.stoppingDistance = attackDistance;
if (smith.destination != player.position)
{
smith.isStopped = true;
smith.ResetPath();
smith.destination = player.position;
}
Return() 함수에서도 기존의 이동 부분을 주석 처리하고
void Return()
{
// 만일, 초기 위치에서의 거리가 0.1f 이상이라면 초기 위치 쪽으로 이동한다.
if (Vector3.Distance(transform.position, originPos) > 0.1f)
{
//Vector3 dir = (originPos - transform.position).normalized;
//cc.Move(dir * moveSpeed * Time.deltaTime);
//복귀 지점으로 방향을 전환한다. transform.forward = dir;
smith.destination = originPos;
smith.stoppingDistance = 0;
}
// 그렇지 않다면, 자신의 위치를 초기 위치로 조정하고 현재 상태를 대기 상태로 전환한다.
else
{
smith.isStopped = true;
smith.ResetPath();
생략
플레이 해보면 피격시도 미끄러져 옵니다.피격시 에이전트의 이동을 멈추고 경로를 초기화하는 코드를 추가합니다.
죽음상태는 피격상태에서 hp조건에 따라 전환되므로 여전히 피격상태이므로 따로 추가할 필요는 없습니다.
public void HitEnemy(int hitPower)
{
// 만일, 이미 피격 상태이거나 사망 상태 또는 복귀 상태라면 아무런 처리도 하지 않고 함수를 종료한다.
if (m_State == EnemyState.Damaged || m_State == EnemyState.Die || m_State == EnemyState.Return)
{
return;
}
// 플레이어의 공격력만큼 에너미의 체력을 감소시킨다.
hp -= hitPower;
// 에이전트를 멈추고 경로를 새로 탑색한다.
smith.isStopped = true;
smith.ResetPath();
에이전트의 이동속도나 회전속도등은 유니티 에디터에서 수정가능합니다.
적과 플레이어 사이의 큐브를 길게만들어 보겠습니다.
이상태에서 플레이 해보면 적이 피격시 장애물을 돌아 옵니다.
이제 오프메시링크 기능을 사용해 중앙의 장애물을 건너갈수 있도록 해보겠습니다.
장애물을 오르거나 내려갈곳이 필요합니다. 장애물 오브젝트의 자식으로 노란색 기즈모 아이콘이 설정된 빈오브젝트를 4개 추가합니다. 위치는 장애물 위와 근처 바닥으로 합니다. 노란 아이콘을 선택해 이름을 표시해주고요
Obstacle을 선택하고 NavMeshLink컴포넌트를 추가하고 Position에 알맞는 빈오브젝트를 끌어다 놓습니다. 교재에서는 Off Nave Mesh Component를 사용하라고 했는데 찾을수 없어다 비슷한 NavMeshLink를 사용하였습니다.
Area Type은 Jump로 변경합니다.
연결이 끝나면 다음과 같이 보일 것 입니다.
Enemy NavMeshAgent에서 아래쪽 PathFinding>AutoTraverseOffMesh를 켜줍니다. 그럼 NavMeshLink가 쌍방향이 됩니다.
Navigation창에서 DropHeight를 장애물보다 높게 합니다.
모든 장애물들의 부모인 Environmen를 선택하고
NavMeshSurface의 Generate Links도 체크하고 아래 베이크 하면
다음과 같이 구워집니다.
Navigation창의 Areas를 보면 행동의 가중치가 있는데 적은쪽을 우선으로 움직입니다 Jump가 2로 크지만 전체적인 경로 가중치를 계산해 Jump를 사용할 경우도 있는것 같습니다.
'인생유니티 > FPS게임' 카테고리의 다른 글
옵션UI제작 (0) | 2025.04.25 |
---|---|
무기 모드 추가및 효과 적용 (0) | 2025.04.24 |
플레이어 애니메이션 (0) | 2025.04.23 |
플레이어 모델링 교체 (0) | 2025.04.23 |
Enemy Animation (0) | 2025.04.22 |