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