Unity——#19 舉盾


??在RPG類游戲中东且,除了有攻擊,也有和攻擊同等重要的動(dòng)作漠酿,那就是防御分冈。本節(jié)將討論如何實(shí)現(xiàn)防御基显。不過(guò)在有了實(shí)現(xiàn)攻擊的先例經(jīng)驗(yàn)椭员,我想實(shí)現(xiàn)防御的難度已經(jīng)降低了雨涛。
??先著手把動(dòng)畫機(jī)(Animator)里的動(dòng)畫準(zhǔn)備好:添加防御動(dòng)畫衍菱,采取與攻擊動(dòng)畫同樣的命名方式赶么,命名為defense1h;添加閑置(idle)動(dòng)畫鏈接Entry脊串;新增動(dòng)畫機(jī)bool型參數(shù)(Prameters)辫呻,命名為defense清钥;兩個(gè)動(dòng)畫間互拉Transition,都消勾Has Exit Time 放闺,添加觸發(fā)條件(Conditions)為defense參數(shù)祟昭,其中idle→defense1h的defense為true,defense1h→idle的defense為false雄人。

??現(xiàn)在我打算為這個(gè)模型添加一塊盾牌和木棍从橘,說(shuō)是這么說(shuō),其實(shí)添加Cube做盾牌础钠。Cylinder做木棍恰力。為此我們需要找到這個(gè)模型的右手手掌,和左手肘關(guān)節(jié)處旗吁。在模型的右手底下新增empty改名為WeaponHandle踩萎,再在WeaponHandle底下新增一3D Oeject Cylinder命名為sword:

??然后調(diào)整Cylinder的大小和旋轉(zhuǎn)角和WeaponHandle的位置,使其剛好在模型右手手掌的虎口處很钓,這樣角色在握拳時(shí)能剛好握住Cylinder而不穿模:

??現(xiàn)在來(lái)看看揮起來(lái)順不順手:

??看起來(lái)Ok∠愀現(xiàn)在來(lái)添加一塊盾牌,同樣找到左手肘關(guān)節(jié)處码倦,在其底下創(chuàng)建empty企孩,命名為WeaponHandle,再在WeaponHandle底下新增一3D Oeject Cube袁稽,命名為Shield:

??為什么不找左手(LeftHand)勿璃,手背放盾牌不是更好嗎?因?yàn)槲覀兊亩喂魟?dòng)畫有一個(gè)左手往外拐的動(dòng)作:

??如果戴上盾牌后推汽,有可能會(huì)造成穿模(手掌穿出盾牌)补疑,所以打算把盾牌放在肘關(guān)節(jié)以下的位置,通過(guò)偏斜一點(diǎn)盾牌的角度來(lái)避免這個(gè)問(wèn)題歹撒。
??通過(guò)調(diào)整WeaHandle的位置和shield的大小莲组,使其掌心不穿出Cube:

??現(xiàn)在來(lái)看看效果如何:

??因?yàn)殚e置動(dòng)畫的左手就是擺在胸前,導(dǎo)致其放上盾牌后有點(diǎn)變成像防御狀態(tài)的樣子暖夭。但是這并不是我想要的锹杈,不能讓玩家產(chǎn)生閑置狀態(tài)能擋住敵人攻擊的誤解。所以我們要改變?cè)陂e置動(dòng)畫下左手手臂的位置鳞尔。但是這個(gè)動(dòng)畫是是別人做好的嬉橙,我不會(huì)改啊,怎么辦寥假?不怕市框,Unity提供能用代碼改變動(dòng)畫中人物關(guān)節(jié)位置的方法,那就是OnAnimatorIK()糕韧,這個(gè)函數(shù)有點(diǎn)像我們之前用過(guò)的OnAnimatorMove()枫振,前者是改變動(dòng)畫關(guān)節(jié)位置喻圃,后者處理動(dòng)畫的位移量。我們可以看看它的Signature和官方描述MonoBehaviour.OnAnimatorIK(int)

Parameters Means
layerIndex The index of the layer on which the IK solver is called.

Description
Callback for setting up animation IK (inverse kinematics).

OnAnimatorIK() is called by the Animator Component immediately before it updates its internal IK system. This callback can be used to set the positions of the IK goals and their respective weights.

??在解釋這個(gè)函數(shù)之前粪滤,我想先簡(jiǎn)單討論一下何為IK斧拍。IK,即Inverse kinematics杖小,反向動(dòng)力學(xué)肆汹。引用一處IK學(xué)習(xí)筆記中關(guān)于反向動(dòng)力學(xué)的解釋:

