大家好,我是秦元培,歡迎大家繼續關注我的部落格,我的部落格地址是blog.csdn.net/qinyuanpei。
首先感謝大家對我部落格的關注,今天我想和大家分享的是一個飛機大戰的項目。這是一個比較綜合的項目,希望對大家學習Unity3D有所協助,我會在文章最後給出項目代碼。作為一個遊戲而言,遊戲策劃十分重要,所以在開始今天的文章之前,我們先來瞭解下這個項目的策劃。我們的玩家是一個飛機,玩家可以使用A、D、S、W四個鍵位來控制飛機位置,當按下空格鍵時,我方飛機可以向敵機發射炮彈,當敵機中彈後將減少生命值,當敵機生命值為0時,敵機將爆炸銷毀。在遊戲情境中只有一種從螢幕上方不斷向下飛行的敵機,當我方飛機與敵機碰撞後,雙方都將減少生命值。當我方生命值減少至0時,遊戲將結束。好了,瞭解完遊戲規則設定後,我們就可以開始今天的內容了。
一、遊戲情境
遊戲情境我們採用2D的介面,,我們建立一個藍天白雲的平面情境,該情境垂直於攝像機並採取正交投影方式。如果對在Unity3D中建立2D情境尚存在疑惑的朋友可以參考文章《[Unity3D]Unity3D遊戲開發之《經典打磚塊》遊戲的實現》和《Unity3D遊戲開發之使用Unity3D開發2D遊戲 (一)》兩篇文章。
我們這裡在情境中添加GUIText對象來顯示玩家得分等基本資料,指令碼定義如下:
using UnityEngine;using System.Collections;public class GameManager : MonoBehaviour {//玩家得分private Transform Grade;//玩家生命private Transform HP;//遊戲結束private Transform Text;//玩家private GameObject Player;void Start (){ //初始化介面 Grade=transform.Find("Grade"); HP=transform.Find("HP"); Text=transform.Find("Text"); Text.guiText.enabled=false; //擷取玩家對象 Player=GameObject.Find("Player");}void Update () { if(Player!=null) { //更新UI Grade.guiText.text="得分:"+Player.GetComponent<Player>().Grade.ToString(); HP.guiText.text="生命:"+Player.GetComponent<Player>().MaxHP.ToString(); } if(HP.guiText.text=="生命:0") { Text.guiText.enabled=true; //立即複活 if(Input.GetKey(KeyCode.Y)) {Application.LoadLevel("Main"); } //退出 if(Input.GetKey(KeyCode.N)) {Application.Quit(); } }}}
二、玩家飛機
玩家飛機的建立和背景的建立時相同的,這裡我們不再多說。玩家飛機需要完成移動、發射、碰撞的事件處理。為此我們編寫下面的指令碼:
using UnityEngine;using System.Collections;public class Player : MonoBehaviour { //飛機的移動速度 public float MoveSpeed; //飛機的最大生命值 public int MaxHP=100; //定義子彈對象 public GameObject Bullet; //定義子彈發射位置 private Transform BulletPosL; private Transform BulletPosR; [HideInInspector]public int Grade=0;void Start () { BulletPosL=this.transform.Find("BulletPosL"); BulletPosR=this.transform.Find("BulletPosR");}void Update () { if(Input.GetKey(KeyCode.A)) { transform.Translate(Vector3.left*Time.deltaTime*(-MoveSpeed)); } if(Input.GetKey(KeyCode.D)) { transform.Translate(Vector3.left*Time.deltaTime* MoveSpeed ); } if(Input.GetKey(KeyCode.W)) { transform.Translate(Vector3.forward*Time.deltaTime*(-MoveSpeed)); } if(Input.GetKey(KeyCode.S)) { transform.Translate(Vector3.forward*Time.deltaTime*MoveSpeed); } //按下空格鍵,發射子彈 if(Input.GetKey(KeyCode.Space)) { Instantiate(Bullet,BulletPosL.transform.position,Quaternion.Euler(new Vector3(0,1,0))); Instantiate(Bullet,BulletPosR.transform.position,Quaternion.identity); }}#region 減血public void Hit(int Value){ if(MaxHP>0) { MaxHP-=Value; }else { Destroy(this.gameObject); }}#endregion#region 增加分數 public void Add(int Value){Grade+=Value;}#endregion}
在這段代碼中,Bullet是我們的子彈對象,它從飛機的兩個子彈發射位置BulletPosL、BulletPosR發射,向螢幕上方按照一定的速度緩緩移動,當子彈與敵人碰撞時,子彈對象將銷毀,同時敵人生命值減少。Bullet對象對應於我們的一個Prefab。BulletPosL、BulletPosR對應于飛機上的兩個位置。
我們的子彈Bullet是一個綁定了指令碼的Capsule。它的代碼定義如下:
using UnityEngine;using System.Collections;public class Bullet : MonoBehaviour {//定義子彈的移動速度public float MoveSpeed=10F;//定義子彈的銷毀時間public float DestroyTime=2.0F;//定義子彈對敵人的傷害值public int Damage=2;//玩家飛機private GameObject Player;void Start(){Player=GameObject.Find("Player");}void Update () { //移動子彈 transform.Translate(Vector3.up * MoveSpeed * Time.deltaTime);}//碰撞事件捕捉void OnTriggerEnter(Collider mCollider){if(mCollider.gameObject.tag=="Enemy"){//敵人減血mCollider.gameObject.GetComponent<Enemy>().Hit(Damage);//我方得分Player.GetComponent<Player>().Add(1);//銷毀子彈Destroy(this.gameObject);}} //當離開攝像機範圍時觸發銷毀事件void OnBecameInvisible(){ Destroy(this.gameObject);}}
三、敵人飛機
在我們的遊戲中共有三種敵機,我們先將它們製作成預設。然後通過敵機產生器不斷地產生敵機。
和子彈相反,我們希望敵機從螢幕上方以一定速度向下移動,當碰到玩家飛機或者子彈時,將減少生命值。為此,我們這樣定義敵機的指令碼:
using UnityEngine;using System.Collections;public class Enemy : MonoBehaviour {//移動速度public float MoveSpeed=1.5F;//爆炸public GameObject Explosion;//最大生命值public int MaxHP=100;void Update () { //移動飛機 transform.Translate(Vector3.forward*Time.deltaTime*MoveSpeed);}public void Hit(int Value){ //如血量不低於0,則敵人飛機掉血 if(MaxHP>0) { MaxHP-=Value; }else { //產生爆炸效果 Instantiate(Explosion,transform.position,Quaternion.Euler(new Vector3(90,180,0))); //銷毀敵機 Destroy(this.gameObject); } }void OnTriggerEnter(Collider mCollider){ //如果與玩家飛機遭遇,則雙方減血 if(mCollider.gameObject.tag=="Player") { //敵機掉血 this.Hit(2); //玩家飛機掉血 Transform mPlayer=mCollider.gameObject.transform.Find("Player"); mPlayer.GetComponent<Player>().Hit(2); }}void OnBecameInvisible(){ Destroy(this.gameObject);}} 接下來,我們通過敵機產生器來不斷地產生敵機。敵人產生器是我們預製在遊戲情境中的空遊戲體,它位於遊戲情境的頂部。我們將下面的指令碼綁定到遊戲產生器 上,使其可以不斷地產生敵人:
using UnityEngine;using System.Collections;public class SpawnEnemy : MonoBehaviour {//定義敵人速度public float SpawnTime=1.0f;//定義敵人對象數組public GameObject[] Enemys;void Start () { StartCoroutine("Spawn");}//通過迭代器產生敵人IEnumerator Spawn(){ //等待 yield return new WaitForSeconds(SpawnTime); //複製對象 Instantiate(Enemys[Random.Range(0,3)],new Vector3(transform.position.x * Random.Range(-1F,1F),transform.position.y,-4),Quaternion.Euler(new Vector3(90,180,0))); StartCoroutine("Spawn");}} 其中Enemys對應到我們的敵人預設,每隔一段時間,我們隨機地產生一種敵人,該敵人將從螢幕上方緩緩向下移動。
四、碰撞檢測
在這個遊戲中,主要存在子彈與敵機的碰撞、玩家飛機與敵機的碰撞兩種形式。它們分別被定義在Bullet.cs和Enemy.cs兩個類檔案中。
//碰撞事件捕捉void OnTriggerEnter(Collider mCollider){if(mCollider.gameObject.tag=="Enemy"){//敵人減血mCollider.gameObject.GetComponent<Enemy>().Hit(Damage);//我方得分Player.GetComponent<Player>().Add(1);//銷毀子彈Destroy(this.gameObject);}}
void OnTriggerEnter(Collider mCollider){ //如果與玩家飛機遭遇,則雙方減血 if(mCollider.gameObject.tag=="Player") { //敵機掉血 this.Hit(2); //玩家飛機掉血 Transform mPlayer=mCollider.gameObject.transform.Find("Player"); mPlayer.GetComponent<Player>().Hit(2); }}
五、爆炸特效
當敵機被摧毀時,將顯示爆炸特效,我們這裡採用一組2D貼圖來實現爆炸特效,原理是改變貼圖的mainTextureScale和mainTextureOffset兩個屬性值。我們來一起看代碼:
using UnityEngine;using System.Collections;public class Explosion : MonoBehaviour {//動畫序列索引private int index=0;//聲音private AudioSource mAudio;void Start(){ mAudio=GetComponent<AudioSource>();}void FixedUpdate () { if(index<8) { this.renderer.sharedMaterial.mainTextureScale=new Vector2(1.0F/8,1); this.renderer.sharedMaterial.mainTextureOffset=new Vector2(index * 1.0F/8,0); index+=1; }else{ mAudio.Play(); Destroy(this.gameObject);}}} 其中mAudio對應到一個AudioSource組件,我們在這裡指定一個爆炸的音效。同樣地,我們將爆炸製作成預設,該預設對應於Enemy.cs中的Explosion。
好了,到這裡今天的 內容就講解完了,我們一起來看看最終的效果吧!
希望今天的內容大家能夠喜歡。學了這麼長時間的Unity3D,感慨還是挺多的,很多東西你不努力去做,是永遠做不好的,你不給自己壓力,你不會知道自己有多優秀。本項目原始碼可以從這裡下載。
每日箴言: 不管活到什麼歲數,總有太多思索、煩惱與迷惘。一個人如果失去這些,安於現狀,才是真正意義上的青春的完結。—— 渡邊淳一
喜歡我的部落格請記住我的名字:秦元培,我的部落格地址是blog.csdn.net/qinyuanpei
轉載請註明出處,本文作者:秦元培,本文出處:http://blog.csdn.net/qinyuanpei/article/details/25158323