您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關(guān)Unity制作俄羅斯方塊游戲的方法,文章內(nèi)容質(zhì)量較高,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
一、使用SpriteRenderer作為小方塊圖片,創(chuàng)建7種由若干個小方塊圖片組成的方塊,如下圖:
Shape-1是一個空物體,其子物體Block、Block(1)、Block(2)、Block(3)是小方塊,Pivot是錨點(空物體),錨點用作于旋轉(zhuǎn)中心點,方塊旋轉(zhuǎn)是以它為中心進行旋轉(zhuǎn)的。旋轉(zhuǎn)方塊的代碼如下:
transform.RotateAround(pivot.position, Vector3.forward, -90);
二、通過測試劃分出一個俄羅斯方塊操作區(qū)域(游戲區(qū)域),在z軸相同 的xy平面上的 每個坐標(biāo)作為二維數(shù)組map的索引,如:map[1,0]保存(1,0,z)坐標(biāo)上的小方塊物體的Transform組件,游戲區(qū)域上x是橫軸、y是縱軸,左下角的小方塊坐標(biāo)(0,0),右上角是的小方塊坐標(biāo)(x-1,y-1)。這樣,將游戲區(qū)域劃分成 一個map數(shù)組后,就可以管理全部小方塊,實現(xiàn)判斷整行滿并消除行,方塊是否可以下落一行,方塊是否可以變形,方塊是否可以水平移動等功能,下面貼出相關(guān)代碼。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Model : MonoBehaviour { public const int NORMAL_ROWS = 20;//最大行數(shù)(這個也是用于判斷游戲結(jié)束邏輯) public const int MAX_ROWS = 23;//最大行數(shù)+3(用于判斷游戲結(jié)束邏輯) public const int MAX_COLUMNS = 10;//最大列數(shù) private Transform[,] map = new Transform[MAX_COLUMNS, MAX_ROWS];//地圖數(shù)組map //下面這些不用管,是UI的一些參數(shù) private int score = 0; private int highScore = 0; private int numbersGame = 0; public int Score { get { return score; } } public int HighScore { get { return highScore; } } public int NumbersGame { get { return numbersGame; } } public bool isDataUpdate = false; private void Awake() { LoadData(); } //檢查一個方塊(如Sharp-1)的位置是否合理,參數(shù)t是方塊的Transform public bool IsValidMapPosition(Transform t) { foreach (Transform child in t) { //子物體帶"Block"字符的標(biāo)簽tag都是"Block",它們就是小方塊 if (child.tag != "Block") continue; //如果遍歷到的子物體是小方塊的話進行下面的邏輯判斷 Vector2 pos = child.position.Round();//Round是我擴展的方法,==貼出來. //若不在地圖范圍內(nèi),則不可用 if (IsInsideMap(pos) == false) return false; //有其他圖形占用著,則不可用 if (map[(int)pos.x, (int)pos.y] != null) { return false;//不可用 } } return true; } //不在地圖范圍內(nèi)返回false,在返回true private bool IsInsideMap(Vector2 pos) { return pos.x >= 0 && pos.x < MAX_COLUMNS && pos.y >= 0; } /// <summary> /// 在方塊進行檢查位置不合理后,會固定自身位置 放入map[,]保存小方塊Block的Transform組件 /// </summary> /// <param name="t">shape的父物體transform</param> public bool PlaceShape(Transform t) { foreach (Transform child in t) { if (child.tag != "Block") continue; Vector2 pos = child.position.Round(); map[(int)pos.x, (int)pos.y] = child; } //放進map后需要檢查整張地圖是否需要消行 return CheckMap(); } /// <summary> /// 檢查地圖 是否需要消除行 /// </summary> private bool CheckMap() { int count = 0;//消行數(shù) for (int i = 0; i < MAX_ROWS; i++) { //若第i行填滿小方塊 if (CheckIsRowFull(i)) { count++; DeleteRow(i);//消除第i行 MoveDownRowsAbove(i + 1);//第i+1行及其上方的所有行向下移動一行(從下到上移動) i--; //因為上面的那一行已經(jīng)移動下來了,這里將i--,目的是為了繼續(xù)檢查上面那一行是否滿,因為for會將i++,這樣就抵消了i++,讓i繼續(xù)保持原樣 } } //下面不用管,是UI部分的邏輯 if (count > 0) { score += count * 100; if(score>highScore) { highScore = score; } isDataUpdate = true; return true; } else { return false; } } //檢查第row行是否滿 private bool CheckIsRowFull(int row) { for (int i = 0; i < MAX_COLUMNS; i++) { if (map[i, row] == null) { return false; } } return true; } private void DeleteRow(int row) { for (int i = 0; i < MAX_COLUMNS; i++) { Destroy(map[i, row].gameObject); map[i, row] = null; } } //將索引row行至最上面的行都往下移動一行(從下開始移動) public void MoveDownRowsAbove(int row) { for (int i = row; i < MAX_ROWS; i++) { MoveDownRow(i); } } //將row行 下移一行,處理了邏輯位置 和 物體位置 private void MoveDownRow(int row) { for (int i = 0; i < MAX_COLUMNS; i++) { if (map[i, row] != null) { map[i, row - 1] = map[i, row];//這里是邏輯上的移動 map[i, row] = null; map[i, row - 1].position += new Vector3(0, -1, 0);//物理上的移動 } } } //判斷游戲結(jié)束邏輯 public bool isGameOver() { for(int i= NORMAL_ROWS; i<MAX_ROWS;i++) { for(int j=0;j<MAX_COLUMNS;j++) { if (map[j, i] != null) { numbersGame++; SaveData(); return true; } } } return false; } public void Restart() { for(int i=0;i<MAX_COLUMNS;i++) { for(int j=0;j<MAX_ROWS;j++) { if(map[i,j]) { Destroy(map[i, j].gameObject); map[i, j] = null; } } } score = 0; } private void LoadData() { highScore= PlayerPrefs.GetInt("HighScore", 0); numbersGame = PlayerPrefs.GetInt("NumbersGame",0); } private void SaveData() { PlayerPrefs.SetInt("HighScore", highScore); PlayerPrefs.SetInt("NumbersGame", numbersGame); } public void ClearData() { score = 0; highScore = 0; numbersGame = 0; SaveData(); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Shape : MonoBehaviour { private GameManager gameManager; private Ctrl ctrl; private bool isPause = false; private bool isSpeedUp = false; private float timer = 0; private float stepTime = 0.8f;//0.8s方塊下落一行 private Transform pivot;//錨點(旋轉(zhuǎn)中心點) private int multiple = 15; private void Awake() { pivot = transform.Find("Pivot"); } private void Update() { if (isPause) return; timer += Time.deltaTime; if(timer>stepTime) { timer = 0; Fall(); } InputControl(); } /// <summary> /// 方塊下落一行邏輯 /// </summary> private void Fall() { //先嘗試將方塊下移一行 Vector3 pos = transform.position; pos.y -= 1; transform.position = pos; //使用Model的方法檢查方塊位置是否合理,若不合理返回false進入if if(ctrl.model.IsValidMapPosition(this.transform)==false) { pos.y += 1;//因為當(dāng)前位置是不可用的,而上一個位置肯定是可用的,所以這里移動回到上一個位置處 transform.position = pos; isPause = true;//暫停當(dāng)前shape的下移 bool isLineclear = ctrl.model.PlaceShape(this.transform);//使用Model的方法固定shape,即放入map數(shù)組保存小方塊信息,并且檢查地圖消除行 if (isLineclear) ctrl.audioManager.PlayLineClear();//isLineclear是true代表消除行了,播放聲音 gameManager.FallDown();//設(shè)置GameManager中的currentShape=null,這樣就會實例化下一個shape方塊,并且更新分?jǐn)?shù)UI return; } ctrl.audioManager.PlayDrop();//方塊固定的聲音 } //輸入控制 private void InputControl() { // if (isSpeedUp) return; float h=0; if(Input.GetKeyDown(KeyCode.LeftArrow)) { h = -1; } else if(Input.GetKeyDown(KeyCode.RightArrow)) { h = 1; } if(h!=0) { //這里和Fall下移邏輯處理手法一樣,不再闡述! Vector3 pos = transform.position; pos.x += h; transform.position = pos; if (ctrl.model.IsValidMapPosition(this.transform) == false) { pos.x -= h; transform.position = pos; } else { ctrl.audioManager.PlayControl(); } } //按鍵盤↑對方塊進行旋轉(zhuǎn)(即變形) if(Input.GetKeyDown(KeyCode.UpArrow)) { //以pivot位置為旋轉(zhuǎn)中心,繞z軸旋轉(zhuǎn)-90° transform.RotateAround(pivot.position, Vector3.forward, -90); //旋轉(zhuǎn)后自然也要檢查下位置是否合理 if (ctrl.model.IsValidMapPosition(this.transform) == false) { //不合理,旋轉(zhuǎn)90° 變回之前那樣子(注意:這個過程是瞬間發(fā)生的,玩家不會看到這個變化過程!) transform.RotateAround(pivot.position, Vector3.forward, 90); } else { ctrl.audioManager.PlayControl(); } } //按鍵盤↓會進行加速方塊下移 if(Input.GetKeyDown(KeyCode.DownArrow)) { isSpeedUp = true; stepTime /= multiple; } } public void Init(Color color,Ctrl ctrl,GameManager gameManager) { this.gameManager = gameManager; this.ctrl = ctrl; foreach(Transform t in transform) { if(t.tag=="Block") { t.GetComponent<SpriteRenderer>().color = color; } } } public void Pause() { isPause = true; } public void Resume() { isPause = false; } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameManager : MonoBehaviour { private Ctrl ctrl; private bool isPause = true;//是否暫停狀態(tài) private Shape currentShape = null; public Shape[] shapes;//shape prefabs public Color[] colors;//shape colors private Transform blockHolder; private void Awake() { ctrl = GetComponent<Ctrl>(); blockHolder = transform.Find("BlockHolder"); } void Update () { if(isPause) { return; } //如果當(dāng)前方塊為空,生成一個方塊(這個currentShape是由Shape if (currentShape == null) { SpawnShape(); } } /// <summary> /// 刪除已經(jīng)沒有小方塊Block的sharp方塊物體,即childCount小于等于1的 /// 并且判斷游戲結(jié)束邏輯 /// </summary> public void FallDown() { currentShape = null;//將當(dāng)前方塊設(shè)置為空,這一步是為了生成新的方塊 //更新UI邏輯 if(ctrl.model.isDataUpdate) { ctrl.view.UpdateGameUI(ctrl.model.Score, ctrl.model.HighScore); } //刪除已經(jīng)沒有小方塊的sharp物體 foreach(Transform t in blockHolder) { if(t.childCount<=1) { Destroy(t.gameObject); } } //判斷游戲結(jié)束 if(ctrl.model.isGameOver()) { PauseGame(); ctrl.view.ShowGameOverUI(ctrl.model.Score); } } public void StartGame() { isPause = false; if (currentShape != null) { currentShape.Resume(); } } public void PauseGame() { isPause = true; if(currentShape!=null) { currentShape.Pause(); } } /// <summary> /// 生成一個方塊sharp /// </summary> void SpawnShape() { //隨機方塊類型 int index = Random.Range(0, shapes.Length);//random create a shape //隨機顏色 int indexColor = Random.Range(0, colors.Length);//random shape color //實例化方塊 currentShape = GameObject.Instantiate(shapes[index]); //放入blockholder物體下 currentShape.transform.parent = blockHolder; //初始化其方塊顏色等工作 currentShape.Init(colors[indexColor],ctrl,this); } /// <summary> /// 刪除當(dāng)前正在下落的方塊 /// </summary> public void ClearShape() { if(currentShape!=null) { Destroy(currentShape.gameObject); currentShape = null; } } }
大致上,俄羅斯方塊的核心邏輯都總結(jié)在這3個腳本,Sharp是處理了方塊的移動邏輯,Model是真正的核心處理方塊的位置是否合理、消行、消行后將上方方塊整體下移一行等邏輯,GameManager是處理游戲結(jié)束之類的邏輯。
以上就是Unity制作俄羅斯方塊游戲的方法,看完之后是否有所收獲呢?如果想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊,感謝各位的閱讀。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。