??反向動(dòng)力學(xué)與前向動(dòng)力學(xué)相反,先給出骨骼點(diǎn)的位置予权,然后要求出運(yùn)動(dòng)骨骼以什么樣的位移昂勉、旋轉(zhuǎn)、縮放可以使得骨骼點(diǎn)到達(dá)指定的位置扫腺。
??用加法來(lái)做比喻的話岗照,前向動(dòng)力學(xué)是已知算式1+1+3,求結(jié)果;反向動(dòng)力學(xué)是已知結(jié)果5笆环,求算式攒至。可以看出躁劣,反向動(dòng)力學(xué)計(jì)算得到的結(jié)果往往不是的迫吐,因此比前向動(dòng)力學(xué)要復(fù)雜許多。

??能看出其實(shí)IK是一門非常復(fù)雜的學(xué)科账忘,如果日后有機(jī)會(huì)必定深入學(xué)習(xí)渠抹。但今天我們僅僅是簡(jiǎn)單地使用一下OnAnimatorIK(),不做深入討論闪萄。
??回到OnAnimatorIK()上,這個(gè)函數(shù)會(huì)在動(dòng)畫組件更新它內(nèi)部的IK系統(tǒng)前被調(diào)用奇颠。用途是能夠用來(lái)設(shè)置IK目標(biāo)的位置和它們各自的權(quán)重败去。說(shuō)白了就是這個(gè)函數(shù)能在IK更新前,對(duì)動(dòng)畫的IK做最后的調(diào)整烈拒,這個(gè)調(diào)整就是對(duì)骨骼點(diǎn)的運(yùn)動(dòng)做位移圆裕、旋轉(zhuǎn)和縮放。那么究竟怎么做調(diào)整荆几,那就要用到另外的API了吓妆。
??我們想要的是把閑置動(dòng)畫里抬起來(lái)的左手給放到左大腿邊上,所以要對(duì)骨骼點(diǎn)進(jìn)行旋轉(zhuǎn)吨铸,這要用到兩個(gè)函數(shù):Animator.GetBoneTransform()Animator.SetBoneLocalRotation行拢,接下來(lái)對(duì)這兩個(gè)函數(shù)分別做出解釋:
public Transform GetBoneTransform(HumanBodyBones humanBoneId)

Parameters Means
humanBoneId The human bone that is queried, see enum HumanBodyBones for a list of possible values.

Description

Returns Transform mapped to this human bone id.

??如果想對(duì)某個(gè)骨骼點(diǎn)進(jìn)行一些操作,那就先獲得這個(gè)骨骼點(diǎn)的位置诞吱;要想獲得這個(gè)骨骼點(diǎn)的位置舟奠,就要用這個(gè)骨骼點(diǎn)對(duì)應(yīng)的枚舉值(enum)去查詢(queried)竭缝。等會(huì)用到這個(gè)函數(shù)時(shí)我們就知道怎么查詢左下臂。
public void SetBoneLocalRotation(HumanBodyBones humanBoneId, Quaternion rotation)

Parameters Means
humanBoneId The human bone Id.
rotation The local rotation.

Description
Sets local rotation of a human bone during a IK pass.

Can be used to create rotation IK goals for any human bone. Ex: Control lower and upper body independantly by setting Hips and Spine local rotation during an IK pass.

??這個(gè)函數(shù)就是對(duì)某指定的骨骼點(diǎn)進(jìn)行旋轉(zhuǎn)沼瘫。不難理解抬纸。描述給的例子是通過(guò)髖部和脊柱(Hips and Spine)的局部旋轉(zhuǎn)來(lái)獨(dú)立控制上下身體。

??我再重申一下我的需求:把閑置動(dòng)畫里抬起來(lái)的左手給放到左大腿邊上耿戚,但是在舉盾(進(jìn)入defense1h動(dòng)畫)時(shí)湿故,要取消這個(gè)修改不然這個(gè)舉盾動(dòng)畫也會(huì)被一并改掉。
??在準(zhǔn)備Add Component前膜蛔,需注意的是要想這個(gè)OnAnimatorIK()生效坛猪,第一個(gè)要做的就是在defense Layer層級(jí)上把IK Pass上勾上,宣告我這個(gè)OnAnimatorIK()是作用于此Layer的飞几,在之前實(shí)現(xiàn)一段攻擊時(shí)也有提到過(guò)這個(gè)砚哆。


??第二個(gè)就是把你寫的這個(gè)函數(shù)放在有Animator組件的對(duì)象的兄弟層級(jí)上,這里我就在Ybot上直接Add Component屑墨,命名為L(zhǎng)eftArmAnimFix:

??把其中的Start()Update()函數(shù)給砍了躁锁,這里用不上。然后宣告一個(gè)Animator對(duì)象卵史,在Awake()獲得Ybot上的Animator組件:

    private Animator anim;

    void Awake(){
        anim = GetComponent<Animator> ();
    }

