[Unity3D入門]入門級游戲項目"坦克狙擊手"更新


[Unity3D入門]入門級游戲項目"坦克狙擊手"更新

上一篇中我分享了一個尚未完全寫好的入門級unity3d項目"坦克狙擊手"。

本文介紹最新版的"坦克狙擊手"相關情況。

需要源代碼和發布的Windows版、網頁版程序的同學麻煩支付100元留下你的郵箱~

關於調節粒子系統參數的經驗

如你所見,我對導彈尾焰的粒子效果進行了調節。這里學到的一個經驗是,分析然后模仿現實生活中的物理化學現象,才能做出逼真的效果。一個粒子就是火焰中的一個點。我們都知道蠟燭的火焰分為內焰中焰外焰三層。符合一個粒子從誕生到熄滅、從中心位置到邊沿位置、從白色到黃色到金色(顏色方面我就不細琢磨了,畢竟 導彈和蠟燭不完全一樣)的變化過程。根據這些知識去設定粒子系統的參數就可以得到比較好的效果。

 

使用第三方包Detonator的爆炸效果

本篇更新的導彈爆炸效果用的是Detonator提供的示例prefab,只稍微調節了一下大小和爆炸時間。Detonator很好用,其效果很贊,包內自帶的示例場景Detonator-TestWall和PDF說明文檔一目了然。唯一需注意的一點是,導入Detonator包時,在"NormalMap settings"窗口中一定要選擇"Ignore"按鈕,否則,你會看到爆炸煙霧的正方形邊沿,爆炸效果就顯得假了。

哦對了,發布的時候也要注意一點,就是必須把示例場景Detonator-TestWall也加入到發布列表,否則爆炸效果是無法顯示的。原因,暫時不知道。

 

導彈殺傷一定半徑范圍內的所有坦克

上一篇中,導彈只能對命中的坦克造成殺傷。這一篇中通過使用"Physics.OverlapSphere()"方法,導彈可以對一定半徑范圍內的所有坦克造成殺傷,更具真實性。

 1     public float explosionRadius = 10;
 2     public float maxPower = 100;
 3     public float maxForce = 10000;
 4     void OnCollisionEnter(Collision collision) {
 5         var point = collision.contacts[0].point;//獲取導彈擊中(爆炸)的位置
 6         Collider[] colliders = Physics.OverlapSphere(point, explosionRadius);//獲取導彈爆炸范圍內所有的碰撞體
 7         Destroy(this.gameObject);//導彈已經不復存在
 8         foreach (Collider hit in colliders) {
 9             if (hit == null) { continue; }
10             if (hit.rigidbody == null) { continue; }
11             if (hit.gameObject.tag != "Tank") { continue; }
12             var tank = hit.gameObject.GetComponent<TankMove>();
13             if (tank != null) {//這個碰撞體是一個坦克
14                 tank.Damage(maxPower);//坦克被殺傷(暫時認為殺傷半徑內的殺傷力是相同的,簡化計算)
15                 if (tank.hp <= 0) {//坦克掛掉了
16                     hit.rigidbody.AddExplosionForce(maxForce, point, explosionRadius);//坦克被爆炸沖擊波沖走
17                 }
18             }
19         }
20         ExplosionEffectHelper.Instance.Explode(ExplosionEffectHelper.ExplosionEffect.MissileExplosion, point);//Detonator爆炸效果
21         SoundEffectHelper.Instance.MakeExplosionSound();//爆炸聲音
22     }

PS:在我知道"Physics.OverlapSphere()"這個方法前,我在導彈爆炸后創建了一個Sphere,讓它代表導彈爆炸的球形沖擊波,通過這個Sphere在膨脹過程中與周邊坦克的OnCollisionEnter事件對坦克計算殺傷。這樣雖然也有周邊殺傷的能力,但是計算沖擊波的力量有點繁瑣;且爆炸瞬間的殺傷變成了Sphere膨脹若干個幀之后的殺傷,不太真實。

 

坦克撞坦克問題

上一篇中,后面速度快的坦克撞上前面速度慢的坦克,它倆就可能飛起來。本篇解決了這個問題。方法如下:

