상세 컨텐츠

본문 제목

[유니티 소소모임] 3주차. 유니티 에디터 배우기 2 (Editor : Hetbahn)

24-25/Untiy

by 롱롱😋 2024. 11. 8. 10:01

본문

728x90

 

 

Navigation Mesh

바닥, 장애물과 같은 게임 월드의 정보를 미리 저장해두고, 에이전트가 이동할 때 저장된 정보를 바탕으로 장애물을 피해 목표 위치까지 이동할 경로를 탐색함. 게임 월드에 네비게이션 매쉬를 설정하고, 이동 에이전트가 NavMeshAgent 컴포넌트를 기반으로 이동하도록 설정함

또한 OffMeshLink, NavMeshObstacle 등의 컴포넌트도 활용함

 

1. 강의 링크에 있는 미리 만들어둔 GameWorld 패키지를 import

2. GameWorld 프리팹을 씬에 배치함

 

 

3. Window - AI - Navigation (Obsolete)를 클릭해 Navigation View에서 Navigation Mesh를 설정함

 

4. Navigation View의 Object 탭을 누른 다음 Mesh Renderers를 클릭하고, 하이어라키에 있는 GameWorld 하위 항목을 모두 선택한 후 "Navigation Static" 변수를 체크해 Navigation Mesh 데이터로 사용 가능하게 함

 

5. Navigation View의 Bake 탭에서 "Bake" 버튼을 누르면, 현재 설정된 정보를 바탕으로 Navigation Mesh 데이터를 설정함

  • Scene View에서 하늘색으로 표시되는 부분이 이동 가능한 부분 (Navigation View가 활성화되어 있어야 Navigation Mesh가 출력)
  • 맵에 새로운 바닥이나 장애물을 설치했다면 Navigation Static 설정과 Bake를 다시 진행

Navigation Mesh 데이터가 저장되어 있는 에셋 파일을 확인 가능

 

6. 3D Object - Capsule로 Player 오브젝트를 만들고 Material을 설정한 뒤, transform을 리셋하고 position을 (0,1,0)으로 변경

7. Player 오브젝트에 Nav Mesh Agent 컴포넌트를 추가

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class MoveMent3D : MonoBehaviour
{
    [SerializeField]
    private float moveSpeed = 5.0f;
    private NavMeshAgent navMashAgent;


    // Start is called before the first frame update
    private void Awake()
    {
        navMashAgent = GetComponent<NavMeshAgent>();
    }

    // Update is called once per frame
    public void MoveTo(Vector3 goalPosition)
    {
        // 기존에 이상 행동을 하고 있었다면 코루틴 중지
        StopCoroutine("OnMove");
        // 이동 속도 설정
        navMashAgent.speed = moveSpeed; 
        // 목표 지점 설정 (목표까지의 경로 계산 후 알아서 움직임)
        navMashAgent.SetDestination(goalPosition);
        // 이동 행동에 대한 코루틴 시작
        StartCoroutine("OnMove");
    }

    IEnumerator OnMove()
    {
        while (true)
        {
            // 목표 위치(navNeshAgent.detination)와 내 위치(transform.position)의 거리가 0.1 미만일때
            // 즉, 목표 위치에 거의 도착했을때
            if(Vector3.Distance(navMashAgent.destination, transform.position) < 0.1f)
            {
                // 내 위치를 목표 위치로 설정
                transform.position = navMashAgent.destination;
                // SetDestination()에 의해 설정된 경로를 초기화. 이동을 멈춘다
                navMashAgent.ResetPath();

                break;
            }

            yield return null;
        }
    }
}

 

  • NavMeshAgent와 같은 유니티의 인공지능 기능을 사용하기 위해서는 UnityEngine.AI가 필요
  • NavMeshAgent.SetDestination(Vector3 position);: position을 목표 지점으로 설정 (목표 지점만 설정되면 경로를 탐색하여 자동으로 이동)
  • float distance = Vector3.Distance(Vector3 a, Vector3 b);: a와 b 두 벡터 사이의 거리 값(distance)을 구함
  • NavMeshAgent.destination: SetDestination()으로 설정한 목표 지점의 Vector3 정보가 저장됨
  • NavMeshAgent.ResetPath();: 현재 설정된 이동 경로를 초기화하여 이동을 멈추게 함

 

 

Physics.Raycast()를 이용한 오브젝트 선택

우리가 보고 있는 화면은 2차원 모니터이고, 게임 세상은 3차원임.

즉, 2차원(2D) 화면을 통해 3차원(3D) 오브젝트를 제어해야 함

 

구현 원리:

  1. 카메라에서 플레이어가 클릭한 마우스 위치를 관통하는 광선을 생성해 발사
  2. 카메라에 보이는 화면을 관통해 뻗어나가는 광선은 지정한 길이에 도달하거나 오브젝트에 부딪히면 멈춤
  3. 오브젝트에 부딪힌 경우, 가장 먼저 부딪힌 오브젝트의 정보를 반환 (광선에 부딪혔다는 것은 마우스로 해당 오브젝트를 선택했다는 의미)

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private MoveMent3D movement3D;

    private void Awake()
    {
        movement3D = GetComponent<MoveMent3D>();
    }

    // Update is called once per frame
    private void Update()
    {
        // 마우스 왼쪽 버튼을 눌렀을때
        if (Input.GetMouseButtonDown(0))
        {
            RaycastHit hit;
            // Camera.main : 태그가 "Camera"인 오브젝트 = "Main Camera"
            // 카메라로부터 마우스 좌표(Input.mousePosition)위치를 관통하는 광선 생성
            // ray.origin : 광선 시작 위치
            // ray.direction : 광선의 진행 방향
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            // Physics.Raycast() : 광선을 발사해서 부딪치는 오브젝트를 검출
            // (광선에 부딪치는 오브젝트가 있으면 true 반환)
            // ray.origin 위치로부터 ray.direction 방향으로 무한한 길이(Mathf.Infinity)의 광선 발사
            // 광선에 부딪치는 오브젝트의 전보를 hit에 저장
            if(Physics.Raycast(ray, out hit, Mathf.Infinity))
            {
                // hit.transform.position : 부딪힌 오브젝트의 위치
                // hit.point : 광선과 오브젝트가 부딪힌 세부 위치

                // hit.point를 목표 위치로 이동
                movement3D.MoveTo(hit.point);
            }
        }
    }
}

 

 

클릭한 위치로 플레이어를 이동시키며, 이동 경로가 없는 곳(절벽, 높은 경사면)으로는 가지 못함

 

 


해당 포스트는 고박사, [ 따라하면서 배우는 고박사의 유니티 기초[유니티 2D 기초 (Unity 3D Basic)] ], (2020, 07월 06일) 인프런 강의를 참고하여 작성하였습니다.

 

 

 

Corner Unity

Editor : Hetbahn

728x90

관련글 더보기