一文教你零基礎Unity製做像素鳥遊戲

「本文已參與好文召集令活動,點擊查看:後端、大前端雙賽道投稿,2萬元獎池等你挑戰!前端

前言

真的如標題所說肝了好幾天晚上。原本是想着拿以前作的項目直接來寫教程的;寫着寫着發現了不少作的很差的地方,又從新整理修改。其實徹底就是從新作了一個項目。文章重新建工程開始一步步帶你完成零基礎也能製做的像素鳥遊戲。還原經典玩法,一塊兒來嘗試下吧~ios

老規矩,先看下最終實現效果: xiaoguo後端

怎麼樣?有心動嗎?想體驗下本身製做完成的成就感嗎? 下面開始製做過程吧~markdown


一,新建目錄

1.1 新建工程後建立目錄以下圖: 工程目錄 建立的目錄存放資源分別對應:dom

  • Audios:音頻資源, Materials:材質球, Prefabs:預製體, Scenees:遊戲場景, Scripts:腳本資源, Texture:圖片資源

1.2 導入提早準備好的音效和圖片資源並放到對應目錄:【文末提供】 1.3 導入後將UI使用的圖片資源格式修改成Sprite(2D and UI),按住Ctrl選中gameover,score和start三個圖片進行個數修改,以下圖: 而後找到點擊下面的「Apply」按鈕: 修改完成後是以下效果: ide


二,製做材質

2.1 製做材質球(背景,管道和像素鳥)oop

在Materials文件上右鍵,選擇Create --> Material 新建材質球: 而後修改其名稱爲bg,修改其Shader爲Unlit/Transparent: 最後爲其賦值爲背景圖片 --> 點擊Select按鈕 --> 在彈窗中雙擊bg圖片便可: 而後選中bg材質球,使用快捷鍵 Ctrl+D 複製三個材質球: 修改其名稱並重覆上面修改圖片的步驟將其挨個修改成back,brid,tipe (別忘了將材質球的貼圖從新指定一下哦) , 所有處理完的效果以下: post


三,場景搭建

3.1 修改主攝像機屬性:測試

  • 修改其座標爲(0,0,-2),旋轉爲(0,0,0),縮放爲(1,1,1)
  • 將其修改成正交攝像機 (Projection --> Orthographic)

3.2 修改遊戲尺寸 點擊Game視圖下的分辨率選擇面板,在點擊最下面「+」建立新的分辨率,屬性值設置以下:字體

而後再次點擊分辨率選擇面板,選擇剛剛建立的屬性:


四,建立地圖

4.1 建立背景 在Hierarchy空白處右鍵 --> 選擇3D Object --> 選擇Quad 建立出來做爲背景。

若建立出來在Game視圖顯示不出來的話,修改其Position座標爲(0,0,0),修改Scale縮放爲(10,12,1),最後將咱們以前作好的bg材質球賦值給Quad,獲得效果以下:

4.2 建立底部

選中上面建立的背景「Quad」,右鍵 選擇3D Object --> 選擇Quad 在建立一個,而後將back的材質球賦值給它,獲得下圖結果:

4.3 整理位置 將背景「Quad」 重命名爲BG,其子物體重命名爲Back。而後修改BG的Position座標爲(-4,-1,0),使其在最左端出現,效果以下: 4.4 移除碰撞體

選中BG,在Inspector面板「Mesh Collider」組件上,右鍵選擇「Remove Component」來移除碰撞體組件:

同理選中Quad,移除「Mesh Collider」組件。


五,製做管道

5.1 複製背景鋪滿屏幕

選中Hierarchy --> BG 使用快捷鍵 Ctrl+D 複製一份,將其座標調整爲(6,-1,0),調整後效果以下:

5.2 製做一個管道

在新複製出來的BG (1) 下面建立一個空物體命名爲Pipe1做爲上下兩個管子的父物體,設置座標,旋轉爲(0,0,0),縮放爲(1,1,1):

而後選中Pipe1,再按照上面的步驟建立Quad命名爲Up,材質球指定爲tipe;設置其座標(0,0.7,0),旋轉(0,0,0),縮放(0.07,1,1);

而後選中Up,Ctrl+D複製一份,將其座標修改成(0,-0.5,0),其餘屬性都不動,獲得效果以下:

5.3 調整位置

如今可看到如今下面的管子是暴露在地圖外面,調整下下部背景Back的z軸爲-1,獲得效果以下:


六,建立主角

6.1 建立小鳥

按照上面的步驟再次建立一個Quad命名爲Brid,設置Position爲(0,0,-1),而後將材質球指定爲brid,效果以下:

6.2 設置Brid的Tag標籤爲Player:

6.3 修改材質球屬性

修改Tiling(0.3333,1), Offset(0.3333,1) 修改後效果以下:

