?
本文基于Unity 5.3版本和C#語言,使用前請注意本文未必適用于其他的版本。 前言 我們知道在諸如Unity此類的游戲引擎中,游戲內(nèi)物體是已經(jīng)有現(xiàn)成的力與運動的物理模型的。我們可以調(diào)用相關(guān)的API來對物體施力(比如Unity的AddForce),獲取坐標(biāo)等。因此在引入萬有引力,磁場力等物體的相互作用時,只要了解力的結(jié)算公式和作用方式,即可通過在每幀用腳本進行力的結(jié)算和施加,來實現(xiàn)這些物理上的效果。 此外,作為一個游戲開發(fā)者,出于游戲需求經(jīng)常會被要求模擬一些其他領(lǐng)域的現(xiàn)象與原理。我們應(yīng)當(dāng)始終保持一種學(xué)習(xí)的心態(tài)來獲取其他領(lǐng)域的經(jīng)驗與知識,但也要記住我們的初衷-“在游戲中實現(xiàn)”。每當(dāng)我們遇到這樣的問題時,獲取知識的同時也要在大腦中思考,如何在你所用的引擎中實現(xiàn)這些效果,以及你要追求的是什么,是正確,還是效率。 追求正確需要以最貼合公式的方式進行結(jié)算,并且需要考慮到各類極限情況。在為信息安全,航空航天等精密領(lǐng)域開發(fā)軟件時,正確性無疑是非常關(guān)鍵的。 追求效率則是優(yōu)先保證資源分配效率的情況下,允許犧牲一部分正確性。這個效率既可以是指開發(fā)成本,比如一些游戲使用靜態(tài)模型動畫替代布娃娃系統(tǒng);也可以指運行效率,比如多數(shù)游戲物理所采用的牛頓力學(xué)而忽略相對論性效應(yīng)和量子力學(xué)效應(yīng);兩者都是的情況也有,比如WoW中投射物動畫與游戲邏輯的分離。這都是在資源有限情況下所側(cè)重的一種決策。 在游戲開發(fā)中,我們會經(jīng)常遇到這樣的抉擇。由于絕大多數(shù)游戲是為用戶打造的,我們更多時候會考慮實現(xiàn)效率。當(dāng)然也有諸如Kerbal Space Program這樣相對更加追求正確性的游戲存在,但畢竟是特例,是由游戲定位所決定的。 基本物理知識與思路 要實現(xiàn)磁體吸引與排斥的功能,先得補習(xí)一點物理知識。 “磁性是物質(zhì)響應(yīng)磁場作用的屬性。每一種物質(zhì)或多或少地會被磁場影響。鐵磁性是最強烈、最為人知的一種磁性。由于具有鐵磁性,磁石或磁鐵會產(chǎn)生磁場。另外,順磁性物質(zhì)會趨向于朝著磁場較強的區(qū)域移動,即被磁場吸引;反磁性物質(zhì)則會趨向于朝著磁場較弱的區(qū)域移動,即被磁場排斥;還有一些物質(zhì)會與磁場有更復(fù)雜的關(guān)系,例如,自旋玻璃的性質(zhì)、反鐵磁性等等。外磁場對于某些物質(zhì)的影響非常微弱。” “磁單極子 磁單極子是一種假想的粒子(或粒子類),這粒子只擁有一個磁極(指北極或指南極)。換句話說,類似帶電粒子的擁有電荷,磁單極子擁有磁荷。 現(xiàn)今,對于這概念的興趣大多出自于粒子物理學(xué),特別值得注意的是大統(tǒng)一理論和超弦理論,關(guān)于磁單極子的存在或可能性,它們做了很多預(yù)測,因而激發(fā)出許多物理學(xué)者尋找磁單極子的強烈興趣。但盡管竭盡全力,物理學(xué)者至今仍舊無法觀察到任何磁單極子的蛛絲馬跡.” “永久磁鐵的磁場 永久磁鐵的磁場比較復(fù)雜,特別是在磁鐵附近。一個微小條形磁鐵的磁場與其磁矩成正比,也會與磁鐵的定向有關(guān)。當(dāng)尺寸驅(qū)向無窮小極限時,磁鐵可以理想化成為磁偶極子,以方程表示,這微小條形磁鐵(磁偶極子)產(chǎn)生的磁場為 ?
有時候,磁鐵與磁鐵之間感受到的磁力和力矩,可以采用“磁極模型”來計算,磁極與磁極之間會互相吸引或互相排斥,就好像電荷與電荷之間的庫倫力。很可惜地,磁極模型不能正確地反映出磁鐵內(nèi)部的真實狀況(請參閱鐵磁性)。科學(xué)家尚未找到磁荷存在的實證。磁鐵的指北極與指南極無法被分離;任何分離動作會造成兩個子磁鐵,各自擁有自己的指北極與指南極。磁極模型無法解釋電流產(chǎn)生的磁場,也無法解釋移動于磁場中的電荷所感受到的洛倫茲力。 更正確地描述磁性,涉及了計算廣泛分布于磁鐵內(nèi)部的原子尺寸載流循環(huán)所產(chǎn)生的磁場。” 為什么我只關(guān)心這三項?因為作為一個物理苦手,哦不,游戲程序員(其實我是設(shè)計師啊設(shè)計師啊),我并不關(guān)心磁場強度是怎么計算的,也不關(guān)心磁單極子是否存在。就算把整個物理公式都照搬進來,有效率的在游戲中模擬也難度非常高,并不符合實際。 對于游戲需求而言,最常見的是順磁性,反磁性和鐵磁性。我這里只做鐵磁性(Magnetic)和順磁性(Paramagnetic),對應(yīng)磁鐵和被磁鐵吸引的物體。如果你想加反磁性,只需要修改順磁性的代碼,把力的方向反過來就能做到了。 我的思路就是,類似于磁極模型,把磁場力的相互作用全部簡化為磁單極之間的作用。在一定范圍內(nèi),這樣模擬出來的效果常人是很難分辨的。 事實上,我只關(guān)心這里出現(xiàn)在分母的r三次方項。這r^3告訴了我,磁場內(nèi)某一點的磁感應(yīng)強度和相對距離的3次方成反比。具體的常數(shù)可以根據(jù)游戲內(nèi)容和代碼相關(guān)進行微調(diào)。 場景準(zhǔn)備工作 首先,我們先給這個Unity的物理世界加入兩種新成員:順磁性物體(Paramagnetic),鐵磁性物體(Magnetic)。為它們制作帶有標(biāo)示性的標(biāo)簽。 ?
然后便是最簡單最容易想到的順磁性物體:硬幣 ?
請原諒我沒有添加金屬材質(zhì),這并不是重點。 這個硬幣最重要的就是Rigidbody和Tag了 ?
注意Continuous Dynamic可以防止因瞬時速度太快而導(dǎo)致的碰撞失效。 稀松平常的硬幣,由壓扁的圓柱體制成。加上Rigidbody和標(biāo)簽,這樣就算完工了。 做成Prefab吧。 接下來做一個磁鐵吧。 ?
注意我用的是紅色長方體(North Bar)加藍(lán)色長方體(South Bar)拼成的,為了區(qū)分N極與S極。 ?
不要忘記標(biāo)簽。 重點解釋一下磁鐵下的兩個Empty Object:North Pole & South Pole ?
這兩個抽象的點,便是鐵磁性物體的磁極。 這里用了物理學(xué)終極大法:簡化為質(zhì)點法,把所有磁性物體的相互作用都看作磁單極點的相互作用,一會的Script便可以用到它們(作為NP和SP)。 注意:一定要把磁極藏在物體里面,否則會導(dǎo)致外部物體和裸磁極接觸后果自負(fù)! 其實也沒那么嚴(yán)重,具體請參照下面腳本里,如果有像范例的腳本里一樣限制最小距離的話,也不用擔(dān)心和裸磁極接觸直接彈飛的問題。 這樣還沒完,還得做出“磁場”這個物體。 ?
根據(jù)需要來做,我這里用一個Capsule型的Trigger Collider代替了。 要避免bug的話,推薦大一點,要注重性能的話,推薦小一點。 注意勾上Trigger,這樣不會錯誤的被認(rèn)為是物體本身的碰撞體。 完成以后,做成Prefab。 ?
這里“磁場”的意義是,規(guī)定相互作用的最大范圍。 i.e. 任何超出這個范圍的物體均不在相互作用的考量范圍內(nèi),有點類似希爾球的概念。 這樣場景編輯器里的工作就暫時完成了,我們得到了兩個Prefab:硬幣,以及條形磁鐵。 腳本編寫 在準(zhǔn)備編寫的時候,先得理清楚思路。比如“我們現(xiàn)在有了什么,我們要腳本實現(xiàn)的是什么”。 我們已經(jīng)有了鐵磁性物體和順磁性物體的Prefab,鐵磁性物體也有了兩個磁單極點和磁場。 我們現(xiàn)在需要一個鐵磁性物體的腳本,來對磁場內(nèi)的物體施加作用力,即磁場力。 在磁場中的物體受到的磁場力應(yīng)該取決于如下幾個因素: ?
物體與磁鐵磁極的位移距離,的三次方,成反比(根據(jù)開頭的物理知識) 物體的“磁導(dǎo)率”。(物體對磁鐵越友好,受到磁力越大) 磁鐵的“磁場強度”。(磁鐵的強度越高,能施加的磁力越大) 作為上帝,哦不,游戲程序員所必需的,一個磁常數(shù)項,用于根據(jù)實際結(jié)果調(diào)整大小。
上述簡化做法來自生活經(jīng)驗,同物理學(xué)公式存在出入,請勿當(dāng)作物理學(xué)知識運用! 為此我們可以先做出一個吸引順磁性物體的腳本,然后進一步細(xì)化到鐵磁性物體的相互作用。 磁鐵腳本開頭聲明部分: 現(xiàn)在為條形磁鐵添加一個腳本吧(這個腳本也應(yīng)該適用于所有帶有鐵磁性的物體): ?
using UnityEngine; using System.Collections; public class MagneticField : MonoBehaviour { ? ?? ?? ?? ?public GameObject NP; ? ?? ?? ?? ?public GameObject SP; ? ?? ?? ?? ?private static float mu0 = 10.0f; ? ?? ?? ?? ?public float strength; ? ?? ?? ?? ?private Rigidbody rb; ? ?? ?? ?? ?// Use this for initialization ? ?? ?? ?? ?void Awake () { ? ?? ?? ?? ?? ?? ?? ?? ?rb = GetComponent<Rigidbody> (); ? ?? ?? ?? ?} } 復(fù)制代碼
NP:該磁鐵的N極。 SP:該磁鐵的S極。 mu0:磁常數(shù)項。 strength:該磁鐵的“磁場強度”。 rb:讀取并記錄該物體的rigidbody,便于后續(xù)頻繁的使用。 ?
回到場景編輯器中,將條形磁鐵附屬的兩個磁極分別拖拽連接到對應(yīng)的位置,并設(shè)定磁場強度。 磁鐵同磁場內(nèi)順磁性物體交互的部分: 我們之前設(shè)定了一個Trigger Collider作為磁場最大范圍,現(xiàn)在可以直接用OnTriggerStay來編寫每一幀的同磁場范圍內(nèi)的物體的相互作用。 這里我為了簡化操作避免給順磁性物體添加腳本,直接用質(zhì)量代替了物體的“磁導(dǎo)率”。如果你有實際應(yīng)用的需求,可以更改代碼里的相關(guān)項目,并為物體加上對應(yīng)的腳本和屬性來實現(xiàn)。 ?
??// Range of magnetic field ? ?? ?? ?? ?void OnTriggerStay (Collider other) { ? ?? ?? ?? ?? ?? ?? ?? ?Rigidbody other_rb = other.gameObject.GetComponent<Rigidbody> (); ? ?? ?? ?? ?? ?? ?? ?? ?// check the tag of object ? ?? ?? ?? ?? ?? ?? ?? ?if (other.gameObject.tag == "Paramagnetic") { ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 r_n = other.gameObject.transform.position - NP.transform.position; // displacement vector ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 r_s = other.gameObject.transform.position - SP.transform.position; // displacement vector ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?float mu = Time.fixedDeltaTime * strength * mu0 * other_rb.mass; ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?// Calculate Force towards magnetic poles ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 f_n = ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(r_n.normalized) * mu / ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(Mathf.Pow (Mathf.Max(r_n.magnitude, 0.2f), 3)); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 f_s = ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(r_s.normalized) * mu / ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(Mathf.Pow (Mathf.Max(r_s.magnitude, 0.2f), 3)); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?// 截圖中此處debug請無視 ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?// Apply attracting force to other object ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_rb.AddForce ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?-1f * f_n); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_rb.AddForce ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?-1f * f_s); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?// Apply attracting force to magnetic object ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?rb.AddForceAtPosition ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?1f * f_n, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?NP.transform.position); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?rb.AddForceAtPosition ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?1f * f_s, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?SP.transform.position); ? ?? ?? ?? ?? ?? ?? ?? ?} ? ?? ?? ?? ?} 復(fù)制代碼
other_rb:同該磁鐵相互作用的目標(biāo)物體的rigidbody。 r_n:從北磁極到目標(biāo)物體的矢量位移。 r_s:從南磁極到目標(biāo)物體的矢量位移。 mu:由每幀間隔時間,磁鐵的磁場強度,目標(biāo)物體的磁導(dǎo)率(在這里用了質(zhì)量)以及磁常數(shù)共同決定的一個公式系數(shù)。 f_n:北磁極對物體施加的矢量力。 f_s:南磁極對物體施加的矢量力。 磁場力的大小最終為mu值除以距離的三次方。力的方向自然是位移的方向。 我這里限定了位移距離的標(biāo)量大小不小于一個特定值(如0.2),否則分母在接近0的時候會出現(xiàn)磁力過大彈飛物體的問題。電腦物理引擎每幀間隔都相對比較長,因此要考慮到這點。 此外要注意我不只為被吸引的物體加了吸引力,還為磁鐵的磁極加了一個相反方向的力。 這是因為: “牛頓第三運動定律” “To every action there is always opposed an equal reaction: or the mutual actions of two bodies upon each other are always equal, and directed to contrary parts.” “每一個作用力都對應(yīng)著一個相等反抗的反作用力:也就是說,兩個物體彼此施加于對方的力總是大小相等、方向相反。” 有了這個腳本,目前場景內(nèi)的磁鐵應(yīng)該已經(jīng)可以吸引硬幣了。 你可以加一點簡單的控制腳本來幫助測試, 手機游戲拍賣平臺 并且調(diào)整對應(yīng)的常數(shù)值來觀察物體相互作用的變化,以達(dá)到你自己的預(yù)期要求。 磁鐵同磁場內(nèi)其他磁鐵交互的部分: 上一步的腳本只做了針對帶有“Paramagnetic”標(biāo)簽的物體的相互作用,現(xiàn)在我們來做對于“Magnetic”的物體,也就是其他磁鐵,的相互作用。把之前的if 部分改到下列代碼的else if部分即可。
??if (other.gameObject.tag == "Magnetic") { ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?MagneticField other_script = other.gameObject.GetComponent<MagneticField> (); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?GameObject other_NP = other_script.NP; ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?GameObject other_SP = other_script.SP; ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???Vector3 r_n_n = other_NP.transform.position - NP.transform.position; // from this(N) to that(N) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 r_s_s = other_SP.transform.position - SP.transform.position; // from this(S) to that(S) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???Vector3 r_n_s = other_SP.transform.position - NP.transform.position; // from this(N) to that(S) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???Vector3 r_s_n = other_NP.transform.position - SP.transform.position; // from this(S) to that(N) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?float other_strength = other_script.strength; ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?// Calculate Force towards magnetic poles ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?float mu = Time.fixedDeltaTime * strength * other_strength; ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 f_n_n = // from this(N) to that(N) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(r_n_n.normalized) * mu / ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(Mathf.Pow (Mathf.Max(r_n_n.magnitude, 0.2f), 3)); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 f_s_s = // from this(S) to that(S) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(r_s_s.normalized) * mu / ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(Mathf.Pow (Mathf.Max(r_s_s.magnitude, 0.2f), 3)); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 f_n_s = // from this(N) to that(S) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(r_n_s.normalized) * mu / ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(Mathf.Pow (Mathf.Max(r_n_s.magnitude, 0.2f), 3)); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 f_s_n = // from this(S) to that(N) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(r_s_n.normalized) * mu / ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(Mathf.Pow (Mathf.Max(r_s_n.magnitude, 0.2f), 3)); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?//截圖中此處的Debug請無視 ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?// Apply Rejecting Force ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_rb.AddForceAtPosition ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?1f * f_n_n, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_NP.transform.position); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_rb.AddForceAtPosition ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?1f * f_s_s, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_SP.transform.position); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??? ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?// Apply Attracting Force ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_rb.AddForceAtPosition ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?-1f * f_n_s, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_SP.transform.position); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_rb.AddForceAtPosition ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?-1f * f_s_n, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_NP.transform.position); ? ?? ?? ?? ?? ?? ?? ?? ?} 復(fù)制代碼
相比順磁性的物體來說,兩個鐵磁性物體的交互則稍許多了點變量和運算量。 other_rb:同該磁鐵相互作用的目標(biāo)磁鐵的rigidbody。 other_script:目標(biāo)磁鐵下屬的這個腳本。用于獲取該物體同腳本連接的public變量。 r_n_n:從本磁鐵北磁極到目標(biāo)磁鐵北磁極的矢量位移。 r_s_s:從本磁鐵南磁極到目標(biāo)磁鐵南磁極的矢量位移。 r_n_s:從本磁鐵北磁極到目標(biāo)磁鐵南磁極的矢量位移。 r_s_n:從本磁鐵南磁極到目標(biāo)磁鐵北磁極的矢量位移。 mu:由每幀間隔時間,磁鐵的磁場強度,目標(biāo)磁鐵的磁場強度以及磁常數(shù)共同決定的一個公式系數(shù)。 f_n_n:本磁鐵北磁極對目標(biāo)磁鐵北磁極施加的矢量力。 f_s_s:本磁鐵南磁極對目標(biāo)磁鐵南磁極施加的矢量力。 f_n_s:本磁鐵北磁極對目標(biāo)磁鐵南磁極施加的矢量力。 f_s_n:本磁鐵南磁極對目標(biāo)磁鐵北磁極施加的矢量力。 這里磁場力的計算同上一部分異曲同工。 此外,還要注意因為磁鐵(是直的,)存在“同性相斥,異性相吸”的規(guī)律。同名磁極之間的力應(yīng)當(dāng)是排斥力。 為什么我這里沒有向之前一樣施加反作用力? 因為同該磁鐵相互作用的另一磁鐵也有這個腳本!也會執(zhí)行同樣的效果! 而且由于計算公式符合交換律,計算出的結(jié)果應(yīng)當(dāng)是一樣的。 我這里默認(rèn)物體的磁場范圍都足夠大。如果你有特殊需求,或者說你的磁場范圍不得不做的很小,那么請考慮到一個情況:B磁鐵進了A磁鐵的磁場范圍,而A磁鐵沒有進入B磁鐵的磁場范圍。這可能會導(dǎo)致潛在的bug。 如果你的磁場范圍都足夠大,磁場邊緣的相互作用已經(jīng)可以忽略不計了,那么就放心的省了反作用力吧。 這個問題,符合和我開頭所說的抉擇,即追求正確還是效率。 這樣以后就大工告成了。 完整代碼: ?
using UnityEngine; using System.Collections; public class MagneticField : MonoBehaviour { ? ?? ?? ?? ?public GameObject NP; ? ?? ?? ?? ?public GameObject SP; ? ?? ?? ?? ?private static float mu0 = 10.0f; ? ?? ?? ?? ?public float strength; ? ?? ?? ?? ?private Rigidbody rb; ? ?? ?? ?? ?// Use this for initialization ? ?? ?? ?? ?void Awake () { ? ?? ?? ?? ?? ?? ?? ?? ?rb = GetComponent<Rigidbody> (); ? ?? ?? ?? ?} ? ?? ?? ?? ?// Update is called once per frame ? ?? ?? ?? ?void FixedUpdate () { ? ?? ?? ??? ? ?? ?? ?? ?} ? ?? ?? ?? ?// Range of magnetic field ? ?? ?? ?? ?void OnTriggerStay (Collider other) { ? ?? ?? ?? ?? ?? ?? ?? ?Rigidbody other_rb = other.gameObject.GetComponent<Rigidbody> (); ? ?? ?? ?? ?? ?? ?? ?? ?if (other.gameObject.tag == "Magnetic") { ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?MagneticField other_script = other.gameObject.GetComponent<MagneticField> (); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?GameObject other_NP = other_script.NP; ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?GameObject other_SP = other_script.SP; ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???Vector3 r_n_n = other_NP.transform.position - NP.transform.position; // from this(N) to that(N) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 r_s_s = other_SP.transform.position - SP.transform.position; // from this(S) to that(S) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???Vector3 r_n_s = other_SP.transform.position - NP.transform.position; // from this(N) to that(S) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???Vector3 r_s_n = other_NP.transform.position - SP.transform.position; // from this(S) to that(N) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?float other_strength = other_script.strength; ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?// Calculate Force towards magnetic poles ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?float mu = Time.fixedDeltaTime * strength * other_strength; ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 f_n_n = // from this(N) to that(N) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(r_n_n.normalized) * mu / ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(Mathf.Pow (Mathf.Max(r_n_n.magnitude, 0.2f), 3)); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 f_s_s = // from this(S) to that(S) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(r_s_s.normalized) * mu / ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(Mathf.Pow (Mathf.Max(r_s_s.magnitude, 0.2f), 3)); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 f_n_s = // from this(N) to that(S) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(r_n_s.normalized) * mu / ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(Mathf.Pow (Mathf.Max(r_n_s.magnitude, 0.2f), 3)); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 f_s_n = // from this(S) to that(N) ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(r_s_n.normalized) * mu / ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(Mathf.Pow (Mathf.Max(r_s_n.magnitude, 0.2f), 3)); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?//Debug.Log ( f_n_n.magnitude + ", " + f_n_n.magnitude); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?// Apply Rejecting Force ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_rb.AddForceAtPosition ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?1f * f_n_n, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_NP.transform.position); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_rb.AddForceAtPosition ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?1f * f_s_s, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_SP.transform.position); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??? ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?// Apply Attracting Force ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_rb.AddForceAtPosition ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?-1f * f_n_s, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_SP.transform.position); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_rb.AddForceAtPosition ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?-1f * f_s_n, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_NP.transform.position); ? ?? ?? ?? ?? ?? ?? ?? ?} ? ?? ?? ?? ?? ?? ?? ?? ?else if (other.gameObject.tag == "Paramagnetic") { ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 r_n = other.gameObject.transform.position - NP.transform.position; // displacement vector ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 r_s = other.gameObject.transform.position - SP.transform.position; // displacement vector ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?float mu = Time.fixedDeltaTime * strength * mu0 * other_rb.mass; ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?// Calculate Force towards magnetic poles ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 f_n = ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(r_n.normalized) * mu / ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(Mathf.Pow (Mathf.Max(r_n.magnitude, 0.2f), 3)); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Vector3 f_s = ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(r_s.normalized) * mu / ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(Mathf.Pow (Mathf.Max(r_s.magnitude, 0.2f), 3)); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?//Debug.Log ( nf.magnitude + ", " + sf.magnitude); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?// Apply attracting force to other object ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_rb.AddForce ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?-1f * f_n); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?other_rb.AddForce ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?-1f * f_s); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?// Apply attracting force to magnetic object ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?rb.AddForceAtPosition ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?1f * f_n, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?NP.transform.position); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?rb.AddForceAtPosition ( ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?1f * f_s, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?SP.transform.position); ? ?? ?? ?? ?? ?? ?? ?? ?} ? ?? ?? ?? ?} } 復(fù)制代碼
再加點控制功能就可以進場景測試了。 實例體驗 ?
硬幣,條形磁鐵。 ?
接近中 ?
成功吸附! ?
多丟點硬幣下來。不要吐槽硬板的陰影效果和藥片似的硬幣材質(zhì)。。。 ?
?
進去掃一圈。效果還不錯。 ?
多放點硬幣,老mac電腦還算剛的住,掉幀不明顯。 這里還是有瑕疵的,按理說被磁鐵吸引的物體自己也會被暫時磁化,所以在這里應(yīng)該是硬幣吸硬幣吸起一串來。(有興趣的同學(xué)可以自己嘗試實現(xiàn),一個思路是把順磁性物體做成兩個磁極重合的磁化強度較低的鐵磁性物體,然后根據(jù)受磁化率提升自身的磁場強度。) ?
清空,再丟個條形磁鐵下來。 ?
?
從左側(cè)平行接近目標(biāo)。 ?
十動然拒了。。 ?
從上方靠近 ?
合體! ?
再來丟下來點磁鐵。 測試項目的瀏覽器在線試玩(不支持Chrome,需下載Unity Web Player): Magnet Simulation Test (海外網(wǎng)站) 操作: 上下左右:通過一個特定數(shù)值的力移動磁鐵。(磁鐵互相吸引后由于用于移動的力還是恒定值,因此會越來越難移動) A/Z:抬起/下壓磁鐵。 空格:天上隨機掉下一個硬幣。 B:天上隨機掉下一個條形磁鐵。 這個項目只是用來測試上述的磁場相互作用腳本的,基本已經(jīng)和現(xiàn)實生活很接近了。 該腳本也基本適用于其他形狀不太正常的磁鐵,使用時最主要的還是兩個磁極的位置以及強度的設(shè)定。公式是死的,人是活的,請結(jié)合實際情況使用和修改。
總結(jié)
以上是生活随笔 為你收集整理的游戏物体的力与运动:用unity实现磁体相互吸引和排斥的效果 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。