Unity Navigation ์‚ฌ์šฉ๋ฒ•, NavMesh, NavAgent

5 ๋ถ„ ์†Œ์š”

๐Ÿ’ก ๊ณต๋ถ€ํ•œ ๋‚ด์šฉ ์ ๊ธฐ

Unity Navigation ์‚ฌ์šฉ๋ฒ• Nav Mesh Agent, Obstacle, ์ฝ”๋“œPermalink

navigation์€ 3D๊ฒŒ์ž„์—์„œ ์•„๊ตฐ ๋˜๋Š” ์ ๊ตฐ์ด ๊ธธ์„ ์ฐพ์•„๊ฐ€๋Š”๋ฐ ์“ฐ์ด๋Š” package๋กœ unity์—์„œ ์ œ๊ณตํ•œ๋‹ค.

์ด ๊ธ€์€ Nav Mesh๋กœ ํ•  ์ˆ˜ ์žˆ๋Š” ์…‹ํŒ…๊ณผ ์†Œ์Šค์ฝ”๋“œ์— ๋Œ€ํ•ด ์ ์—ˆ๋‹ค.

์ด๋ฏธ ์ž˜ ์•„๋Š” ์‚ฌ๋žŒ์€ ์ •๋ฆฌ๋œ ๊ธ€์„ ์ฝ์œผ๋ฉด ๋˜๊ณ  ์ฒ˜์Œ ์ ‘ํ•œ ์‚ฌ๋žŒ์€ ์•„๋ž˜ ์˜์ƒ์„ ๋ณด๋ฉด์„œ ๊ณต๋ถ€ํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค. ๋ฒ ๋ฅด์˜ ๊ฒŒ์ž„ ๊ฐœ๋ฐœ - navigation์„ค๋ช…

๋‚˜๋„ ์—ฌ๊ธฐ ๋ณด๋ฉด์„œ ์ดํ•ดํ•  ๊ฒƒ์„ ์•„๋ž˜์— ์ •๋ฆฌํ•œ๊ฒƒ์ด๋‹ค.

1. NavMeshAgentPermalink

์•„๋ž˜ ์…‹ํŒ…์„ ์‚ฌ์ „ ์ž‘์—… rigidbody์˜ Constraints๋ฅผ ๋ชจ๋‘ ๋ง‰๋Š”๋‹ค

image-20220813025029857

  • Base Offset : ์ปฌ๋ผ์ด๋” ์ฒ˜๋Ÿผ ๋‚ด ์ถฉ๋Œ ํŒ์ •ํ•˜๋Š”๊ฑฐ ์œ„์น˜ ์žก๋Š”๊ฑฐ์ธ๋“ฏ
  • Speed : ๋ชฉ์ ์ง€๊นŒ์ง€ ๊ฐ€๋Š” ์†๋„
  • Angular Speed : ๋ชฉ์ ์ง€ ๊ฐˆ๋•Œ ๋ฐฉํ–ฅ ๋Œ๋ฆฌ๋Š” ์†๋„
  • Acceleration : ์ตœ๋Œ€ ์†๋„ ๋„๋‹ฌ ์†๋„ ๋ฐ”๋กœ ๋ฐ”๋กœ ์›€์ง์ด๋ ค๋ฉด 1000 ์ด๋ ‡๊ฒŒ ์ฃผ๋Š”๊ฒƒ๋„ ์ข‹๋‹ค
  • Stopping Distance : ๋ชฉ์ ์ง€ ์–ผ๋งˆ๋‚˜ ์ „์— ๋ฉˆ์ถœ๊ฒƒ์ธ์ง€, range ์œ ๋‹›์šฉ
  • Auto Braking : ๋ชฉ์ ์ง€ ๋„์ฐฉ์ „๋ถ€ํ„ฐ ๊ฐ์†ํ•  ๊ฒƒ์ธ์ง€, ์ฒดํฌ๋ฅผ ํ’€๋ฉด ๋ชฉ์ ์ง€๋ฅผ ์ง€๋‚˜์ณ๊ฐ ๊ฐ ๊ฐ’๋“ค์„ ์ƒ๊ฐ ๋ณด๋‹ค ํฌ๊ฒŒ ์žก์•„์•ผํ• ๋“ฏ