如圖所示,在坦克prefab中,在其前后左右分別放置一個Cube,將其包圍起來(並取消勾選Cube的Mesh Renderer,選中Is Trigger),做成"圍牆"。在坦克prefab前方的Cube(命名為Front)中設置OnTriggerEnter()等方法。

 1     TankMove tankMoveScript;
 2     void Awake() {
 3         this.tankMoveScript = this.GetComponentInParent<TankMove>();
 4     }
 5     
 6     void OnTriggerEnter(Collider other)
 7     {    if (other.gameObject.tag == "Back")//other是前面的一輛坦克的“圍牆”
 8         {
 9             this.tankMoveScript.SetForward(false);//撞到了前面的坦克的“圍牆”,就暫時不要繼續走了
10         }
11     }
12 
13     void OnTriggerExit(Collider other)
14     {
15         if (other.gameObject.tag == "Back")//other是前面的一輛坦克的“圍牆”
16         {
17             this.tankMoveScript.SetForward(true);//前面的坦克走開了,那么我也繼續走
18         }
19     }

在坦克prefab后方的Cube(命名為Back)中也設置OnTriggerEnter()等方法。

 1     private GameObject other;
 2     void OnTriggerEnter(Collider other)
 3     {   if (other.gameObject.tag == "Front")//other是后面的一輛坦克的“圍牆”
 4         {
 5             this.other = other.gameObject;//我擋住后面的一輛坦克了
 6         }
 7     }
 8     
 9     void OnTriggerExit(Collider other)
10     {
11         if (other.gameObject.tag == "Front")
12         {
13             this.other = null;//我不再繼續擋着后面那輛坦克了
14         }
15     }
16     
17     void OnDestroy() {
18         var o = other;
19         if (o != null) {//要是在我擋住后面一輛坦克的時候,我掛了,我得通知人家
20             o.GetComponentInParent<TankMove>().SetForward(true);
21         }
22     }

 

顯示一些信息

例如,我想在屏幕上顯示出當前我擊殺了多少坦克。

很簡單,創建一個腳本"DisplayKilledTankCount.cs",編寫代碼如下。

1     public int killedTank = 0;
2     void OnGUI() {
3         GUI.Label(new Rect(10, 10, 200, 20), string.Format("Killed tank: {0}", killedTank));
4     }

將這個腳本作為一個component添加到Main Camera上。

在"TankMove.cs"的"Damage()"方法中添加2行代碼:

 1     public float hp = 100;
 2     public void Damage(float damageCount) {
 3         hp -= damageCount;
 4         if (hp <= 0) {
 5             this.gameObject.rigidbody.freezeRotation = false;//掛掉了,可以被導彈沖擊到任何角度
 6             var display = Camera.main.GetComponent<DisplayKilledTankCount>();
 7             display.killedTank += 1;//擊殺的坦克增加1
 8             Destroy(gameObject, 20);
 9         }
10     }

 

坦克的布娃娃效果

布娃娃效果就是人死的時候會呈現各種姿式,不會像以前一樣,跟一棍似的直不楞登一倒~

坦克掛掉了,不應該立即被Destroy()掉,那樣太突兀了。我想做的效果是坦克在掛掉時被導彈沖擊波擊飛,落地,然后掉入地面下消失,然后才Destroy()。

實際上上文中的代碼已經順帶顯示了如果實現這一效果。

首先,導彈擊殺掉坦克的時候,在Damage()方法中設定20秒(經驗值)后被Destroy()。

然后,在TankMove.cs中添加字段"deadTime",記錄坦克掛掉后經過了多久。在坦克掛掉10秒(經驗值)后,我們讓坦克具備陷入地下的能力。

 1     private float deadTime = 0;
 2     private bool sinking = false;
 3     // 每幀調用一次,用於更新游戲場景和狀態(和物理狀態有關的更新應放在FixedUpdate里)
 4     void Update () {
 5         if ((!sinking) && (hp <= 0)) {
 6             deadTime += Time.deltaTime;
 7             if (deadTime >= 10) {
 8                 this.gameObject.collider.isTrigger = true;//這樣,物理引擎就不會對坦克生效。(當然,仍會觸發OnTriggerXxx()事件)
 9                 sinking = true;
10             }
11         }
12     }

最后,坦克掛掉之后就不應該有動力了。

 1     // 每個固定物理時間間隔(physics time step)調用一次,用於物理狀態的更新
 2     void FixedUpdate() {
 3         if (hp <= 0) { return; }//掛了,就別自己動了,隨遇而安吧。
 4         if (this.forward) {
 5             this.rigidbody.velocity = new Vector3(0, rigidbody.velocity.y, zSpeed);
 6         }
 7         else {
 8             this.rigidbody.velocity = new Vector3(0, rigidbody.velocity.y, 0);
 9         }
10     }

 

需要源代碼和發布的Windows版、網頁版程序的同學麻煩支付100元留下你的郵箱~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM