Wander : 떠돌다
RPG게임에서 야생동물이나, 오픈월드게임에서 시민NPC들이 정처없이 떠도는걸 말한다.
활용한 에셋:
에셋스토어에는 100불짜리 에셋밖에없지만 제작자 홈페이지에 들어가면
여기서 무료버전도 배포하고있다.
몇가지 기능이 제한돼있다는데 그럼에도 충분히 원하는기능을 구현하기에는 부족함이 없다.
* 이 게시물은 개인 기록용이므로 이 에셋에대한 자세한 사용법은 다루지
않습니다.
맵 오브젝트에 이렇게 컴포넌트를 크기에맞게 세팅해주고 스캔을 누르면
Walkable영역은 파란색으로 기즈모를 보여준다(Navmesh와 비슷)
그리고 이 위를 움직일 Agent에게 이 3개의 컴포넌트를 달아줘야한다
AI Destination Setter컴포넌트의 Target변수에 할당된 오브젝트를 쫒아 이동하는 방식이라
항상 타겟오브젝트가 필요하다.
이 글의 목적은 Wander구현이었으니,
구현전에 먼저 방법을 생각해보자면
여기서 Target오브젝트를 Walkable구역중에 랜던함곳으로 일정주기마다 혹은 Target에 도착할때마다 옮겨주면 된다.
우선 초기화 코드다.
여기선 웨이포인트 오브젝트를 눈으로 식별할수있게 3D스피어로 동적생성했는데
사실 굳이 그럴필요없이 변수를 Public으로 선언하고 인스펙터에 손으로 넣어도 상관없다.
// 이 에셋의 코드에 접근하기위한 네임스페이스
using Pathfinding;
.
.
.
// 현재 프로젝트에 개발중인 몬스터의 클래스(내용과 상관없음)
public class DragoonMonster : MonsterController
{
// 타겟을 집어넣을 컴포넌트
private AIDestinationSetter destinationSetter;
// 움직임을 설정하는 컴포넌트
private AIPath aiPath;
// 이 클래스에서 초기화를 담당하는곳 다른프로젝트에선 그냥 Start()에서해도 무방
public override void OnStateEnter(MonsterState state)
{
switch (state)
{
case MonsterState.Patrol:
// 웨이포인트를 3D 스피어로 동적생성 => 그냥 public으로 직접 집어넣어도 무방
if (testWayPoint == null)
testWayPoint = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform;
// 동적생성한 웨이포인트를 타겟으로 지정
destinationSetter.target = testWayPoint;
// 움직임 허용
aiPath.canMove = true;
break;
}
}
}
아래 코드처럼 임의로 설정한 타이머의 시간이 다 됐거나, 웨이포인트에 닿았다면 =>
범위안에 랜덤한 지점을 찍어서 그 지점에서 제일 가까운 Walkable한 노드로 웨이포인트를 옮겨준다.
.
public float waypointSearchRadius = 10f;
public float originWaypointSearchTime = 3f;
private float waypointSearchTimer;
// 맵에 부착했던 길을 베이크해주는 컴포넌트
private AstarPath myArenaPath;
// Update()
public override void StateUpdate(MonsterState state)
{
switch (state)
{
case MonsterState.Patrol:
// 재검색 시간이 됐거나 웨이포인트에 도착했다면
if (waypointSerachTimer <= 0f || aiPath.remainingDistance <= 0.1f)
{
// 범위안에 랜덤한 지점을 찍는다.
Vector3 randomDir = Random.insideUnitSphere * waypointSearchRadius;
// 범위의 중심을 Agent의 포지션으로 보정
randomDir += transform.position;
// 위아래로 움직이진 않을것이므로 y값은 Agent의 y값으로 고정
randomDir.y = transform.position.y;
// 가까운 웨이포인트를 찾을때 제한조건 설정 => 여기서는 Walkable한 노드만 검색
NNConstraint constraint = new NNConstraint()
{
walkable = true,
constrainWalkability = true,
constrainDistance = false
};
// 베이크된 길에서 갈수있는 노드를 찾아 웨이포인트를 그 포지션으로 옮겨줌
// GetNearest()라는 함수도 있는데 이함수는 가끔 Walkable하지않은 노드를 반환해줌
// GetNearestForce()는 제한조건을 확실히 들어주는 함수인듯함
testWayPoint.position = myArenaPath.graphs[0].GetNearestForce(randomDir, constraint).clampedPosition;
// Timer초기화
waypointSerachTimer = originWaypointSearchTime;
// target을 바꿧으니 Path도 다시계산해준다.
aiPath.SearchPath();
}
else
waypointSerachTimer -= Time.deltaTime;
break;
}
}
결과적으로 이렇게 확실한 목적지없이 잘 떠돌아 다니게 된다.
참고한 링크
Navmesh Wander스크립트
여담
확실한 웨이포인트들이 필요한 정찰과는 달리 불규칙하게 정처없이 떠돌아다녀야 할 경우에는
생각보다 구현할때 번거로운 점들이 있다.
이 에셋을 활용하면 에셋안에 있는 변수들, 함수들만 잘 찾는다면 아주 쉽게 구현할수 있다.
Navmesh로 쓴다해도 위 링크에있는 코드를 활용하면 쉽게 구현할 수 있을것 같다.
'Unity > C#' 카테고리의 다른 글
[Unity] JSON을 딕셔너리처럼 입출력하기 (0) | 2022.05.17 |
---|---|
[Unity] Raycasthit.transform과 Raycasthit.collider.transform (0) | 2022.05.09 |
[Unity] FSM패턴 (0) | 2022.02.22 |
[Unity, C#] Vector3 회전 (0) | 2022.01.28 |
[C#]선택적 매개변수로 Color사용 / ?? 및 ??=, ?. 연산자 (0) | 2022.01.28 |