天天看點

【Unity】FlappyBird剖析-附源碼

FlappyBird不用多說了,一款極其簡單,但是又很火的遊戲。我在得知這款瘋狂的遊戲後,就有一種把它重制的沖動,然後花了我4個多小時,産生出了一個可以玩的版本,分享給大家(文末尾付下載下傳連結)。

下面簡單介紹遊戲的開發過程(本文的例子需要使用unity4.3.0以上的版本打開)。

目錄介紹

 運作圖:

【Unity】FlappyBird剖析-附源碼

項目的目錄結構如下圖,anims中存放動畫資源,prefab中存放預置對象,scprits存放腳本,sprites用來存放貼圖。

【Unity】FlappyBird剖析-附源碼

準備資源

擷取FlappyBird的貼圖資源和音效資源。把資源導入到sprites檔案夾下,選中atlas,在Inspector中進行編輯,如下圖:

【Unity】FlappyBird剖析-附源碼

設定為sprite,模式為Multiple,點選按鈕Sprite Editor進行相應的圖檔分隔。在彈出的對話框中,可以使用自動切圖方式,如下圖:

【Unity】FlappyBird剖析-附源碼

接下來就可以進行編碼了

設定場景

為了區分場景的層次(主要是用來決定圖層的順序,sorting Layer的功能)以及編碼的需求,建立一些tag sorting Layer和Layer。先點選Unity編輯器右上方的Layers下拉菜單并選擇"Edit Layers...",如下圖:

【Unity】FlappyBird剖析-附源碼

并填寫如下資訊:

【Unity】FlappyBird剖析-附源碼

移動的道路和障礙

一格道路有兩個障礙(如下圖),場景中用兩格道路來反複循環(當一格道路移出螢幕後就重新調整位置,等待下一次出現在螢幕上),達到不斷移動的效果。

【Unity】FlappyBird剖析-附源碼

下面是道路移動的部分代碼road.cs

public class road : MonoBehaviour {	
	....
	// Update is called once per frame
	void Update () {
	 	Vector3 pos = trans.position;
		pos.x -= speed * Time.deltaTime;
		trans.position = pos;
		if(pos.x <= -1.6f - 3.35f*idx) {   //當道路移出螢幕後,從小調整其位置
			Vector3 pp = roads[idx%2].transform.position;
			pp.x += 3.35f;
			idx++;
			roads[idx%2].transform.position = pp;
			if(isBegin){
				roads[idx%2].GetComponent<roadGen>().gen();
			}
		}
	}
           

道路障礙的顯示與否(在歡迎頁面,路面不需要障礙),以及障礙的生成都在檔案roadGen.cs中,我把上下柱子合并成一個對象,在生成障礙時,隻要使其在一定範圍内上下移動就可以了。代碼片段如下:

public class roadGen : MonoBehaviour {  
    public GameObject[] zhuzi;  
    public float down=3.8f, upper = 6.0f;     ...  
    public void gen() { // 一格道路有兩個柱子  
        zhuzi[0].SetActive(true);  
        zhuzi[1].SetActive(true);  
        Vector3 p = zhuzi[0].transform.localPosition;    
        float vv = Random.value;  
        p.y = Mathf.Lerp(down, upper, vv);   
        zhuzi[0].transform.localPosition = p; //設定第一個柱子的位置  
  
        p = zhuzi[1].transform.localPosition;  
         vv = Random.value;  
        p.y = Mathf.Lerp(down, upper, vv);  
        zhuzi[1].transform.localPosition = p; //設定第二個柱子的位置
    }  
  
    public void hidden() {  
        zhuzi[0].SetActive(false);  
        zhuzi[1].SetActive(false);  
    }  
}  
           

最後在障礙物和地面都添加BoxCollider2D,使其能夠擷取碰撞消息。

大嘴唇的小鳥

首先小鳥有個飛行的幀動畫,在sprite檔案夾下的atlas中,選擇三個幀,直接拖動到場景中,unity自動形成了一個帶有幀動畫的sprite。選中該sprite,在Window/Animation界面中,調整sprite的播放時間,如下圖:

【Unity】FlappyBird剖析-附源碼

同樣要給小鳥一個BoxCollider2D的Component,使其能夠響應碰撞,還要添加Rigibody2D。具體請參考例子。這裡會涉及到兩個腳本(時間匆忙,沒怎麼考慮設計):bird.cs和clider.cs;前者用來向小鳥施加力的作用,後者處理碰撞。 這個遊戲的最主要部分就是 clider .cs,這個檔案處理得分和是否碰撞到障礙物。代碼如下:

using UnityEngine;
using System.Collections;

public class clider : MonoBehaviour {
	public score s;
	public int clideNum;
	public string tag;
	public bool isSuccess = false, isFail = false;

