「本文已參與好文召集令活動,點擊查看:後端、大前端雙賽道投稿,2萬元獎池等你挑戰!」前端
真的如標題所說肝了好幾天晚上。原本是想着拿以前作的項目直接來寫教程的;寫着寫着發現了不少作的很差的地方,又從新整理修改。其實徹底就是從新作了一個項目。文章重新建工程開始一步步帶你完成零基礎也能製做的像素鳥遊戲。還原經典玩法,一塊兒來嘗試下吧~ios
老規矩,先看下最終實現效果: 後端
怎麼樣?有心動嗎?想體驗下本身製做完成的成就感嗎? 下面開始製做過程吧~markdown
1.1 新建工程後建立目錄以下圖: 建立的目錄存放資源分別對應:dom
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 修改主攝像機屬性:測試
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和音效兩部分就完成了哦,加油加油!
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。
終因而製做完成了,雖然文章文字很少,可是結合配圖已經講解的很詳細了。文章很長,建議收藏。原創不易,三連支持下再走吧~