image-20220813024502997

  • Radius : ๋‹ค๋ฅธ ์œ ๋‹›๋“ค์„ ๋ฐ€์ณ๋‚ด๋Š” ๋ฒ”์œ„, ๋ฒฝ๋“ค์— ๊ฑธ๋ฆฌ์ง€๋Š” ์•Š์Œ
  • Height : ๋‹ค๋ฅธ ์œ ๋‹›์„ ๋ฐ€์ณ๋‚ด๋Š” ๋†’์ด
  • Quality : ๋‹ค๋ฅธ ์œ ๋‹›์„ ํ”ผํ•˜๋Š” ์›€์ง์ž„์˜ ์ •๋ฐ€๋กœ ์กฐ์ •
  • Priority : ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์€ agent๋Š” ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋‚ฎ์€ agent๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ์ง€๋‚˜๊ฐ, ๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„๋Š” ๋†’์€ ์šฐ์„ ์œ„๋ฅผ ๋ฐ€์ง€ ๋ชปํ•จ
  • Auto Traverse Off Mesh : โ€”
  • Auto Repath : mesh๋“ฑ์˜ ์ƒํ™ฉ์ด ๋ณ€ํ• ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ ๊ธธ์„ ์ฐพ์Œ(๊ฒฝ๋กœ๋ฅผ ์žฌ๊ณ„์‚ฐ), ํ•˜์ง€๋งŒ ์‹œ์•ผ์— ๋ณด์ด์ง€ ์•Š์•„๋„ ๋ฐ”๋กœ๋ฐ”๋กœ ์ฐพ๊ธฐ ๋•Œ๋ฌธ์— ์‹œ์•ผ์— ๋ณด์ด์ง€ ์•Š๋Š”๊ณณ๊นŒ์ง€ ์ด๋™ํ•œ๋’ค ๋ชป์›€์ง์ด๋Š” ์ƒํ™ฉ์— ๋‹ค๋ฅธ action์„ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ฒดํฌ๋ฅผ ํ•ด์ œํ•˜๊ณ  ์ฝ”๋“œ๋กœ ์Šน๋ถ€๋ฅผ ๋ด์•ผํ•จ
  • Area Mask : ๊ฐ์ข… ํƒ€์ž…๋“ค์ด ์ •ํ•ด์ ธ์žˆ๊ณ , ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฌผ๋กœ ๋ชป๊ฐ€๋Š” ์œ ๋‹›์€ ๋ฌผ์„ ์„ ํƒํ•ด์ œํ•˜๋ฉด ๊ทธ์ชฝ์œผ๋กœ ๊ฐ€์ง€ ์•Š๋Š”๋‹ค.

2. NavMesh ObstaclePermalink

NavMesh agent๊ฐ€ ์•„๋‹Œ obstacle

Navgation static(๋ฒฝ ๋“ฑ) ์œผ๋กœ ์„ค์ •๋œ๊ฒƒ๊ณผ navmesh obstacle๋กœ ์„ค์ •๋œ๊ฒƒ์˜ ๊ฐ€์žฅ ํฐ์ฐจ์ด๋Š” obstacle์€ ๊ฒŒ์ž„ ์ค‘์— ์›€์ง์ผ ์ˆ˜ ์žˆ๋Š” ์žฅ์• ๋ฌผ์ด๋‹ค.

image-20220813140424655

  • **Carve ** : ์‹ค์‹œ๊ฐ„์œผ๋กœ navmesh ์œ„์น˜๋ฅผ ํŒŒ๋‚ด์„œ ์ง€๋‚˜๊ฐˆ ์ˆ˜ ์—†๋Š” ์˜์—ญ์œผ๋กœ ๋งŒ๋А๋“ ๊ฒƒ
  • Move Threshold : Threshold๋ณด๋‹ค ์ ๊ฒŒ ์›€์ง์ธ๊ฒƒ์€ ์ƒˆ๋กœ ์›€์ง์ธ๊ฑธ๋กœ ํŒ๋‹จํ•˜์ง€ ์•Š์•„์„œ Carve๋ฅผ ์ƒˆ๋กœ ๊ทธ๋ฆฌ์ง€ ์•Š์Œ

  • Time to Stationary : ์›€์ง์ž„์„ ๋ฉˆ์ถ”๊ณ  navmesh๋ฅผ ์ƒˆ๋กœ ๊ณ„์‚ฐํ•˜๋Š”๋ฐ ์ด๊ฑด 0.5์ดˆ ํ›„์— ๊ณ„์‚ฐํ•œ๋“œ๋Š”๋œป
  • Carve Only Stationary : ์ฒดํฌ ๋ฐ•์Šค๋ฅผ ๋„๋ฉด ์›€์ง์ผ ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ ๊ณ„์‚ฐํ•˜๋Š”๋ฐ, ์ด๋Ÿฌ๋ฉด ๋” ์ž์—ฐ์Šค๋Ÿฝ์ง€๋งŒ ์„ฑ๋Šฅ์— ์•ˆ์ข‹๋‹ค. ๊ทธ๋ž˜์„œ ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•œ๊ณณ์—์„œ๋งŒ ๋„์ž. ๋ฐ”๋กœ ์œ„์˜ ์˜ต์…˜๊ณผ ๊ด€๋ จ์ด ์žˆ์Œ