6.4 讓小鳥飛起來

建立腳本BridHandler 掛載到Brid上,內容編輯以下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BridHandler : MonoBehaviour {

    //單例
    public static BridHandler intance;
    private void Awake()
    {
        intance = this; 
    }
    
    private Renderer _renderer;      // 材質
    
    private float timer;        //計時器,
    private int frameNum =10;   // 每秒顯示幾幀
    private int frameCount;     // 幀的計數器

	void Start () {
        _renderer = this.GetComponent<Renderer>();
    }
	
	// Update is called once per frame
	void Update () {
        timer += Time.deltaTime;  //加上一幀的時間
        if (timer >= 1.0f / frameNum)  //大於1幀所用的時間
        {
            frameCount++;   //幀數增長
            timer -= 1.0f / frameNum;

            //三幀 (0,1,2顯示每一幀畫面)
            int frameIndex = frameCount % 3;

            //更新offset x 屬性
            _renderer.material.SetTextureOffset("_MainTex", new Vector2(0.33333f * frameIndex, 0));
         }
  	}
}
複製代碼

運行後,便可看到小鳥在飛了,效果以下:


七,小鳥動起來

7.1 在主角Brid上面添加Rigidbody剛體組件:

並將其Constraint --> Freeze Rotation 的XZY所有勾選上,爲避免其進行旋轉:

7.2 在BridHandler腳本添加腳本以下:

private Rigidbody _rigidbody;    //剛體組件
private float x = 3;             //小鳥運行速度

void Start () {
    _rigidbody = this.GetComponent<Rigidbody>();
    _rigidbody.useGravity = false;
}

void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
       StartGame();
    }
}

public void StartGame()
{
     _rigidbody.useGravity = true;
     _rigidbody.velocity = new Vector3(x, 0, 0);
}

複製代碼

7.3 而後運行點擊空白處,就能夠看到小鳥動起來了:

7.4 處理報錯 若你的工程運行後報錯(沒報錯可忽略)

勾選Brid的Mesh Collider的 Convex屬性便可:

添加Sphere Collider 組件

調整碰撞體半徑爲0.28,在Scene看下和鳥的顯示輪廓保持一致便可:


八,遊戲狀態控制

8.1 建立GameManager腳本,並掛載到場景中。 添加腳本內容以下:

using UnityEngine;

public enum GAME_STATUS
{
    // 遊戲開啓
    GAME_START = 0,  
    // 遊戲中
    GAME_PLAYING = 1,
    // 遊戲結束
    GAME_END = 2 
}

public class GameManager : MonoBehaviour {
    //單例
    public static GameManager intance;
    private void Awake()
    {
        intance = this; 
    } 
    /// <summary>
    /// 當前遊戲狀態
    /// </summary>
    public GAME_STATUS GameState = GAME_STATUS.GAME_START;    
    // 須要移動的背景
    public Transform moveBgTrans;

    void Start()
    {   
    }

    void Update () {

        switch (GameState)
        {
            case GAME_STATUS.GAME_START: 
                //點擊屏幕 開始遊戲
                if (Input.GetMouseButtonDown(0))
                {
                    GameState = GAME_STATUS.GAME_PLAYING;
                    BridHandler.intance.StartGame();
                }
                break;
            case GAME_STATUS.GAME_PLAYING:
                break;
            case GAME_STATUS.GAME_END:
            
                break;
            default: break;
        }
    }
}
複製代碼

8.2 在Hierarchy上右鍵,建立一個空物體GameObject,並將其名稱修改成GameManager。

8.3 修改BridHandler.cs腳本Update方法,其中添加遊戲狀態控制和小鳥跳的邏輯,具體代碼以下:

void Update()
{
    if (GameManager.intance.GameState == GAME_STATUS.GAME_PLAYING) //能夠跳的狀態
    {
        Vector3 vel = _rigidbody.velocity;
        //跳
        if (Input.GetMouseButtonDown(0))
        {
            vel.x += 0.05f; // 每跳一次增長一點移速
            _rigidbody.velocity = new Vector3(vel.x, 5, vel.z);
            Debug.Log(vel);
        }
        
        //經過遊戲狀態控制,是否播放此動畫
        timer += Time.deltaTime; //加上一幀的時間
        if (timer >= 1.0f / frameNum) //大於1幀所用的時間
        {
            frameCount++; //幀數增長
            timer -= 1.0f / frameNum;
            //三幀 (0,1,2顯示每一幀畫面)
            int frameIndex = frameCount % 3;
            //更新offset x 屬性
            _renderer.material.SetTextureOffset("_MainTex", new Vector2(0.33333f * frameIndex, 0));
        }
    }
}
複製代碼

8.4 修改小鳥的初始位置偏左上角一點,座標爲(-2,1.8,-1): 8.5 此時再次運行,點擊屏幕則小鳥就能夠跳了:


