在Unity中實(shí)現(xiàn)角色行走時(shí)會(huì)遇到林林總總的問題乖寒,這里就記錄一下我遇到的問題并提供解決方法贝润。
由于本人是零基礎(chǔ)自學(xué)探颈,可能會(huì)出現(xiàn)一些很基本的問題璃氢,記錄成長(zhǎng)為主。
1.玩家鍵盤的輸入轉(zhuǎn)為移動(dòng)信號(hào)
? ? 玩家的輸入一般由兩種形式雨饺,一是鍵盤輸入,二是手柄輸入,這里暫且只考慮鍵盤輸入簸呈。一般移動(dòng)的輸入鍵是wasd亦或是↑↓←→。而移動(dòng)信號(hào)的表現(xiàn)形式為一個(gè)二維坐標(biāo)軸:
? ? 我們要做的就是當(dāng)玩家鍵入W時(shí)店茶,記錄坐標(biāo)軸的xy變量分別為(1,0)蜕便;另外還要考慮沖突問題,當(dāng)玩家同時(shí)鍵入AD時(shí)xy變量應(yīng)為(0,0)贩幻,角色應(yīng)靜止不動(dòng)轿腺。
? ? 由此我們可以寫下如下代碼:
? ? 顯然targetUp為x坐標(biāo),targetRight為y坐標(biāo)丛楚。剩下要做的就是添加blend tree和動(dòng)畫族壳,把blend tree(Blend Type為1D)的參數(shù)與信號(hào)聯(lián)系起來,這是后話了趣些。
2.平滑移動(dòng)的問題
? ? 按上述實(shí)現(xiàn)的代碼的話仿荆,不難發(fā)現(xiàn):當(dāng)玩家鍵入W,角色會(huì)從靜止立刻到播放行走的動(dòng)畫,即0直接變?yōu)?拢操,這就很突兀锦亦,動(dòng)畫播放上會(huì)不連貫。解決這個(gè)問題的根本就是0應(yīng)該勻速增長(zhǎng)到1或是1勻速減少到0令境。恰好Mathf類提供了這么一個(gè)方法:
? ? 這個(gè)函數(shù)能實(shí)現(xiàn)從一個(gè)三維坐標(biāo)向一個(gè)理想值地逐漸轉(zhuǎn)變杠园。由圖知此函數(shù)需要一個(gè)當(dāng)前的坐標(biāo)值、一個(gè)目標(biāo)坐標(biāo)值舔庶、一個(gè)當(dāng)前速度的三維坐標(biāo)引用抛蚁,一個(gè)平滑時(shí)間的浮點(diǎn)值。其中的3個(gè)不難理解栖茉,平滑時(shí)間就是規(guī)定完成這個(gè)過程的時(shí)間篮绿,但這個(gè)currentVelocity需要解釋一下,按照官網(wǎng)的描述吕漂,當(dāng)你每一次調(diào)用這個(gè)函數(shù)時(shí)亲配,這個(gè)值都會(huì)被修改,那么其實(shí)就提供一個(gè)不用初始化的Vector3變量就好惶凝,其余的SmoothDamp會(huì)自己搞定吼虎。
? ? targetUp呢就是剛才得到的硬邦邦的不是0就是1的值,顯然這個(gè)就是目標(biāo)值苍鲜,需要?jiǎng)蛩僭鲩L(zhǎng)或減少到這個(gè)值思灰;Dup呢就是初始值,是增長(zhǎng)或減少前的值混滔。當(dāng)Dup為0時(shí)洒疚,targetUp為1時(shí),就從0增到1坯屿;當(dāng)targetUp變回0時(shí)油湖,此時(shí)Dup是1,就從1減到0领跛。
? ? 這個(gè)處理其實(shí)與Blend Tree里的參數(shù)是很符合的乏德。
3.轉(zhuǎn)向問題
? ? 轉(zhuǎn)向問題其實(shí)就是改變角色當(dāng)前向前的方向的問題(forward)。一開始用的是坐標(biāo)軸的坐標(biāo)做信號(hào)吠昭,現(xiàn)在可以換個(gè)方式喊括,用距坐標(biāo)軸原點(diǎn)的距離做移動(dòng)的信號(hào),配合上單位向量矢棚,就能解決轉(zhuǎn)向和斜向走的問題郑什。
? ? 設(shè)置一變量記錄距原點(diǎn)的距離:勾股定理,不難理解蒲肋。
? ? ? 當(dāng)然Dmag只是一個(gè)標(biāo)量蹦误,不具備方向劫拢,但可以與Blend Tree的參數(shù)產(chǎn)生聯(lián)系了,forward為在Blend Tree里的參數(shù)强胰,anim為一Animator類型舱沧,接收其Animator組件,不再贅述偶洋。
? ? 我們還需要一個(gè)Vector3變量來記錄其方向和坐標(biāo)值:
? ? 以此改變模型的向前向量:
? ? 此時(shí)角色就能隨意轉(zhuǎn)向了熟吏,但仍有一點(diǎn)瑕疵:
? ? ? ? 1.當(dāng)Dup、Dright歸0時(shí)玄窝,Dvec會(huì)得到一個(gè)(0,0,0)的矢量牵寺,從而導(dǎo)致模型的向前向量也變?yōu)?0,0,0),會(huì)出現(xiàn)無(wú)論我怎么轉(zhuǎn)方向恩脂,過一會(huì)就會(huì)回到模型z軸的正方向帽氓。
? ? ? ? 2.轉(zhuǎn)向也缺少平滑處理。
? ? ? ? 3.Dmag會(huì)出現(xiàn)1.414的情況俩块,原因是當(dāng)斜向走時(shí)由于勾股定理得到的是一個(gè)根號(hào)2黎休,這會(huì)造成當(dāng)你角色真正走起來時(shí)斜向走的速度會(huì)比正向走快40%。
? ? 關(guān)于第一個(gè)問題玉凯,只要在改變轉(zhuǎn)向之前給Dmag設(shè)個(gè)最低閾值势腮,這就能防止把(0,0,0)給到向前向量。
? ? 其他問題將會(huì)在后續(xù)解決漫仆。
4.真正走起來
? ? 在給模型添加了剛體(Rigidbody)組件后捎拯,有兩種方式可以令角色真正走起來,一是改變剛體的位置position盲厌,二是改變剛體的速度velocity署照。改變位置很簡(jiǎn)單,速度乘以時(shí)間就好:
? ? 但這一過程要在FixedUpdate()里實(shí)現(xiàn)吗浩,而不是Update()建芙,因?yàn)檫@兩個(gè)函數(shù)每一幀的時(shí)間不一致,Update()每一幀的時(shí)間不固定拓萌,即第一幀與第二幀的時(shí)間t1和第三幀與第四幀的時(shí)間t2不一定相同。FixedUpdate()每幀與每幀之間相差的時(shí)間是固定的升略。所以一些物理屬性的更新操作應(yīng)該放在FxiedUpdate中操作微王,因?yàn)檫@樣GameObject的物理表現(xiàn)的更平滑,更接近現(xiàn)實(shí)品嚣。而Time.fixedDeltaTime與Time.DeltaTime也有所區(qū)別炕倘,前者是固定時(shí)間,為0.02s(可修改)翰撑;后者是前一幀到后一幀所用的時(shí)間罩旋,因?yàn)閁pdate()中的幀率會(huì)變化啊央,所以Time.DeltaTime也會(huì)變化。
? ? 如果改變的是剛體的速度涨醋,要有一點(diǎn)需要注意瓜饥,如果單純是這樣:
? ? 這在地面上時(shí)沒什么問題,可以正常行走浴骂,但當(dāng)你走上斜波再走下來乓土,你會(huì)發(fā)現(xiàn)你懸空然后慢慢下降:
? ? 因?yàn)樯鲜龃a把它速度中的y分量置0了,movingVec中只有x(Dright)和z(Dup)分量有值溯警,y分量為0趣苏,這就導(dǎo)致了它一下坡就懸空了。代碼應(yīng)該改為
? ? 這就可以了√萸幔現(xiàn)在角色走起來沒什么大礙了食磕。
以后多點(diǎn)GIF來展示效果好一點(diǎn)。
2019年7月1日 17:07:20
5.平滑轉(zhuǎn)向
? ? 現(xiàn)在物體前進(jìn)的方向是受Dvec控制的喳挑,而Dvec只是單純的坐標(biāo)軸坐標(biāo)與單位向量相乘而得彬伦,就是說D就是左,A就是右蟀悦,從左轉(zhuǎn)到右不具備轉(zhuǎn)身的過渡態(tài)媚朦,是立刻完成。上圖或許更直觀:
? ? 這里需要一個(gè)函數(shù)來解決這個(gè)平滑轉(zhuǎn)向的問題日戈,那就是Vector3.Slerp询张,先看看這個(gè)函數(shù)在官網(wǎng)上的描述:
? ? 能在兩坐標(biāo)之間進(jìn)行球面插值,何為插值浙炼?就是在離散數(shù)據(jù)之間補(bǔ)插一條連續(xù)函數(shù)份氧,使得這些離散數(shù)據(jù)可以在這條函數(shù)中估算得到。例如兩個(gè)不相關(guān)的點(diǎn)弯屈,在其間補(bǔ)插了一條連續(xù)函數(shù)之后蜗帜,能用這條函數(shù)從一個(gè)點(diǎn)遞增或遞減到另外一個(gè)點(diǎn),不過這是線性插值资厉,線性插值有經(jīng)過零點(diǎn)的可能厅缺,相關(guān)函數(shù)是Mathf.Lerp。球面插值與線性插值不同宴偿,它加入了向量當(dāng)做方向湘捎,這使得它可以不經(jīng)過零點(diǎn)。這個(gè)特性很好的解決了轉(zhuǎn)向的問題窄刘。
? ? 接下來看看它要怎么調(diào)用:
? ? 它吃3個(gè)參數(shù)窥妇,一個(gè)是當(dāng)前值,一個(gè)目標(biāo)值娩践,一個(gè)是進(jìn)行插值過程的速度活翩。好來試試看:
? ? 為了讓效果明顯一點(diǎn)烹骨,我把速度設(shè)為了0.1f,這個(gè)轉(zhuǎn)向速度就很慢了:
? ? 我們可以看到材泄,現(xiàn)在已經(jīng)有一個(gè)轉(zhuǎn)身的效果了沮焕,但是速度設(shè)置太慢會(huì)有一個(gè)副作用,就是會(huì)產(chǎn)生一段與轉(zhuǎn)身反向垂直方向的位移脸爱,這不能說不好遇汞,看是否需要吧,要是不需要就把速度提高點(diǎn)簿废,提高到0.5試試看:
? ? 現(xiàn)在呢位移就幾乎沒有了(實(shí)際上還是有的)空入,轉(zhuǎn)向也很流暢、自然族檬。