一個簡易的兩點移動巡邏AI

因為單純要寫一個敵人AI在兩個端點移動並待機幾秒,所以這個程式沒有寫得很複雜。



主要用四個布林來判斷狀態,分別為
行走 、 待機 、 是否面對方向 、 是否到達巡邏點

待機開始時,會先關閉判斷是否到達巡邏點的布林,所以在開頭會以



#pragma strict
var pointA : Transform; // 巡邏點A
var pointB : Transform; // 巡邏點B
var lookAtTarget : Transform; // 目前巡邏
var lookAtPos: Vector3; // 目前巡邏點座標
var lookAtPoint :int = 1; // 預設巡邏點
var Gravity : float = 20.0; // 重力
var walkSpeed : float = 1.0; // 走路速度
var idleTimes : float = 3.0; // 待機時間

// ------- 狀態布林 ---------- // : 行走、待機、面對方向、到達巡邏點
var walk:boolean;
var idle:boolean;
var isFaced:boolean;
var inPoint:boolean;
private var MoveDirection : Vector3 = Vector3.zero;


function Start () {
idle = true;
inPoint = true;
}

來進行初始化的動作。
在物件結構上,會建立一個空物件(Empry),底下分別擺放敵人模型、巡邏點A(Empry)、巡邏點B(Empry),並將兩個巡邏點拉到開頭宣告的兩個 Transform。


而在每個影格不斷反覆確認各種狀態,行走第一次則要先確認是否面對著下個要巡邏的位置,且不斷進行行走與判斷是否到達巡邏點的函數。


function Update () {
// 假使 走路狀態 為真
if (walk)
{
// 假使 面向巡邏點 為否
if (!isFaced)
{
// 執行 面向巡邏點 函數
FaceToPoint();
}
// 執行 行走 函數
Walking();
// 執行 確認移動位置與巡邏點距離 函數
CheckWalkPoint();
}
// 假使 待機狀態 為真
if (idle && inPoint)
{
// 執行 待機 函數
Idle();
}
}

 最主要的待機狀態,我們在一開始先將是否到達巡邏點的布林關閉,以免再次觸發待機函數,並等待一段時間,接著才關閉待機狀態,開啟下個行走狀態的布林。



function Idle()
{
print("Idle");
inPoint = false;
// 等待 待機時間
yield WaitForSeconds(idleTimes);
// 關閉 待機狀態
idle = false;
// 開啟 行走狀態
walk = true;
}

 接著就是行走前只執行一次的函數,先判斷目前要走向的巡邏點,如果為A,那麼下個巡邏點就改為B,反則類推。
並限制面向的軸向,以免讓角色軸向歪斜,並將面對方向以及到達巡邏點的狀態開啟與關閉。



function FaceToPoint()
{
switch (lookAtPoint)
{
case 1 :
lookAtPos = pointA.position;
lookAtTarget = pointA;
lookAtPoint = 2;
break;
case 2 :
lookAtPos = pointB.position;
lookAtTarget = pointB;
lookAtPoint = 1;
break;
default:
print("None");
}
lookAtPos.y = transform.position.y;
transform.LookAt(lookAtPos);
inPoint = false; // 尚未到達巡邏點
isFaced = true; // 已面向該方向。
}
接著是不斷執行的向前行走以及確認與目前巡邏點的距離,如果已到達就更改狀態布林,以便進入待機狀態。

因為是最後一段,就直接放上所有的程式碼。
在結構上,就請參考圖片。


#pragma strict
var pointA : Transform; // 巡邏點A
var pointB : Transform; // 巡邏點B
var lookAtTarget : Transform; // 目前巡邏
var lookAtPos: Vector3; // 目前巡邏點座標
var lookAtPoint :int = 1; // 預設巡邏點
var Gravity : float = 20.0; // 重力
var walkSpeed : float = 1.0; // 走路速度
var idleTimes : float = 3.0; // 待機時間

// ------- 狀態布林 ---------- // : 行走、待機、面對方向、到達巡邏點
var walk:boolean;
var idle:boolean;
var isFaced:boolean;
var inPoint:boolean;
private var MoveDirection : Vector3 = Vector3.zero;
function Start () {
idle = true;
inPoint = true;
}
function Update () {
// 假使 走路狀態 為真
if (walk)
{
// 假使 面向巡邏點 為否
if (!isFaced)
{
// 執行 面向巡邏點 函數
FaceToPoint();
}
// 執行 行走 函數
Walking();
// 執行 確認移動位置與巡邏點距離 函數
CheckWalkPoint();
}
// 假使 待機狀態 為真
if (idle && inPoint)
{
// 執行 待機 函數
Idle();
}
}
function Idle()
{
print("Idle");
inPoint = false;
// 等待 待機時間
yield WaitForSeconds(idleTimes);
// 關閉 待機狀態
idle = false;
// 開啟 行走狀態
walk = true;
}

function CheckWalkPoint()
{
// 宣告 dis 為 自身座標 與 移動巡邏點座標 距離
var dis : float=Vector3.Distance(transform.position, lookAtTarget.transform.position);
// 假使 距離小於等於0.1
if (dis <= 0.1)
{
// 開啟 到達巡邏點 狀態
inPoint =true;
// 關閉 面向巡邏點 狀態
isFaced = false;
// 關閉 行走 狀態
walk = false;
// 開啟 待機 狀態
idle = true;
}
}
function FaceToPoint()
{
switch (lookAtPoint)
{
case 1 :
lookAtPos = pointA.position;
lookAtTarget = pointA;
lookAtPoint = 2;
break;
case 2 :
lookAtPos = pointB.position;
lookAtTarget = pointB;
lookAtPoint = 1;
break;
default:
print("None");
}
lookAtPos.y = transform.position.y;
transform.LookAt(lookAtPos);
inPoint = false; // 尚未到達巡邏點
isFaced = true; // 已面向該方向。
}
function Walking ()
{
var forward : Vector3 = transform.TransformDirection(Vector3.forward);
Debug.DrawRay (transform.position, forward, Color.green);
var GameEnemy : CharacterController = GetComponent(CharacterController);
MoveDirection = forward;
MoveDirection.x *= walkSpeed;
//主角移動方向的Y軸數值,每秒持續減去重力值。
MoveDirection.y -= Gravity * Time.deltaTime;
//每秒持續移動主角。
GameEnemy.Move(MoveDirection * Time.deltaTime);
}





留言

這個網誌中的熱門文章

參加畢業展之設計類展場小心得

Unity 判斷兩物之間距離、角度,並注視目標

Action Game Maker 1.03 正體中文漢化版