前言
但凡是涉及到怪物AI邏輯這一部分,無非是 索敵—>尋路—>戰(zhàn)斗嘛,這次是說索敵這一塊
簡單粗暴點的話,當(dāng)玩家離怪物一定的距離就令怪物走向玩家就好了,但這顯得有點蠢
我們希望怪物有一個先發(fā)現(xiàn)玩家、再進行后續(xù)動作的過程,這樣顯得更真實,也可以為其他一些功能做準(zhǔn)備(比如我們的玩家可以偷偷繞到怪物背后,給他一錘子)
為了更真實地去做到“怪物發(fā)現(xiàn)入侵者”這一功能,我們可以換位思考一下,我們是如何發(fā)現(xiàn)怪物的?——怪物進入了我們攝像機的視錐體,嗯,所以怪物也該有一個視野范圍,當(dāng)我們進入它的視野范圍時,它才會“看見”我們
所以我采用了以下思路:
一、用扇形區(qū)域模擬怪物的視野范圍
首先,設(shè)定最大可視距離maxVisionDistance和最大視野角度maxVisionAngle
當(dāng)玩家與怪物的 距離<maxVisionDistance, 角度<maxVisionAngle,那么玩家進入怪物的視野范圍
public float maxVisionDistance;//視野長度
public float maxVisionAngle;//視野角度
bool isInMyVision(Collider c)
{
GameObject target = c.gameObject;
//計算與目標(biāo)距離
float distance = Vector3.Distance(transform.position, target.transform.position);
Vector3 mVec = transform.rotation * Vector3.forward ;//當(dāng)前朝向
Vector3 tVec = target.transform.position - transform.position;//與目標(biāo)連線的向量
//計算兩個向量間的夾角
float angle = Mathf.Acos(Vector3.Dot(mVec.normalized, tVec.normalized)) * Mathf.Rad2Deg;
if (distance < maxVisionDistance)
{
if (angle <= maxVisionAngle)
{
if(canSee(c))
return true;
}
}
return false;
}
二、排除遮擋
如果我們的玩家想要不驚動怪物,暗中觀察,或許會躲在一塊石頭后面。
直接用上述判斷距離和角度的方法顯然是不行的,我們需要追加一個判斷是否有障礙物遮擋視野,這里我想的辦法是用射線來解決。
從當(dāng)前點向目標(biāo)位置發(fā)射一條射線Ray,如果碰撞到的第一個物體是目標(biāo)物體,就判定沒有遮擋,這樣的話,最好將這個腳本綁定到怪物的“眼睛”這個地方,讓它有一定的高度。
我這里只是大致判斷了一下,當(dāng)然可以有更精確的判斷方式,請各位發(fā)揮想象力
bool canSee(Collider c)
{
Ray DetectRay = new Ray(transform.position,temVec.normalized*maxVisionDistance);
RaycastHit hitInfo;
if (Physics.Raycast(DetectRay, out hitInfo, maxVisionDistance))
{
if (hitInfo.collider == c)
{
return true;
}
}
}
三、擴展思考
在多人游戲中,可能有多個玩家,這個時候,只設(shè)定一個 target是不夠的
我們可以先將視野中的可能目標(biāo)先找出來,再進行排除和選擇,用一個簡單的球形掃描Physics.OverlapSphere就可以找出所有目標(biāo)了,可以設(shè)定個tag或者layer來進行選擇
void FindTarget()
{
Collider[] AllObejects = Physics.OverlapSphere(transform.position, maxVisionDistance);
foreach( Collider c in AllObejects)
{
//僅對Player進行檢測
if (c.gameObject.tag == "Player")
{
if (isInMyVision(c))
{
print("I see a target");
//在這里執(zhí)行你想要進行的操作,比如設(shè)定尋路目標(biāo)之類的
}
}
}
}
如有建議或指正,歡迎交流。