九,攝像機跟隨

9.1 建立腳本FollowBrid,並附加到攝像機上:

using UnityEngine;

//攝像頭跟隨
public class FollowBrid : MonoBehaviour {

    private Transform bridTrans;

	// Use this for initialization
	void Start () {
        bridTrans = GameObject.FindGameObjectWithTag("Player").transform;
    }
	
	// Update is called once per frame
	void Update () {
        Vector3 bridPos = bridTrans.position;        
        float y = bridPos.y - 4.4f;
        //限制攝像機的最大最小位置
        if (y > 1.5f)
        {
            y = 1.5f;
        }
        if (y < 0 )
        {
            y = 0f;        
        }
        this.transform.position = new Vector3(bridPos.x + 3.63223f,y, -10);
    }
}
複製代碼

9.2 運行效果以下:


十,添加碰撞檢測

10.1 給底部加碰撞體: 選中Back添加"Box Collider"碰撞體(注意兩個Back都要添加哦),添加後將其偏移和大小分別設置爲(0,-0.36,0)和(1,0.28,2),以下圖:

10.2 給管子碰撞體: 首先選中Up移除自身的「Mesh Collider」組件,而後添加"Box Collider",修改size爲(1,1,2);Up (1)也作如上操做,這樣上下兩個管子就都有碰撞體了,效果以下:

10.3 添加遊戲接觸檢測,建立腳本PipUporDown,給上面添加碰撞體的幾個遊戲物體都掛載上,這樣小鳥碰到柱子和底部就能夠觸發遊戲結束了,腳本內容以下:

public class PipUporDown : MonoBehaviour {

    private void OnCollisionEnter(Collision collision)
    {
        if(collision.gameObject.tag == "Player")
        {
            // 遊戲結束
            GameManager.intance.GameState = GAME_STATUS.GAME_END;
        }
    }
}
複製代碼

10.4 給管子父物體添加Box Collider 碰撞體,將其中心調整爲(0,0.1,0),大小(0.1,0.2,2),位置設爲兩個管子中間便可。勾選Is Trigger 用於觸發穿過得分:

PS:注意這個碰撞體size值爲(0.1,0.2,2)哦。

10.5 添加管子高度隨機邏輯和得分邏輯: 建立PipeHandler腳本,並掛載BG(1) --> Pipe1 上,用來隨機管子的顯示高度,代碼以下:

using UnityEngine;

public class PipeHandler : MonoBehaviour {

    private void Start()
    {
        RandomPos();
    }

    /// <summary>
    /// 產生隨機數
    /// </summary>
    public void RandomPos()
    {
        float pos_y = Random.Range(-0.1f, -0.1f);
        this.transform.localPosition = new Vector3(this.transform.localPosition.x, pos_y, this.transform.localPosition.z);
    }

    // 穿過觸發得分:
    private void OnTriggerExit(Collider other)
    {
        if(other.tag == "Player")
        {
            Debug.Log("todo...加分");
        }
    }
}
複製代碼

10.6 複製一份管子Pipe1,並將其位置調整爲(0.5,0,0),這樣一個地圖兩個管道了,這個間距比較符合遊戲難度,效果以下圖:


十一,完善背景

11.1 處理背景連續1: 選擇BG (1) 右鍵建立空物體重命名爲「MoveTrrgger」,調整位置爲(1.3,0,-1),併爲其添加Box Collider 組件大小修改成(0.1,1,1),效果以下:

11.2 處理背景連續2: 建立腳本MoveTrigger,將其掛載到10.4建立的「MoveTrrgger」物體上,代碼內容以下:

using UnityEngine;

public class MoveTrigger : MonoBehaviour
{
    public Transform currentBg;

    public PipeHandler pipe1;
    public PipeHandler pipe2;

    private void OnTriggerExit(Collider other)
    {
        // Debug.Log("觸發到背景移動");
        if (other.tag == "Player")
        {
            //前面的背景移動到後面
            //獲取第一個背景位置
            Transform firstbg = GameManager.intance.moveBgTrans;
            //移動
            currentBg.position = new Vector3(firstbg.position.x + 10, currentBg.position.y, currentBg.position.z);
            //更新
            GameManager.intance.moveBgTrans = currentBg;

            pipe1.RandomPos();
            pipe2.RandomPos();
        }
    }
}
複製代碼

11.3 給代碼賦值,賦值狀況以下:

11.4 複製兩份BG(1),獲得BG(2),BG(3)位置分別設置爲(16,0,0),(26,0,0),效果以下:

11.5 給GameManager中 moveBgTrans 屬性賦值

11.6 此時運行則能夠實現背景的無限鏈接了:

至此遊戲主體邏輯已經完成大部分了,還差UI和音效兩部分就完成了哦,加油加油!