??然后實(shí)現(xiàn)OnAnimatorIK()函數(shù)战转,思路是先在里面獲得左前臂的位置,然后宣告一個(gè)Vector3變量以躯,把它曝露出去槐秧,方便我們對(duì)其作出修改(在改到合適位置后在把它寫死),然后再把這個(gè)Vector3變量轉(zhuǎn)換為四元數(shù)喂給Animator.SetBoneLocalRotation()忧设。

public class LeftArmAnimFix : MonoBehaviour {
    private Animator anim;

    public Vector3 tempLocalRotation;

    void Awake(){
        anim = GetComponent<Animator> ();
    }

    void OnAnimatorIK()
    {
        if (anim.GetBool("defense") == false) {
            Transform leftArm = anim.GetBoneTransform (HumanBodyBones.LeftLowerArm);
            leftArm.localEulerAngles = tempLocalRotation;
            anim.SetBoneLocalRotation (HumanBodyBones.LeftLowerArm, Quaternion.Euler (leftArm.localEulerAngles));   
        }
    }
}

??這個(gè)HumanBodyBones的枚舉值有很多刁标,我們要的是左前臂,所以是LeftLowerArm:


??由于我們?cè)O(shè)置的歐拉角址晕,所以要把它轉(zhuǎn)換為四元數(shù)(函數(shù)要求)膀懈,轉(zhuǎn)換的方法就是Quaternion.Euler()。現(xiàn)在我們就可在外部調(diào)整我們的手臂了谨垃,記住先在Play mode下調(diào)整好启搂,然后Copy Component ,取消Play mode刘陶,再Paste Component Values胳赌。這是調(diào)好的角度,已經(jīng)基本實(shí)現(xiàn)了我的需求:

??Last but not least, 實(shí)現(xiàn)舉盾動(dòng)作匙隔。這里我只給出手柄的實(shí)現(xiàn)疑苫,鍵盤就不再另說(shuō)了。首先在IUserInput.cs里宣告一bool變量命名為defense:

    [Header("===== State =====")]
    ...
    public bool defense;

??然后在JoystickInput.cs里用RB鍵舉盾:

        //角色舉盾
        defense = Input.GetButton(keyButRB);

??在ActorController.cs里,將輸入信號(hào)defense與動(dòng)畫機(jī)參數(shù)defense聯(lián)系起來(lái):

        anim.SetBool ("defense",pi.defense);

??現(xiàn)在代碼方面完成了缀匕,但是我差點(diǎn)了忘了講兩件事情纳决,就是給defense Layer灌個(gè)Avatar Mask和它的權(quán)重。這里我把新建一個(gè)Avatar Mask乡小,只覆蓋左手阔加,命名為lefthand,然后灌給defense Layer:



??因?yàn)檫@層只覆蓋其他層動(dòng)畫的左手满钟,所以可以不考慮權(quán)重變化的問(wèn)題胜榔,直接拉滿就行:



??現(xiàn)在應(yīng)該就大功告成了,來(lái)看看效果:
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末湃番,一起剝皮案震驚了整個(gè)濱河市夭织,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吠撮,老刑警劉巖尊惰,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異泥兰,居然都是意外死亡弄屡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門鞋诗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)膀捷,“玉大人,你說(shuō)我怎么就攤上這事削彬∪梗” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵融痛,是天一觀的道長(zhǎng)壶笼。 經(jīng)常有香客問(wèn)我,道長(zhǎng)雁刷,這世上最難降的妖魔是什么拌消? 我笑而不...
    開(kāi)封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮安券,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘氓英。我一直安慰自己侯勉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布铝阐。 她就那樣靜靜地躺著址貌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上练对,一...
    開(kāi)封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天遍蟋,我揣著相機(jī)與錄音,去河邊找鬼螟凭。 笑死虚青,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的螺男。 我是一名探鬼主播棒厘,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼下隧!你這毒婦竟也來(lái)了奢人?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤淆院,失蹤者是張志新(化名)和其女友劉穎何乎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體土辩,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡支救,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了脯燃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搂妻。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖辕棚,靈堂內(nèi)的尸體忽然破棺而出欲主,到底是詐尸還是另有隱情,我是刑警寧澤逝嚎,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布扁瓢,位于F島的核電站,受9級(jí)特大地震影響补君,放射性物質(zhì)發(fā)生泄漏引几。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一挽铁、第九天 我趴在偏房一處隱蔽的房頂上張望伟桅。 院中可真熱鬧,春花似錦叽掘、人聲如沸楣铁。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)盖腕。三九已至赫冬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間溃列,已是汗流浹背劲厌。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留听隐,地道東北人补鼻。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像遵绰,于是被迫代替她去往敵國(guó)和親辽幌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354