Unity Game Development
第7話 淺談AI尋路及延伸
Lecturer:水獺
目錄(可點)
本堂課內容
本堂課內容
安裝Package(s)

AI Navigation

前往Editor左上方
Window
--> Package Manager
--> 左上角In Project改Unity Registry
--> 滑到AI Navigation按Install
就好了?
對
那它可以幹嘛?
✋

你們應該是Install(我已經裝過了)
AI Navigation

這個Package可以讓你做到以下幾件事:
- 自動尋路
- 障礙物型尋路
- 可動障礙物型尋路
- 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度),這裡不會用
掉落(不會用)
跳躍(不會用)
Bake

以上所有設定都做好之後
就可以按下管理器Component上的Bake


原本是空的
這些被綠色線框住的地方
就是自動巡路的範圍啦
依據前面設定的障礙物排除範圍後
自動建立範圍

本堂課內容
本堂課內容
番外延伸

移動障礙

現在我已經有兩個不會動的障礙物了
但是如果我想讓它動起來
產生不一樣的地圖 該怎麼做?


❓
✋
移動障礙

移動障礙並不用想的太難
因為Nav Mesh Plus非常強大
即使障礙物在移動
Bake出來的限制範圍也可以跟著移動的障礙物產生變化



Q&A&DO

建北電資Unity遊戲開發小社第7堂
By MH Yang
建北電資Unity遊戲開發小社第7堂
- 74