Unity小白: 簡(jiǎn)單地 做傷害判定(重投原創(chuàng))
為了實(shí)現(xiàn)自己想要的功能而在網(wǎng)上找七找八,有時(shí)毫無(wú)頭緒,只能無(wú)能狂怒。

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

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

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

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

在update中設(shè)置子彈的運(yùn)動(dòng)

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

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

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

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

然后添加如此代碼


注,這樣子?生成的gizmos物體除編輯窗口外是看不見的哦!
(作者自鞭,這應(yīng)該是受到了新建圖層的影響)
然后別看了!寫你的代碼去吧!