3. ํด๋ฆญํ•œ ์œ„์น˜๋กœ ์บ๋ฆญํ„ฐ ์ด๋™Permalink

๋ฒ ๋ฅด์˜ ๊ฒŒ์ž„ ๊ฐœ๋ฐœ - ํด๋ฆญํ•œ ์œ„์น˜๋กœ ์บ๋ฆญํ„ฐ ์ด๋™

a. NavAgent๋ฅผ ์•ˆ์“ด ์ฝ”๋“œPermalink

  1. ๋งˆ์šฐ์Šค ํ„ฐ์น˜ ์‹œ Raycast๋กœ ๋ชฉ์ ์ง€ point๋ฅผ SetDestination()
  2. move ๋ณ€์ˆ˜ true ๋ฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ณ€๊ฒฝ
  3. move() ํ•จ์ˆ˜ ์ง€์†์  update ๋ชฉํ‘œ ์œ„์น˜ ๋„๋‹ฌ ์‹œ move = false ๋ฐ animation ๋ณ€๊ฒฝ
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            RaycastHit hit;
            if (Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out hit))
            {
                SetDestination(hit.point);
            }
        }
        Move();
    }

    private void SetDestination(Vector3 dest)
    {
        destination = dest;
        isMove = true;
        SetAnimation(ANIMATION_QUADRUPED_WALK);
    }

    private void Move()
    {
        if (isMove)
        {
            var dir = destination - transform.position;
            transform.forward = dir; // ๋ฐ”๋ผ๋ณด๋Š” ๋ฐฉํ–ฅ
            transform.position += dir.normalized * Time.deltaTime * 5f;
        }
        if (Vector3.Distance(transform.position, destination) <= 1f)
        {
            isMove = false;
            SetAnimation(ANIMATION_IDLE_C);
        }
    }

    private void SetAnimation(int what)
    {
        animator.SetInteger("animation", what);
    }

b. NavAgent๋ฅผ ์“ด ์ฝ”๋“œPermalink

  1. agent.updateRotation = false : ๋ฐฉํ–ฅ์„ ์ง์ ‘ ์ •ํ•ด์ค„๊บผ๋ผ ํ•„์š”์—†์Œ
  2. ์ง์ ‘ ์œ„์น˜๋ฅผ ๋ฐ”๊พธ๋˜ ์ฝ”๋“œ๋ฅผ agent.SetDestination์œผ๋กœ ๋ณ€๊ฒฝ
  3. ๋ณด๋Š” ๋ฐฉํ–ฅ์„ agent.steeringTarget๋ฅผ ์ด์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝ
agent.updateRotation = false; // ์บ๋ฆญํ„ฐ๊ฐ€ ๋ณด๋Š” ๋ฐฉํ–ฅ์„ ๋‚ด๊ฐ€ ์ง์ ‘ ์ง€์ •ํ•ด ์ค„๊ฑฐ๋‹ˆ๊นŒ ๊ตณ์ด ๋กœํ…Œ์ด์…˜์„ ๋ฐ”๊ฟ€ ํ•„์š” ์—†์Œ
    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            RaycastHit hit;
            if (Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out hit))
            {
                SetDestination(hit.point);
            }
        }
        LookMoveDirection();
    }

    private void SetDestination(Vector3 dest)
    {
        destination = dest;
        agent.SetDestination(destination);
        isMove = true;
        SetAnimation(ANIMATION_QUADRUPED_WALK);
    }

    private void LookMoveDirection()
    {
        if (isMove)
        {
            if (agent.velocity.magnitude == 0f)
            {
                isMove = false;
                SetAnimation(ANIMATION_IDLE_C);
                return;
            }

            var dir = new Vector3(agent.steeringTarget.x, transform.position.y, agent.steeringTarget.z) - transform.position;
            transform.forward = dir;
        }
    }

    private void SetAnimation(int what)
    {
        animator.SetInteger("animation", what);
    }

๊ธ€์ž์ƒ‰ sample

fire brick

violet

drak green

medium blue

dark quoise

fire brick

violet

drak green

medium blue

dark quoise

๐Ÿ”” ํฌ์ŠคํŒ… ๊ณต์ง€
ใ…ใ…‡ใ„ดใ„ปใ„ดใ…‡

ํƒœ๊ทธ:

์นดํ…Œ๊ณ ๋ฆฌ:

์—…๋ฐ์ดํŠธ: