百度云免費(fèi)空間seo主要做什么工作
被武士砍中后,怪物將向四面八方飛散。
動(dòng)作的不同將導(dǎo)致攻擊力度的強(qiáng)弱表現(xiàn)不同,被攻擊的各個(gè)對(duì)象的反應(yīng)也有很大差異。在格斗游戲中,對(duì)對(duì)手一頓拳打腳踢后,看到其步履蹣跚的樣子,往往可以感受到他的疼痛。相反如果對(duì)手顯得從容不迫,即使動(dòng)作再華麗也只能給人一種給攻擊力很弱的印象。
有時(shí)候我們常常聽(tīng)到攻擊反饋的說(shuō)法。在玩游戲時(shí)大家應(yīng)該都有過(guò)感覺(jué)按鍵和搖桿好像變重了的經(jīng)歷吧?可以說(shuō)這種游戲通過(guò)通過(guò)視覺(jué)和聽(tīng)覺(jué)把攻擊反饋完美地呈現(xiàn)了出來(lái)。
我們將通過(guò)怪物的四處飛散來(lái)表現(xiàn)武士的攻擊強(qiáng)度。另外,我們也將實(shí)現(xiàn)上文提到的靠近斬殺怪物會(huì)獲得高分的規(guī)則,并使“在多金的距離斬殺了怪物”影響怪物的飛散方式。
不過(guò)每次都采用同樣的飛散方式未免有些單調(diào),因此我們會(huì)調(diào)整飛散的方向使每次的效果都略有不同。
一、想象一下“圓錐體”
在考慮實(shí)現(xiàn)方法之前,我們首先整理一下“需要做什么”,用專(zhuān)業(yè)術(shù)語(yǔ)來(lái)說(shuō)在這叫需求分析
- 要讓怪物華麗地四處飛散
- 讓每次的動(dòng)作都各有不同
“華麗”這種描述對(duì)于變成來(lái)說(shuō)是一個(gè)比較曖昧的說(shuō)法,應(yīng)該描述得更加具體一些。
之前已經(jīng)提到過(guò),把若干個(gè)怪物編成一個(gè)小組,并通過(guò)這個(gè)小組來(lái)執(zhí)行被攻擊判定。受到攻擊時(shí)小組內(nèi)的所有怪物都將四處飛散。而如果怪物們都向著同樣的方向飛去,將毫無(wú)“華麗”可言。換句話(huà)說(shuō),所謂的“華麗”,應(yīng)該是這些怪物盡量朝著不同的方向飛散開(kāi)來(lái)。
這個(gè)被刀砍中后各自飛散的過(guò)程,更類(lèi)似于炸彈爆炸的畫(huà)面。由于怪物被刀砍中時(shí)受到了某一方向的作用力,因此往相反的一側(cè)飛出才顯得自然。武士具有右斬、左斬的動(dòng)作,每個(gè)動(dòng)作都將令怪物反方向飛出。
“靠近斬殺時(shí)怪物將更華麗地飛散開(kāi)”這個(gè)要素也是必要的。雖然單純改變速度也能達(dá)到類(lèi)似的效果,但為了讓玩家更容易地了解是否完美地看中了怪物,我們將飛散的方向改為前后方向。如果從前面飛來(lái)的怪物都按照相同的方向彈開(kāi),就能讓玩家強(qiáng)烈地感受到攻擊的力度。
那么我們?cè)俅渭?xì)化需要完成的工作:
- 怪物朝不同的方向飛出
- 根據(jù)動(dòng)作的不同往左或往右飛出
- ?根據(jù)斬殺時(shí)的距離遠(yuǎn)近調(diào)整為前后
- 每次飛出的方式都有變化
?要是每次飛出的方式都不一樣,很多人會(huì)想到使用隨機(jī)數(shù)。不過(guò)如果僅對(duì)飛出的方向和速度進(jìn)行隨機(jī)化處理,雖然可以改變飛出的方向,但不保證怪物會(huì)按照我們期待的方向飛出。
像這樣“想在隨機(jī)化的同時(shí)進(jìn)行某種程度的傾向控制”的時(shí)候,解決問(wèn)題的關(guān)鍵就是先確定好關(guān)鍵性的原則,再使用隨機(jī)數(shù)改變細(xì)節(jié)參數(shù)。
這里我們參考水管?chē)婎^噴水的情景,決定使怪物沿著圓錐的表面飛出,也就是說(shuō),圓錐的朝向基本上決定了飛散的方向,底面的半徑則決定了飛散開(kāi)的范圍。
二、具體的計(jì)算方法
接下來(lái),我們對(duì)各個(gè)參數(shù)進(jìn)行詳細(xì)的說(shuō)明。
首先看看圓錐的底面半徑如何決定了飛散的范圍
怪物被砍中后飛出的方向是由武士攻擊瞬間的速度向量決定的。所有怪物被擊飛后的速度向量都以圓錐的頂點(diǎn)為起始點(diǎn),終點(diǎn)位于圓錐底面的圓周上,按照一定間隔并列排開(kāi)。
底面半徑越大圓錐的開(kāi)口范圍越廣,每個(gè)怪物的速度向量的方向也有很大差異,因此怪物飛散范圍就比較廣。反之如果半徑比較小,則飛散開(kāi)的范圍就比較窄。
下面,我們通過(guò)圓錐的傾角來(lái)控制前后方向
這里的“前后”,指的是從武士的視角看到的前后。武士向畫(huà)面右方前進(jìn),也就是+X方向,這樣在畫(huà)面上看起來(lái)就是左右傾斜。需要注意的是在計(jì)算時(shí)會(huì)變?yōu)閲@Z軸旋轉(zhuǎn)。
最后,通過(guò)圓弧的中心角度來(lái)控制左右方向的飛散
怪物飛散的方向,也就是速度向量分布在圓錐的表面上。但它們并沒(méi)有完全分布在1周360°的各個(gè)角落,而是集中在了大約半個(gè)圓周的范圍內(nèi)。這里將通過(guò)排列著的各個(gè)速度向量的圓弧的中心點(diǎn)的角度控制左右方向。程序中使用y_angle_swing變量來(lái)表示。
下面我們結(jié)合代碼來(lái)看看實(shí)際的計(jì)算過(guò)程:OniGroupControl.OnAttackedFromPlayer方法
public void OnAttackedFromPlayer(){// 累加被擊倒的怪物數(shù)量// (后續(xù)部分也會(huì)進(jìn)行計(jì)算評(píng)價(jià),不過(guò)這里先執(zhí)行一次)this.scene_control.AddDefeatNum(this.oni_num);// 怪物向四處飛散//// 在圓錐表面的形狀上決定各個(gè)怪物飛散開(kāi)的方向// 評(píng)價(jià)越高則圓錐的開(kāi)口越大,這樣就能飛散到更廣的區(qū)域// 玩家的速度如果較快,圓錐會(huì)向前傾斜一些Vector3 blowout; // 怪物飛散的方向(速度向量)Vector3 blowout_up; // ↑的垂直分量Vector3 blowout_xz; // ↑的水平分量float y_angle;float blowout_speed;float blowout_speed_base;float forward_back_angle; // 圓錐的前后傾斜角度f(wàn)loat base_radius; // 圓錐的地面半徑float y_angle_center;float y_angle_swing; // 圓弧的中心(根據(jù)動(dòng)作左右決定該值)float arc_length; // 圓弧的長(zhǎng)度(圓周)switch(this.scene_control.evaluation) {default:case SceneControl.EVALUATION.OKAY:{base_radius = 0.3f;blowout_speed_base = 10.0f;forward_back_angle = 40.0f;y_angle_center = 180.0f;y_angle_swing = 10.0f;}break;case SceneControl.EVALUATION.GOOD:{base_radius = 0.3f;blowout_speed_base = 10.0f;forward_back_angle = 0.0f;y_angle_center = 0.0f;y_angle_swing = 60.0f;}break;case SceneControl.EVALUATION.GREAT:{base_radius = 0.5f;blowout_speed_base = 15.0f;forward_back_angle = -20.0f;y_angle_center = 0.0f;y_angle_swing = 30.0f;}break;}forward_back_angle += Random.Range(-5.0f, 5.0f);arc_length = (this.onis.Length - 1)*30.0f;arc_length = Mathf.Min(arc_length, 120.0f);// 根據(jù)玩家的動(dòng)作(左斬,右斬),改變左右飛散的方向y_angle = y_angle_center;y_angle += -arc_length/2.0f;if(this.player.attack_motion == PlayerControl.ATTACK_MOTION.RIGHT) {y_angle += y_angle_swing;} else {y_angle -= y_angle_swing;}y_angle += ((OniGroupControl.count*7)%11)*3.0f;// 讓組內(nèi)的怪物全部被擊倒foreach(OniControl oni in this.onis) {//blowout_up = Vector3.up;blowout_xz = Vector3.right*base_radius;blowout_xz = Quaternion.AngleAxis(y_angle, Vector3.up)*blowout_xz;blowout = blowout_up + blowout_xz;blowout.Normalize();// 圓周向前后傾斜blowout = Quaternion.AngleAxis(forward_back_angle, Vector3.forward)*blowout;// 飛散開(kāi)的速度blowout_speed = blowout_speed_base*Random.Range(0.8f, 1.2f);blowout *= blowout_speed;if(!SceneControl.IS_ONI_BLOWOUT_CAMERA_LOCAL) {// 全局坐標(biāo)系下飛散開(kāi)(不和攝像機(jī)發(fā)生連動(dòng))時(shí),// 要加上玩家的速度blowout += this.player.GetComponent<Rigidbody>().velocity;}// 旋轉(zhuǎn)Vector3 angular_velocity = Vector3.Cross(Vector3.up, blowout);angular_velocity.Normalize();angular_velocity *= 3.14f*8.0f*blowout_speed/15.0f*Random.Range(0.5f, 1.5f);//angular_velocity = Quaternion.AngleAxis(Random.Range(-30.0f, 30.0f), Vector3.up)*angular_velocity;//oni.AttackedFromPlayer(blowout, angular_velocity);//Debug.DrawRay(this.transform.position, blowout*2.0f, Color.white, 1000.0f);//y_angle += arc_length/(this.onis.Length - 1);}// 播放被擊倒的音效// 太多的音效同時(shí)播放不容易聽(tīng)清,只播放一個(gè)//if(this.onis.Length > 0){AudioClip[] yarareSE = null;if( this.onis.Length >= 1 && this.onis.Length < 3 ){yarareSE = this.YarareLevel1;}else if( this.onis.Length >= 3 && this.onis.Length < 8 ){yarareSE = this.YarareLevel2;}else if( this.onis.Length >= 8 ){yarareSE = this.YarareLevel3;}if( yarareSE != null ){int index = Random.Range( 0, yarareSE.Length );this.onis[0].GetComponent<AudioSource>().clip = yarareSE[index];this.onis[0].GetComponent<AudioSource>().Play();}}OniGroupControl.count++;// 刪除實(shí)例//// 執(zhí)行Destroy(this) 后, 刪除的不是OniGroupPrefab 實(shí)例,而是腳本(OniGroupControl)// 請(qǐng)注意//Destroy(this.gameObject);}