Unity 簡單地 做傷害判定(已修正)

為了實現(xiàn)自己想要的功能而在網(wǎng)上找七找八,有時毫無頭緒,只能無能狂怒。

轉(zhuǎn)入主題:如何使用unity做傷害判定?
做傷害判定有許多種方式,如Trigger、剛體碰撞、RayCast等,不過這次我們要運用BoxCastAll。
BoxCastAll的原理很 簡 單 :在指定坐標(biāo)發(fā)射一條射線,射線末端是一個方形的檢測區(qū)域的中心,然后返回射線與檢測區(qū)域的所有檢測信息。?其API如下:

注:檢測區(qū)域的大小是2倍的輸入值,示意圖如下

了解了這些,我們就可以開始了。
打開你的unity。
新建兩腳本,分別取名為RoleHP、Projectile:

給Projectile添加變量:
? ? public Transform 子彈根;? ??
? ? //在子彈執(zhí)行隔幀檢測修補時,檢測將以上一幀投射部坐標(biāo)即lastPos為起點,終于當(dāng)前子彈頭部坐標(biāo)
? ? public Transform 子彈頭部;
? ? public Transform 投射部;
? ? public float 速度;
? ? public float 下墜;
? ? //BoxCastAll檢測盒體的大小
? ? public Vector3 檢測范圍;
? ? public LayerMask 檢測層級;
? ? public float 距離;
? ? List<RoleHP> HitHP;
? ? Collider HitObj;
? ? float correct;
? ? public bool Gizmo;
? ? Transform gizmoObj;
? ? Quaternion quat;
? ? Vector3 lookAt, speed, lastPos,castArea,投射原點;

在update中設(shè)置子彈的運動

注:此處的Time.deltaTime解釋為 增量時間,其數(shù)值為 1/當(dāng)前的每秒幀數(shù);假設(shè)游戲運行時,1秒是N幀,也就是播放了60個畫面,執(zhí)行完,耗時1秒。
x米=(增量時間 * 1秒總幀數(shù))秒 *10米/秒
這樣無論幀率是多是少,設(shè)置物體1秒移動幾米,子彈每秒移動的距離就是幾米
若不按照以上的方式進(jìn)行移動,那么在幀率不同的時候,物體移動的速度可能也會隨之變化
既然有幀率,那么物體的移動就是有 間隔 的:

因此,如果物體的移動速度過快,則會出現(xiàn)檢測不到子彈正常軌道上的物體的情況;同理,有時候游戲中角色移動過快就會出現(xiàn)無視碰撞地穿墻。
新增?糾正檢測?函數(shù),然后在移動代碼的后方進(jìn)行引用:
? ? private void 糾正檢測()
? ? {
? ? ? ? castArea = 檢測范圍;
? ? ? ? correct = Vector3.Distance(子彈頭部.position, lastPos);
? ? ? ? lookAt = Vector3.Normalize(子彈頭部.position - lastPos);
? ? ? ? if (correct > 檢測范圍.z)
? ? ? ? {? //進(jìn)行補幀檢測
? ? ? ? ? ? 投射原點 = lastPos;
? ? ? ? ? ? castArea.z = correct;
? ? ? ? }
? ? ? ? else
? ? ? ? {? //保持原檢測范圍不變
? ? ? ? ? ? 投射原點 = 投射部.position;
? ? ? ? ? ? castArea.z = 檢測范圍.z;
? ? ? ? }
? ? }

?
繼續(xù)在Update里添加 檢測 的代碼:
? ? ? ? ? ? quat = Quaternion.LookRotation(lookAt);
? ? ? ? ? ? quat.eulerAngles =new Vector3(quat.eulerAngles.x,quat.eulerAngles.y,子彈根.rotation.eulerAngles.z) ;
? ? ? ? ? ? Hits = Physics.BoxCastAll(投射原點, castArea / 2, lookAt, quat, castArea.z / 2, 檢測層級);
? ? ? ? ? ? foreach (var hit in Hits)
? ? ? ? ? ? {? ? ? ? ?? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??判斷攻擊的邏輯靠你們自己寫了...............
? ? ? ? ? ? }

代碼原理如下:
接著:執(zhí)行運動代碼,子彈正式開始移動,然后子彈的位置開始變化。此時,update的代碼就運轉(zhuǎn)到?糾正檢測函數(shù)。雖然子彈的位置產(chǎn)生變化,變量lastPos記錄的還是子彈 上 一 幀 的位置,以此就可以“獲取上一幀位置”。用vector3.distance獲取當(dāng)前幀與上一幀的距離
(此處“l(fā)ookAt”=子彈頭部.position - lastPos 是為了? ?獲 取? lastPos朝向子彈頭部.position的方向)。
代碼運轉(zhuǎn)到了BoxCastAll部分,檢測投射從lastPos中發(fā)出,射線距離等于檢測范圍的z軸(這樣做的原因是為了讓方盒檢測范圍充當(dāng)主要檢測部分,射線暫時不需要),從“上一幀坐標(biāo)”朝向當(dāng)前坐標(biāo)。這里填寫的“quat”是一個quaternion(四元數(shù)),用來調(diào)整檢測盒體的旋轉(zhuǎn)方向(重頭戲):
BoxCastAll的旋轉(zhuǎn)是需代碼更改的,它不會無端端受任何物體的影響。
理想狀態(tài)下,方盒的起始點是lastPos,終點是投射部.position。因此其quat =?LookRotation(lookAt)? ? ? ?.............這就完了嗎?
不,如果你想要檢測再精密一點,這個盒體的z軸就要與子彈根的z軸一致。因此子彈在圍繞Z軸旋轉(zhuǎn)時,檢測盒體也會跟著旋轉(zhuǎn)?
代碼為??quat.eulerAngles = new Vector3(quat.eulerAngles.x, quat.eulerAngles.y, 子彈根.rotation.eulerAngles.z);
然后檢測到的物體只能是指定層級且?guī)в信鲎搀w組件的。
待獲取檢測信息后,foreach?(var hit in Hits)會從所有檢測到的物體中遍歷每個檢測到的物體。若有物體滿足條件:?該物體沒有在?List數(shù)組“所有擊中物”之內(nèi),且包含腳本“HP”。則該物體可以被賦予傷害,然后調(diào)用其腳本“HP”上的傷害函數(shù)。然后添加該物體至 List數(shù)組“所有擊中物”之內(nèi)。最后就用lastPos = transform.position;?來更新“上一幀位置”,以便下一幀update的繼續(xù)調(diào)用。
//忘記加子彈延時銷毀了,請大家需要的自行加上。
如果你還是聽不懂我的十級鬼語的,那么就讓可視化的Gizmos來告訴你吧!
(使用時要保證子彈根即其以上的父物體的scale值為1,1,1哦!?不然Gizmos會有誤差的?。?/strong>
在Resources文件夾(無則新建)下新建一個預(yù)制體名為Gizmos。
給Gizmos添加一個子物體方盒,其z軸前進(jìn)0.5個單位

然后添加如此代碼


注,這樣子?生成的gizmos物體除編輯窗口外是看不見的哦!
然后別看了!寫你的代碼去吧!