
오늘은 nav mesh를 이용해 무작위로 돌아다니는 시스템을 만들어보려구 합니다
+ 월리를 찾아서 게임

오브젝트가 돌아다닐 바닥 부분에 NavMesh Surface 컴포넌트를 붙여줍시다
그 이후 bake를 누르면, 파란 부분으로 돌아다닐 수 있는 표면을 정해줍니다

참고로 로봇은 에셋스토어에서 free로 되어있는 이 친구 이용했습니다


가져온 친구에게 Nav Mesh Agent를 붙여줍니다
이건 Nav Mesh를 사용해 자동으로 움직일 오브젝트 라는 뜻이구요
크게 살펴보실만한 변수들은
Speed: 이동속도
Angular Speed: 각 회전 속도
Acceleration: 최대 가속
Radius: Agent들끼리 서로 부딪친다고 확인될 반지름
Height: 높이
Priority: 우선순위 (숫자가 낮은애가 우선순위가 높아 다른 애들 빵빵 치고다님)
참고로 저는 클릭을 위해 Capsule Collider is trigger로 넣어둬서 이 부분은 무시해주시고 보시면 됩니다
다음으로 아래 코드를 작성해 넣어주세요
using UnityEngine;
using UnityEngine.AI;
using System.Collections;
public class ExploreAI : MonoBehaviour
{
public float updateInterval = 3f;
private NavMeshAgent agent;
private float timeSinceLastUpdate;
private Animator anim;
[Header("애니메이션 이름")]
[SerializeField] private string walkAnimName = "Walk";
[SerializeField] private string jumpAnimName = "Jump_Start"; // 도착 시 점프용
[SerializeField] private string wrongAnimName = "BasicAttack"; // 틀린 로봇 클릭 시
[SerializeField] private string correctAnimName = "Death"; // 정답 로봇 클릭 시
[Header("정답 로봇인지 여부")]
public bool isCorrect = false; // Inspector에서 한 로봇만 true로 설정
private bool isWaiting = false; // 도착 후 점프/대기 루틴 중인지
private bool isInteracting = false; // 클릭 후 A/B 애니메이션 재생 중인지
private void Start()
{
agent = GetComponent<NavMeshAgent>();
anim = GetComponent<Animator>();
updateInterval = Random.Range(3.0f, 5.0f);
timeSinceLastUpdate = updateInterval;
SetNewDestination();
}
private void Update()
{
// 점프/대기 중이거나, 클릭 상호작용 중이면 이동 로직 멈춤
if (isWaiting || isInteracting)
return;
timeSinceLastUpdate += Time.deltaTime;
bool arrived =
!agent.pathPending &&
agent.remainingDistance <= agent.stoppingDistance;
// 목적지 도착 → 점프 루틴
if (arrived)
{
StartCoroutine(ArrivalRoutine());
}
// 도착 전인데 일정 시간이 지나면 새 목적지
else if (timeSinceLastUpdate >= updateInterval)
{
SetNewDestination();
}
}
/// <summary>
/// 목적지 도착했을 때 1초 멈추고 Jump 애니메이션 재생 후 다시 이동
/// </summary>
private IEnumerator ArrivalRoutine()
{
isWaiting = true;
agent.isStopped = true;
anim.Play(jumpAnimName);
yield return new WaitForSeconds(1f);
SetNewDestination();
isWaiting = false;
}
/// <summary>
/// 새 랜덤 목적지 설정 + 걷기 애니메이션 재생
/// </summary>
private void SetNewDestination()
{
Vector3 randomPosition = GetRandomPositionOnNavMesh();
agent.isStopped = false;
agent.SetDestination(randomPosition);
anim.Play(walkAnimName);
timeSinceLastUpdate = 0f;
updateInterval = Random.Range(3.0f, 5.0f);
}
private Vector3 GetRandomPositionOnNavMesh()
{
Vector3 randomDirection = Random.insideUnitSphere * 20f;
randomDirection += transform.position;
NavMeshHit hit;
if (NavMesh.SamplePosition(randomDirection, out hit, 20f, NavMesh.AllAreas))
{
return hit.position;
}
else
{
return transform.position;
}
}
// ===========================
// 👉 클릭 되었을 때 호출
// ===========================
public void OnClicked()
{
// 이미 상호작용 중이면 무시
if (isInteracting)
return;
if (isCorrect)
{
StartCoroutine(CorrectRoutine());
}
else
{
StartCoroutine(WrongRoutine());
}
}
/// <summary>
/// 틀린 로봇 클릭 시: 이동 멈춤 → A 애니메이션 → 다시 랜덤 이동
/// </summary>
private IEnumerator WrongRoutine()
{
isInteracting = true;
agent.isStopped = true;
agent.ResetPath();
anim.Play(wrongAnimName);
// A 애니메이션 길이에 맞게 조정 (예: 1.0f~2.0f)
yield return new WaitForSeconds(1.0f);
// 다시 돌아다니기 시작
isInteracting = false;
SetNewDestination();
}
/// <summary>
/// 정답 로봇 클릭 시: 이동 멈춤 → B 애니메이션 → 게임 종료
/// </summary>
private IEnumerator CorrectRoutine()
{
isInteracting = true;
agent.isStopped = true;
agent.ResetPath();
anim.Play(correctAnimName);
// B 애니메이션 재생 시간만큼 대기
yield return new WaitForSeconds(1.5f);
// 게임 종료 호출
SpotGameManager.Instance.EndGame();
}
}
지피티를 이용해 주석을 달아두었으니 참고해주시구요
대충은 이렇습니다
3~5초 사이로 surface 위 중 범위 20 내로 좌표 하나를 고릅니다.
그 위치로 이동중 시간이 끝나면 새로 시간 및 좌표를 세팅합니다.
시간내로 좌표를 도착한다면 점프 애니메이션을 보여줍니다.
마우스 클릭을 하면 (따로 코드 작성 필요) isCorrect 값에 따라 다른 애니메이션을 출력합니다
저는 월리를 찾아서 처럼 찾는 로봇을 클릭하면 게임이 끝나는 식으로 작성하고 싶어
이외의 코드들을 작성했으니 필요없는 부분들은 제거해주세요

43개 정도 만들고, 각각의 로봇들에게 색깔이나 머리위에 오브젝트들이 다르게 설정해두었습니다

기본적으로 로봇들은 random한 시간 동안 (3~5사이) 이동하고, 해당 목적지에 도착했다면 점프합니다
도착을 못했는데 시간이 끝나면 새로 surface 위에서 목표 지점을 지정하고 계속 움직입니다

마우스로 누른 오브젝트에는 코드의 OnClicked가 작동되게 해뒀습니다
이동을 무시하고 미리 선언해둔 BasicAttack의 애니메이션을 작동합니다.

미리 하나의 로봇만 isCorrect를 true로 인스펙터창에서 바꿔준 다음,
true인 로봇을 클릭하면 Death 애니메이션을 실행하고 멈춥니다
'공부 > Unity' 카테고리의 다른 글
| [Unity] exe 파일이 차단당했을때 (스마트 앱 컨트롤 차단) (0) | 2025.09.22 |
|---|---|
| [Unity] 전체 카메라 fade in / out 효과 (Post processing color adjustment) (0) | 2025.09.19 |
| [Unity] is using a shader without GPU deformation support. Switching the renderer over to CPU deformation. Shader 오류 (0) | 2025.09.15 |
| [Unity] URP 3D 환경에서 2D 리깅 안 될때 (2D Animation, Skinning Editor) (0) | 2025.09.15 |
| [Unity] 애니메이터 랜덤 딜레이 시간 (0) | 2025.09.01 |