Floor의 Navigation을 Bake 한다
순찰 & 추적할 Enemy를 생성하고 NavMeshAgent와 Enmey.cs를 컴포넌트추가한다
Enemy가 순찰할 포인트를 만든다
빈 오브젝트 PathManager에 자식 WayPoint를 추가한다.
부모에 PathManager.cs도 추가한다
PathManager.cs
스크립트에서 waypoint 순찰 지점 목록을 배열로 가져온다.
//waypoint목록을 가져오고싶다
public class PathManager : MonoBehaviour
{
public static PathManager instance;
public Transform[] wayPoints; //배열 생성
void Awake()
{
instance = this;
}
void Start()
{
MeshFilter[] temp = GetComponentInChildren<MeshFilter>();
wayPoints = new Transform[temp.Length];
for (int i = 0; i < temp.Length; i++)
{
wayPoints[i] = temp[i].transform;
}
}
}
Enemy가 PathManager정보를 가져와야한다
Enemy가 해당 정보를 알고 있는 것도 좋지만, 관리하기 번거롭기 때문에 독립적으로 PathManager을 생성하여 관리하는 것이 좋다
PathManager 스크립트를 싱글톤으로 만들어 Enemy로 가져온다
📌 Enemy.cs (Enemy 순찰로직)
✏️ NavMeshAgent.destination
NavMeshAgent가 할당된 Enemy가 목표 target으로 이동한다
target은 wayPoints 하나의 위치값이다.
Enemy와 목표지점의 거리를 구하여, 거리값이 일정값보다 작으면
wayPoints의 인덱스값을 바꾸어 다음 wayPoints로 다시 이동하는 것을 반복한다.
public class Enemy : MonoBehaviour
{
NavMeshAgent agent;
public int index; //wayPoints 목록
void Start()
{
agent = GetComponent<NavMeshAgent>();
}
void Update()
{
Vector3 target = PathManager.instance.wayPoints[index].position;
//Enemy의 위치는 PathManager 위치로 설정
//PathManager.wayPoints[index] 위치로 이동하고 싶다
agent.destination = target;
//만약 도착했다면, 거리가 2 이하라면
float distance = Vector3.Distance(transform.position, target);
if (distance < 2)
{
//인덱스의 값을 바꾼다
//순방향
int len = PathManager.instance.wayPoints.Length; //len은 4
index = (index + 1) % len;
}
}
}
✏️역방향일 경우 로직
//역방향
float distance = Vector3.Distance(transform.position, target);
if (distance < 2)
{
int len = PathManager.instance.wayPoints.Length;
index = (index + len - 1) % len;
}
✏️ Enemy 상태머신 state 생성 : Patrol / Chase
처음 태어났을 때 Patrol로 태어난다
Update()에는 swith문을 사용하여 State상태머신을 작동시킨다
기존의 Update, wayPoints 순서대로 돌던 Enemy 로직은 UpdatePatrol()로 변경한다
NavMeshAgent agent;
public int index; //wayPoints 목록
public State state;
public enum State
{
Patrol, //순찰
Chase, //추적
}
void Start()
{
agent = GetComponent<NavMeshAgent>();
state = State.Patrol;
}
void Update()
{
switch(state)
{
case State.Patrol:
UpdatePatrol();
break;
case State.Chase:
UpdateChase();
break;
}
}
UpdatePatrol()
{
Vector3 target = PathManager.instance.wayPoints[index].position;
//Enemy의 위치는 PathManager 위치로 설정
//PathManager.wayPoints[index] 위치로 이동하고 싶다
agent.destination = target;
//만약 도착했다면, 거리가 2 이하라면
float distance = Vector3.Distance(transform.position, target);
if (distance < 2)
{
//인덱스의 값을 바꾼다, 순방향
int len = PathManager.instance.wayPoints.Length; //len은 4
index = (index + 1) % len;
}
}
UpdateChase()
{
}
📌 Patrol
✏️ Enemy - UpdatePatrol()
Patrol 상태에서 Chase상태로 전이하는 부분을 추가
만약 감지범위 안에 Player가 감지되었다면 추적 대상을 Player로 하고 추적상태로 전이하고 싶다
fpublic float detectedRadius = 5; //감지거리
Transform chaseTarget;
void UpdatePatrol()
{
//만약 감지반경 안에 Player가 감지되었다면
int layerMask = 1 << LayerMask.NameToLayer("Player");
Collider[] cols = Physics.OverlapSphere(transform.position, detectedRadius, layerMask);
if (cols.Length > 0)
{
//cols[0]은 Player임
//추적대상을 Player로 하고 추적상태로 전이하고싶다
chaseTarget = cols[0].transform;
state = State.Chase;
return;
}
Vector3 target = PathManager.instance.wayPoints[index].position;
//Enemy의 위치는 PathManager 위치로 설정
//PathManager.wayPoints[index] 위치로 이동하고 싶다
agent.destination = target;
//만약 도착했다면, 거리가 2 이하라면
float distance = Vector3.Distance(transform.position, target);
if (distance < 2)
{
//인덱스의 값을 바꾼다, 순방향
int len = PathManager.instance.wayPoints.Length; //len은 4
index = (index + 1) % len;
}
}
🔻 Physics.OverlapSphere()
> OverlapSphere는 Collider배열이다
정의한 Collider 범위 내에 접촉한 Collider에 대한 정보를 반환한다.
특정 Layer의 정보만을 반환 받을 수 있으며, 배열의 형태로 값을 반환받는다
public static Collider[] OverlapSphere(Vector3 position, float radius, int layerMask)
(+) Layer추가 / Player Layer 추가하여 할당
📌 Chase
✏️ Enemy - UpdateChase()
agent.destination 목표 타겟이 Player = chaseTarget 이 되어 추적함
public float chaseDistance = 10; //추적거리
void UpdateChase()
{
//추적대상을 향해 이동하고싶다
agent.destination = chaseTarget.position;
//거리를 측정하고
float distance = Vector3.Distance(transform.position, chaseTarget.position);
//만약 추적대상이 추적거리를 벗어나면
if(distance > chaseDistance)
{
//순찰상태로 전이하고싶다
state = State.Patrol;
}
}
🔻 추적하다가 대상이 멀어져서 순찰 상태로 전이할 때, Enemy가 가장 가까운 WayPoint로 가는 로직
Enmey와 WayPoint 사이의 거리를 모두 잰 후에 가장 가까운 지점으로 향함
가장 가까운 순찰위치를 목적지로 하고싶다
if (distance > chaseDistance)
{
//순찰상태로 전이하고싶다
state = State.Patrol;
// 나와 wayPoints의 거리를 측정하고
float patrolDistance = float.MaxValue;
int tempIndex = -1;
//가장 가까운 순찰위치를 목적지로 하고싶다
Transform[] wayList = PathManager.instance.wayPoints;
for (int i = 0; i < wayList.Length; i++)
{
float temDist = Vector3.Distance(transform.position, wayLIst[i].position);
if (tempDist < patrolDistance)
{
tempIndex = i;
patrolDistance = tempDist; //가장 작은 값이 patrolDistance에 담긴다
}
if(tempIndex != -1) //찾았다면 목적지를 tempIndex로 하고싶다
{
index = tempIndex;
}
}
}
'유니티' 카테고리의 다른 글
미니맵 만들기 / Raw Image / Render Texture (0) | 2022.06.06 |
---|---|
Slider HP Bar / property / Billboard (0) | 2022.06.06 |
애니메이션의 특정 부분에 다른 이벤트가 함께 나타나는 기능 / Animation Event / Hit (0) | 2022.06.05 |
공격을 받았을 때 Material 바꾸기 (Flash effect) (0) | 2022.05.24 |
싱글톤 Singleton (C#) (0) | 2022.05.15 |