가장 먼저 네비게이션 기능(NavMesh)을 활성화 할 맵 오브젝트를 선택합니다.
인스펙터 창의 우측 상단에 Static 설정에서 Navigation Static을 체크합니다.
Navigation에서 Bake를 합니다. (Window 메뉴 → AI → Navigation)
Bake가 다되면 파란색 영역이 생성됩니다. 이 영역은 캐릭터가 길을 찾아서 이동할 수 있는 NavMesh입니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Enemy : MonoBehaviour
{
NavMeshAgent nav;
public GameObject player;
void Start()
{
nav = GetComponent<NavMeshAgent>();
}
void Update()
{
nav.SetDestination(player.transform.position);
transform.LookAt(player.transform.position);
}
}
Enemy가 Player를 쫓아오지만 Player가 멈추게 되어도 부딪혀 밀어 버리는 현상이 생깁니다. 그러기 위해서 코드를 수정할 필요가 있습니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Enemy : MonoBehaviour
{
NavMeshAgent nav;
public GameObject player;
float dist;
void Start()
{
nav = GetComponent<NavMeshAgent>();
}
void Update()
{
nav.SetDestination(player.transform.position);
transform.LookAt(player.transform.position);
dist = Vector3.Distance(player.transform.position, transform.position);
UpdateStop();
}
void UpdateStop()
{
if (dist < 10f) nav.isStopped = true;
if (dist > 10f) nav.isStopped = false;
}
}
dist 변수를 추가했습니다. dist는 Vector3.Distance 함수를 이용해 Player와 Enemy 사이의 거리를 계산한 값을 실시간으로 저장합니다.
Distance와 magnitude는 정확한 거리 계산을 하기 때문에 거리를 알고 싶을 때 사용합니다.
sqrMagnitude는 거리의 제곱 값을 리턴하는데 특정 거리보다 작거나 큰지 비교만 하고 싶을때 사용합니다.
스크립트에서 오브젝트의 거리가 10f보다 가까워지면 멈추고, 10f보다 멀어지면 쫓아오게 됩니다.
10f가 어느정도 길이인지 어림짐작 할 수는 있지만 정확하게 알 수는 없습니다. 만약 10f가 아니라 훨씬 크거나 작은 세밀한 값일 경우에는 훨씬 더 어렵습니다.
그렇기 때문에 개발자는 Scene 뷰에서 거리를 확인할 수 있게 기즈모를 추가해주는 것이 좋을 것 같습니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Enemy : MonoBehaviour
{
NavMeshAgent nav;
public GameObject player;
float dist;
Ray ray;
void Start()
{
nav = GetComponent<NavMeshAgent>();
}
void Update()
{
nav.SetDestination(player.transform.position);
transform.LookAt(player.transform.position);
dist = Vector3.Distance(player.transform.position, transform.position);
UpdateStop();
}
void UpdateStop()
{
if (dist < 10f) nav.isStopped = true;
if (dist > 10f) nav.isStopped = false;
}
private void OnDrawGizmos()
{
ray.origin = transform.position;
ray.direction = transform.forward;
Debug.DrawRay(ray.origin, ray.direction * 10f, Color.red);
}
}
OnDrawGizmos 함수에 사용하는 Gizmo는 매 프레임마다 호출되어 항상 노출됩니다.
RaycastHit는 Ray에 의한 충돌 체크입니다. 만약 충돌 체크가 아니라 단순히 Ray만 쏘고 싶다면 메소드 상단에서 ray 변수를 생성한 뒤 OnDrawGizmos 함수에서는 발사지점, 발사방향, 색상만 지정해주는 것으로 쉽게 만들 수 있습니다.
Gizmos 클래스를 이용한다면 직선 Ray 외에도 다양한 레퍼토리가 가능합니다.
Function | Explain |
---|---|
color | 색상을 변경합니다. |
DrawCube | 큐브를 생성합니다. |
DrawGUITexture | |
DrawIcon | |
DrawLine | |
DrawMesh | |
DrawRay | |
DrawSphere | |
DrawWireCube | |
DrawWireMesh | |
DrawWireSphere |
private void OnDrawGizmos()
{
ray.origin = transform.position;
Gizmos.color = Color.red; //color를 지정하지 않을 시 기본색상(흰색)
Gizmos.DrawWireSphere(ray.origin, 10f);
}
각 함수의 파라미터에는 발사지점과 길이만 추가하면 됩니다.
아래는 DrawWireSphere 함수를 사용한 기즈모입니다.
프로퍼티 | 설명 |
---|---|
Base Offset | NavMeshAgent Y축 방향 위치 |
Speed | 최대 이동 속도 |
Augular Speed | 최대 회전 속도 |
Acceleration | 최대 가속 |
Stopping Distance | 목표 위치로부터 설정한 거리만큼 떨어져 정지하는 기능입니다. |
Auto Braking | 활성화 시 에이전트는 목적지에 다다를 때 속도를 줄입니다. 멀티플 포인트 사이에서 부드럽게 움직여야 하는 순찰과 같은 동작을 할 때에는 반드시 비활성화 시켜야 합니다. |
Radius | Agent의 장애물과 에이전트 간의 충돌을 계산하는 반경입니다. |
Height | Agent가 장애물 밑으로 지나갈 수 있는 높이 간격입니다. |
Quality | 장애물 회피 품질입니다. 에이전트의 수가 많다면 장애물 회피 품질을 줄임으로써 CPU 시간을 절약할 수 있습니다. 회피를 없음으로 설정할 경우 충돌만 해결할 수 있을 뿐 다른 에이전트와 장애물에 대한 적극적인 회피는 하지 않습니다. |
Priority | 낮은 우선 순위의 에이전트는 이 에이전트의 회피 대상에서 제외됩니다. 값은 0에서 99사이에서 설정되어야 하며 낮은 숫자가 높은 우선 순위임을 의미합니다. |
Auto Traverse Off Mesh | 자동적으로 횡단하려면 True로 설정해야하고, 애니메이션을 사용하거나 오프메시 링크를 횡단하는 특정한 방법을 사용하고 싶다면 이를 False로 설정합니다. |
Auto Repath | 활성화 시 경로 일부분의 끝에 도달하면 경로를 재탐색합니다. 목적지까지 경로가 없다면 목적지에서 제일 가깝게 도달할 수 있는 위치까지 부분적인 경로가 생성됩니다. |
Area Mask | 경로 탐색에 어떠한 영역 타입을 고려할 것인지를 설명합니다. NavMesh Baking을 위해 Mesh를 준비할 때 각각의 Mesh 영역 타입을 설정할 수 있습니다. 예를 들어 계단을 특별한 영역 타입으로 표시하고 몇몇 캐릭터 타입의 계단 이용을 금지할 수 있습니다. |