Unity Game Development

第7話 淺談AI尋路及延伸

Lecturer:水獺

目錄(可點)

番外延伸

本堂課內容

番外延伸

本堂課內容

番外延伸

安裝Package(s)

AI Navigation

前往Editor左上方

Window

--> Package Manager

--> 左上角In Project改Unity Registry

--> 滑到AI Navigation按Install

就好了?

那它可以幹嘛?

AI Navigation

這個Package可以讓你做到以下幾件事:

  1. 自動尋路
  2. 障礙物型尋路
  3. 可動障礙物型尋路
  4. Offmesh Action(離開尋路網格的行動)

今天會以前三種為主

Nav Mesh Plus

前往 https://github.com/h8man/NavMeshPlus

按綠色按鈕下載Zip檔

Nav Mesh Plus

下載完畢之後找到你的專案資料夾

把這個壓縮檔解壓縮之後將「NavMeshComponents」丟進Assets資料夾中

Nav Mesh Plus

下載完畢之後找到你的專案資料夾

把這個壓縮檔解壓縮之後將「NavMeshComponents」丟進Assets資料夾中

Nav Mesh Plus

這個Package提供了很多原版AI Navigation Mesh的擴充

可以讓我們更容易地完成尋路功能

本堂課內容

番外延伸

本堂課內容

番外延伸

前置作業及腳本

場景

分兩個部分:地板和障礙

首先在Hierarchy中按右鍵新增一個空的GameObject

障礙:空物件上按右鍵 --> 一樣新增一個方形之後調整至長條形 -->加入Rigidbody2D(記得改Kinematic)和Box Collider2D

地板:空物件上按右鍵 --> 2D Objects --> Sprites --> Square新增

一個方形之後調整Transform Scale至符合畫面大小

好了之後新增Prefabs資料夾並把障礙拖進去新增Prefab

玩家

Hierarchy中按右鍵 --> 2D Objects --> Sprites --> Circle新增一個圓形,並加上Rigidbody2D(Gravity Scale改0)、Box Collider2D還有一個移動腳本

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

public class PlayerMove : MonoBehaviour
{
    [SerializeField] new Rigidbody2D rigidbody2D; //鋼體參考
    [SerializeField] float speed = 200f; //移動速度參數
    float horizontal = 0; //水平軸值
    float vertical = 0; //垂直軸值
    
    private void Update() {
        horizontal = Input.GetAxis("Horizontal");
        vertical = Input.GetAxis("Vertical");
        rigidbody2D.velocity = new Vector3(horizontal * speed * Time.deltaTime,vertical * speed * Time.deltaTime,0);
    }
}

移動腳本參考(如果想用InputSystem可以參考之前簡報)

記得建立Prefab

敵人

之後寫一個尋路的腳本

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

public class Enemy : MonoBehaviour
{
    public bool Tracking = false; //是否在尋路狀態
    public Transform Player; //被追蹤的Transform
    NavMeshAgent agent; //一個叫NavMeshAgent的腳本,是尋路物件的核心Component
    private void Start() {
        agent = GetComponent<NavMeshAgent>(); //取得參考
        agent.updateRotation = false; //不轉Sprite方向
        agent.updateUpAxis = false; //不更新朝上軸(上方永遠為Z軸正向)
    }

    private void Update() {
        if(Tracking){
            agent.SetDestination(Player.position); //如果在追蹤狀態就一直把尋路終點設為被追蹤者的位置
        }
        else{
            agent.SetDestination(transform.position); //如果不在追蹤狀態就把尋路終點設為自己的位置
        }
    }
    private void OnCollisionEnter2D(Collision2D col) {
        if(col.gameObject.CompareTag("Player")){ //如果碰到被追蹤者就摧毀
            Tracking = false;
            Destroy(col.gameObject);
        }
    }
}

敵人

還有一個觸發追蹤範圍的腳本

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

public class TrackingRange : MonoBehaviour
{
    private void OnTriggerEnter2D(Collider2D tri) { //如果觸發器被觸發
        if(tri.gameObject.CompareTag("Player") && !transform.parent.GetComponent<Enemy>().Tracking){ //如果觸發的物件為玩家且父物件不在追蹤狀態
            transform.parent.GetComponent<Enemy>().Tracking = true; //更新追蹤狀態
            transform.parent.GetComponent<Enemy>().Player = tri.gameObject.transform; //被追蹤Transform設成玩家Transform 
        }
    }
}

敵人

分兩個部分:主體和追蹤範圍

追蹤範圍:在主體物件上按右鍵新增一個空的GameObject --> 加入Circle Collider2D並把半徑改大到你認為合適的追蹤範圍

--> 把 Is trigger打勾 --> 把第二個腳本附加上去

主體:在Hierarchy中按右鍵 --> 2D Objects --> Sprites --> Circle新增一個圓形,並加上Rigidbody2D(記得改Kinematic)和Circle Collider2D

--> 調整半徑至符合主體大小 --> 把第一個腳本附加上去

記得建立Prefab

管理器

整個尋路系統的核心

目前是一個空物件,等等會講怎麼設定

目前應該要長這樣

本堂課內容

番外延伸

本堂課內容

番外延伸

Nav Mesh Settings

場景

地板:Add Component --> Navigation Modifier

建置網格的時候是否忽略這個GameObject

是否複寫區域性質(可以選Walkable、Not Walkable或Jump ,不勾預設Walkable)

會影響的Agent(這甚麼後面會講),可選All或None

障礙物:Add Component --> Navigation Modifier之後把Override Area改成Not Walkable

管理器

第一步:Add Component --> Navigation Surface

尋路物件類型ID,用來配對適用的網格

在Bake(產生網格)的時候考慮進的遊戲物件,可選All(全部物件,基本上都用這個)、Volume、Children

Bake時考慮的Layer(裡的物件會被全部考慮)

Bake產生的範圍性質,可選Walkable、Not walkable、 Jump

Bake的精確度,越大越精確(但不要超過8,且越大Bake就越慢)

Bake後儲存場景圖塊的大小(預設256*256像素,改太小可能會造成尋路時的錯誤,也就是路徑不是最短路徑)

基本上不用改,用預設就好

管理器

第二步:Add Component --> Navigation CollectSources2D

找不太到這些東西的資料所以我不多作介紹

這個東西大概的用處就是在Bake之後存Bake好的資料

加入之後按一下「Rotate Surface to XY」

敵人

Add Component --> Nav Mesh Agent

基本上就是前面提到的那個Agent Type ID,可以用預設也可以自己設定(下拉選單選Open Agent Settings)

2D用預設就好,3D時因為物件的定位錨不一定在底面,所以可以用這個數值跟Unity說錨點離底面高度是多少

最大速度

最大角速度(影響轉向速度)

最大加速度

距離目標位置多少時停止尋路

到達目的地時減速

避障半徑(後面會用)

避障高度

如果同時要迴避多個東西,避障優先順序低的會被忽略(數值越小順序越高)

避障靈敏度(無則不會主動避障)

在到達目前路線的終點之後再次尋找可能的路徑,如果沒辦法到目的地則自動走向離目的地最近的座標。

敵人

補充:自訂Agent Type

新增一個Agent Type

Agent Type名稱

Agent是由一個圓柱體所定義:

Agent半徑

Agent高

爬階梯會用到的向上尋路步長,這裡不會用

最大可爬坡角(0-60度),這裡不會用

掉落(不會用)

跳躍(不會用)

本堂課內容

番外延伸

本堂課內容

番外延伸

Q&A&DO

建北電資Unity遊戲開發小社第7堂

By MH Yang

建北電資Unity遊戲開發小社第7堂

  • 55