	// Use this for initialization
	void Start () {
		s = GameObject.Find("score").GetComponent<score>();
		clideNum = 0;
		tag = "";
		isSuccess = false;
		isFail = false;
	}
	
	// Update is called once per frame
	void Update () {
	}
	void OnTriggerEnter2D(Collider2D other) {

		if(other.gameObject.tag.Equals("success")) {
			if(!isSuccess) {
				print("===trigger enter==");
				isSuccess = true;
				s.success();
				print ("success");
			}
		} else if(!isFail) {
			print("===trigger enter==");
			isFail = true;
			s.fail();
			print ("fail");
		}
	}

	void OnTriggerExit2D(Collider2D other) {
		print("===trigger exit==");
		isSuccess = false;
	}

	void OnCollisionEnter2D(Collision2D other) { 

		if(other.gameObject.tag.Equals("success")) {
			if(!isSuccess) {
				print("===collision enter==");
				isSuccess = true;
				s.success();
			}
		} else if(!isFail) {
			print("===collision enter==");
			isFail = true;
			s.fail();
		}
	}
	void OnCollisionExit2D(Collision2D coll) {
		print("===collision exit==");
		isSuccess = false;
	}

	public void reset() {
		isSuccess = false;
		isFail = false;
	}
}
           

(補充:回過頭看一下這個代碼,由于當時寫的時候對Trigger和Collision了解不夠,發現Trigger和Collision處理的不太優雅;關于Trigger和Collision差別,請參考《【Unity】技巧集合》中的51和52條。)

歡迎頁面

歡迎頁面有個小鳥的動畫,并且能夠響應觸摸後開始遊戲(在isReady.cs中實作)。 小鳥的動畫就是上下擺動的過程,選擇小鳥,然後在Animation界面中,添加Position屬性,并調節如下圖:

【Unity】FlappyBird剖析-附源碼

isReady.cs的代碼如下:

public class isReady : MonoBehaviour {  
    public GameObject road, bird;  
    // Use this for initialization  
    void Start () {  
      
    }  
      
    // Update is called once per frame  
    void Update () {  
        if(Input.GetButtonDown("Fire1")){ //使用者觸摸螢幕之後,就開始遊戲了  
            gameObject.SetActive(false);  
            road.GetComponent<road>().isBegin = true;  
            bird.GetComponent<Rigidbody2D>().isKinematic = false;//歡迎頁面,這裡設定為true,使小鳥不響應重力,開始後要設定為false 
            bird.GetComponent<Animator>().enabled = false;  
        }  
    }  
}  
           

結算頁面

結算頁面開始使隐藏的,等使用者輸了之後,就會播放一個動畫并顯示,當使用者點選play按鈕後,遊戲重置到歡迎頁面。結算頁面涉及到了腳本restart.cs 這裡遊戲重置的時,用到了 BroadcastMessage的技術,即查找所有tag為needReset的對象,并調用其自身以及子對象中的代碼中的reset函數來進行遊戲的重置。代碼如下:

public class restart : MonoBehaviour {  
    public Camera cam2d;  
    public GameObject ready;   
      
    void Update () {  
        if(Input.GetButtonDown("Fire1")){   
            Collider2D h = Physics2D.OverlapPoint(cam2d.ScreenToWorldPoint(Input.mousePosition), (1<<LayerMask.NameToLayer("btn")));    
            if(h) {  // 如果點選play按鈕  
                gameObject.SetActive(false);  
                Time.timeScale = 1;   
                ready.SetActive(true);  
                GameObject[] resets = GameObject.FindGameObjectsWithTag("needReset"); //查找所有tag為needReset的對象 
                foreach(GameObject r in resets) {  
                    r.BroadcastMessage("reset"); //調用其自身以及子對象中的代碼中的reset函數來進行遊戲的重置
                }  
            }    
        }  
    }  
           

關于Physics2D.OverlapPoint的用法,請參考《【 Unity】技巧集合》中的第二點。

添加音效

待續...

聲明:這篇文章中所引用的資源部分來自網絡,僅供學習之用,請勿商業化。

下載下傳位址:http://download.csdn.net/detail/stalendp/6914227

apk下載下傳連結:http://pan.baidu.com/s/1c09rKMc