十二,UI部分

12.1 分數統計 在Hierarchy空白處右鍵,建立UI --> Text, 並將其錨點調整左上角,文本大小修改成(300,100),字體大小: 42,效果以下:

12.2 遊戲結束 在Canvas下建立Image,做爲遊戲結束的背景板,使其鋪滿屏幕並調整其透明度爲100,並將其重命名爲"UIBG":

在"UIBG"下建立再建立一個Image做爲分數背景板,將score賦值給它:

在"UIBG"下建立兩個文本做爲本局得分和最高分數顯示分別命名爲"Score"和"Best",調整位置文本以下:

12.3 從新開始 在"UIBG"下建立一個Button按鈕做爲從新開始按鈕,隱藏其子物體Text,Image賦值爲start,位置調整以下圖:

12.4 邏輯處理

GameManager類,完整代碼以下:

public class GameManager : MonoBehaviour {
    //單例
    public static GameManager intance;
    private void Awake()
    {
        intance = this; 
    }
 
    /// <summary>
    /// 當前遊戲狀態
    /// </summary>
    public GAME_STATUS GameState = GAME_STATUS.GAME_START;

    // 須要移動的背景
    public Transform moveBgTrans;
    
    // 分數
    public Text ScoreText;
    
    // 遊戲結束UI
    public GameObject GameOverUI;
    // 遊戲結束得分
    public Text GameOverScore;
    // 遊戲結束最高得分
    public Text GameOverBest;
    // 遊戲結束重開按鈕
    public Button GameOverButton;
    
    // 本局得分
    int score = 0;

    void Start()
    {
        GameOverButton.onClick.AddListener(()=>{
            SceneManager.LoadScene(0);
        });
    }

    void Update () {

        switch (GameState)
        {
            case GAME_STATUS.GAME_START: 
                GameOverUI.SetActive(false);
                //點擊屏幕 開始遊戲
                if (Input.GetMouseButtonDown(0))
                {
                    GameState = GAME_STATUS.GAME_PLAYING;
                    BridHandler.intance.StartGame();
                }
                break;
            case GAME_STATUS.GAME_PLAYING:
                break;
            case GAME_STATUS.GAME_END:
                // 遊戲結束,顯示面板 ,維護分數
                GameOverUI.SetActive(true);
                GameOverScore.text = score.ToString();
                GameOverBest.text = PlayerPrefs.GetInt("Best").ToString();
                break;
            default: break;
        }
    }

    // 分數更新
    public void UpdateScore()
    {
        //分數增長
        score++;
        ScoreText.text = "分數:" + score;
        // 維護最高得分
        if (score > PlayerPrefs.GetInt("Best"))
        {
            PlayerPrefs.SetInt("Best", score);
        }
    }
}
複製代碼

給GameManager公有變量拖住賦值:

再修改PipeHandler腳本的OnTriggerExit()方法中寫:

private void OnTriggerExit(Collider other)
{
    if(other.tag == "Player")
    {
        GameManager.intance.UpdateScore();
    }
}
複製代碼

12.5 添加場景

File --> Build Settings --> Add Open Scenes 添加場景,爲打包和重玩邏輯作準備:

至此遊戲主體邏輯已經完成,還差最後一步吧音效添加上就能夠了。


十三,添加音效

13.1 添加背景音樂

在Main Camera上添加"Audio Source"組件

將bgm音效賦值給AudioClip屬性,勾選Loop屬性一遍循環播放:

13.2 添加跳躍音效

在Brid上添加"Audio Source"組件,將sfx_jump音效賦值給AudioClip屬性,取消勾選Play On Awake屬性避免自動播放:

編輯BridHandler腳本,添加下面三行代碼到,下圖位置

// 聲明跳躍音效
private AudioSource Jumpaudio; 
// 賦值
Jumpaudio = this.GetComponent<AudioSource>();
// 播放
Jumpaudio.Play();
複製代碼

13.3 添加得分音效 在Brid上添加"Audio Source"組件,將sfx_point音效賦值給AudioClip屬性,取消勾選Play On Awake屬性避免自動播放:

編輯GameManager腳本,添加下面三行代碼到,下圖位置:

private AudioSource getSecoreAudio;
getSecoreAudio = GetComponent<AudioSource>();
getSecoreAudio.Play();
複製代碼

至此全部遊戲邏輯就都完成了,能夠玩耍了~


十四,寫在結尾

開發環境Unity2019.4.19 (支持5.x - 2021.x全部版本)。

已測試打包平臺 --> Window, Mac, Android ,IOS, WebGL。


終因而製做完成了,雖然文章文字很少,可是結合配圖已經講解的很詳細了。文章很長,建議收藏。原創不易,三連支持下再走吧~

相關文章
相關標籤/搜索