Unity實現俄羅斯方塊遊戲
本文例項為大家分享了Unity實現俄羅斯方塊遊戲的具體程式碼,供大家參考,具體內容如下
一、演示
二、實現思路
建立每一個方塊可移動到的位置點,可以理解為建立一個遊戲地圖,從(0,0)點開始依次向x軸和y軸延伸,例如x最大為9,y最大為19,則建立了一個20行10列的地圖
製作每一個形狀的預製體,Shape是每一個整體形狀,Block是每一塊小方塊,CenterPos代表這個形狀的旋轉中心
建立GameController指令碼控制遊戲邏輯,掛載到面板物體上。建立Shape指令碼控制每個形狀的操作,掛載到每個形狀上
在GameController指令碼中編寫生成形狀的邏輯
//當前方塊 public Shape CurShape { get; set; } private void Update() { if (CurShape == null) { SpawnBlock(); } } /// <summary> /// 生成方塊 /// </summary> private void SpawnBlock() { int randomType = Random.Range(1,8); GameObject shape = Instantiate(Resources.Load<GameObject>("Prefabs/Item/Shape" + randomType)); CurShape = shape.GetComponent<Shape>(); CurShape.transform.SetParent(transform); CurShape.transform.position = new Vector2(4,20); }
在Shape指令碼中編寫形狀下落的邏輯
private float fallTimer;//下落的計時器 private float fallTimeval = 0.5f;//下落的時間間隔 private void Update() { //控制下落 if (fallTimer >= fallTimeval) { //下落 Fall(); fallTimer = 0; } else { fallTimer += Time.deltaTime; } } /// <summary> /// 下落 /// </summary> private void Fall() { Vector3 curPos = transform.position; Vector3 targetPos = curPos; targetPos.y -= 1; transform.position = targetPos; }
但是此時形狀是可以無限下落的,到達底部也不會停止下落,所以我們需要編寫判定能否下落的方法
在GameController指令碼編寫方法判定能否下落的邏輯,需要判定兩點,每個方塊的位置是否到達邊界和每個方塊的位置是否存在於地圖陣列中,注意必須對每個方塊的位置進行四捨五入取整操作
public const int row_max = 23; public const int column_max = 10; public Transform[,] mapArray = new Transform[column_max,row_max];//地圖陣列(儲存每個方塊的位置資訊) /// <summary> /// 判斷是否為合法的位置 /// </summary> /// <param name="shape">每一個形狀</param> /// <returns></returns> public bool IsValidPos(Transform shape) { foreach (Transform block in shape.transform) { if (block.GetComponent<SpriteRenderer>() == null) continue; Vector2 blockPos = block.transform.position; blockPos = new Vector2(Mathf.RoundToInt(blockPos.x),Mathf.RoundToInt(blockPos.y)); if (IsBorder(blockPos) || mapArray[(int)blockPos.x,(int)blockPos.y] != null) { return false; } } return true; } /// <summary> /// 判斷是否到達邊界 /// </summary> /// <param name="pos">每一個方塊的位置</param> /// <returns></returns> private bool IsBorder(Vector2 blockPos) { if (blockPos.x < 0 || blockPos.x >= column_max || blockPos.y < 0) { return true; } return false; }
在形狀下落的方法中新增判斷去控制是否能夠下落
private bool canFall = true;//能否下落 /// <summary> /// 下落 /// </summary> private void Fall() { if (canFall == false) { return; } Vector3 curPos = transform.position; Vector3 targetPos = curPos; targetPos.y -= 1; transform.position = targetPos; if (GameController.Instance.IsValidPos(transform) == false) { targetPos.y += 1; transform.position = targetPos; FallToBottom(); } } /// <summary> /// 下落到了底部 /// </summary> private void FallToBottom() { canFall = false; GameController.Instance.CurBlock = null; }
現在形狀與形狀之間並不會疊加,而是會重疊在一起,在GameController指令碼中編寫方法,將每個方塊位置新增到地圖陣列中(注意必須對每個方塊的位置進行四捨五入取整操作)
/// <summary> /// 將每個方塊位置新增到地圖陣列中 /// </summary> /// <param name="shapeTran"></param> public void AddEachBlockTransToMapArray(Transform shape) { foreach (Transform block in shape.transform) { if (block.GetComponent<SpriteRenderer>() == null) { continue; } Vector2 blockPos = block.position; blockPos = new Vector2(Mathf.RoundToInt(blockPos.x),Mathf.RoundToInt(blockPos.y)); mapArray[(int)blockPos.x,(int)blockPos.y] = block; } }
當形狀下落到底部時,將每一個方塊的位置新增到地圖陣列中
/// <summary> /// 下落到底部 /// </summary> private void FallToBottom() { canFall = false; GameController.Instance.CurShape = null; //方塊下落到底部時將每個方塊位置新增到地圖陣列中 GameController.Instance.AddEachBlockTransToMapArray(transform); }
控制形狀的左右移動
private void Update() { //控制左右移動 ControlMovement(); } /// <summary> /// 控制左右移動 /// </summary> private void ControlMovement() { float h = 0; if (Input.GetKeyDown(KeyCode.RightArrow)) { h = 1; } else if (Input.GetKeyDown(KeyCode.LeftArrow)) { h = -1; } Vector3 curPos = transform.position; Vector3 targetPos = curPos; targetPos.x += h; transform.position = targetPos; if (GameController.Instance.IsValidPos(transform) == false) { targetPos.x -= h; transform.position = targetPos; } }
控制形狀的旋轉
private void Update() { //控制旋轉 ControlRotate(); } /// <summary> /// 控制旋轉 /// </summary> private void ControlRotate() { if (Input.GetKeyDown(KeyCode.UpArrow)) { Transform rotateTrans = transform.Find("CenterPos"); transform.RotateAround(rotateTrans.position,Vector3.forward,-90); if (GameController.Instance.IsValidPos(transform) == false) { transform.RotateAround(rotateTrans.position,90); } } }
控制加速下落
private void Update() { //控制加速下落 ControlUpspeed(); } /// <summary> /// 控制加速 /// </summary> private void ControlUpspeed() { if (Input.GetKeyDown(KeyCode.DownArrow)) { fallTimeval = 0.05f; } if (Input.GetKeyUp(KeyCode.DownArrow)) { fallTimeval = 0.5f; } }
判斷整行的消除
先去判斷是否有行滿了,如果有則進行消除操作,消除時先刪除掉當前行的每一個方塊再將地圖陣列中當前行置空,之後再將滿的行的上面行依次向下移動一行
/// <summary> /// 檢查是否有行滿了 /// </summary> private void CheckRowFull() { for (int row = 0; row < row_max; row++) { bool isFull = true; for (int column = 0; column < column_max; column++) { if (mapArray[column,row] == null) { isFull = false; break; } } //如果有行滿了 if (isFull) { //————————————————————消除操作 ClearRow(row); MoveDownRow(row + 1); row--; } } } /// <summary> /// 清除行 /// </summary> /// <param name="row">清除的行(滿的行)</param> private void ClearRow(int _row) { for (int coloum = 0; coloum < column_max; coloum++) { Destroy(mapArray[coloum,_row].gameObject); mapArray[coloum,_row] = null; } } /// <summary> /// 將清除的行上面的每一行依次向下移動一行 /// </summary> /// <param name="row">依次移動的起始行(清除的行的上面一行)</param> private void MoveDownRow(int _row) { for (int row = _row; row < row_max; row++) { for (int column = 0; column < column_max; column++) { if (mapArray[column,row] != null) { mapArray[column,row - 1] = mapArray[column,row]; mapArray[column,row] = null; mapArray[column,row - 1].position -= Vector3.up; } } } }
判斷遊戲是否失敗
/// <summary> /// 判斷遊戲失敗 /// </summary> /// <returns></returns> private bool IsGameover() { for (int row = row_max - 3; row < row_max; row++) { for (int column = 0; column < column_max; column++) { if (mapArray[column,row] != null) { return true; } } } return false; }
三、完整程式碼
GameController指令碼,控制遊戲整體邏輯
using UnityEngine; public class GameController : MonoSingleton<GameController> { public const int row_max = 23; public const int column_max = 10; private Transform[,] mapArray; //當前方塊 public Shape CurShape { get; set; } /// <summary> /// 初始化資料 /// </summary> public void InitData() { mapArray = new Transform[column_max,row_max]; } /// <summary> /// 清空地圖 /// </summary> public void ClearMap() { for (int row = 0; row < row_max; row++) { for (int column = 0; column < column_max; column++) { if (mapArray[column,row] != null) { Destroy(mapArray[column,row].gameObject); mapArray[column,row] = null; } } } } private void Update() { //if (GameManager.Instance.IsPause) //{ // return; //} if (CurShape == null) { SpawnBlock(); } } /// <summary> /// 生成方塊 /// </summary> private void SpawnBlock() { Color randomColor = Random.ColorHSV(); int randomType = Random.Range(1,8); GameObject shape = Instantiate(Resources.Load<GameObject>("Prefabs/Item/Shape" + randomType)); CurShape = shape.GetComponent<Shape>(); CurShape.transform.SetParent(transform); CurShape.Init(new Vector2(4,20),randomColor); } /// <summary> /// 判斷是否為合法的位置 /// </summary> /// <param name="shape">每一個形狀</param> /// <returns></returns> public bool IsValidPos(Transform shape) { foreach (Transform block in shape.transform) { if (block.GetComponent<SpriteRenderer>() == null) continue; Vector2 blockPos = block.transform.position; blockPos = new Vector2(Mathf.RoundToInt(blockPos.x),Mathf.RoundToInt(blockPos.y)); if (IsBorder(blockPos) || mapArray[(int)blockPos.x,(int)blockPos.y] != null) { return false; } } return true; } /// <summary> /// 判斷是否到達邊界 /// </summary> /// <param name="pos">每一個方塊的位置</param> /// <returns></returns> private bool IsBorder(Vector2 blockPos) { if (blockPos.x < 0 || blockPos.x >= column_max || blockPos.y < 0) { return true; } return false; } /// <summary> /// 將每個方塊位置新增到地圖陣列中 /// </summary> /// <param name="shapeTran"></param> public void AddEachBlockTransToMapArray(Transform shape) { foreach (Transform block in shape.transform) { if (block.GetComponent<SpriteRenderer>() == null) { continue; } Vector2 blockPos = block.position; blockPos = new Vector2(Mathf.RoundToInt(blockPos.x),Mathf.RoundToInt(blockPos.y)); mapArray[(int)blockPos.x,(int)blockPos.y] = block; } //檢查是否有行滿了 CheckRowFull(); } /// <summary> /// 檢查是否有行滿了 /// </summary> private void CheckRowFull() { for (int row = 0; row < row_max; row++) { bool isFull = true; for (int column = 0; column < column_max; column++) { if (mapArray[column,row] == null) { isFull = false; break; } } //如果有行滿了 if (isFull) { //————————————————————消除操作 ClearRow(row); MoveDownRow(row + 1); row--; } } } /// <summary> /// 清除行 /// </summary> /// <param name="row">清除的行(滿的行)</param> private void ClearRow(int _row) { for (int coloum = 0; coloum < column_max; coloum++) { Destroy(mapArray[coloum,_row].gameObject); mapArray[coloum,_row] = null; } UIManager.Instance.FindUI<UI_Game>().UpdateCurScore(); } /// <summary> /// 將清除的行上面的每一行依次向下移動一行 /// </summary> /// <param name="row">依次移動的起始行(清除的行的上面一行)</param> private void MoveDownRow(int _row) { for (int row = _row; row < row_max; row++) { for (int column = 0; column < column_max; column++) { if (mapArray[column,row] != null) { mapArray[column,row]; mapArray[column,row] = null; mapArray[column,row - 1].position -= Vector3.up; } } } } /// <summary> /// 判斷遊戲失敗 /// </summary> /// <returns></returns> public bool IsGameover() { for (int row = row_max - 3; row < row_max; row++) { for (int column = 0; column < column_max; column++) { if (mapArray[column,row] != null) { return true; } } } return false; } }
Shape指令碼,控制每個形狀的操作
using UnityEngine; public class Shape : MonoBehaviour { private bool canFall = true;//能否下落 private float fallTimer;//下落的計時器 private float fallTimeval = 0.5f;//下落的時間間隔 /// <summary> /// 初始化形狀 /// </summary> /// <param name="pos"></param> /// <param name="color"></param> public void Init(Vector2 pos,Color color) { transform.position = pos; foreach (Transform child in transform) { if (child.GetComponent<SpriteRenderer>() != null) { child.GetComponent<SpriteRenderer>().color = color; } } } private void Update() { if (canFall == false) { return; } //控制下落 if (fallTimer >= fallTimeval) { //下落 Fall(); fallTimer = 0; } else { fallTimer += Time.deltaTime; } //控制加速下落 ControlUpspeed(); //控制左右移動 ControlMovement(); //控制旋轉 ControlRotate(); } /// <summary> /// 控制左右移動 /// </summary> private void ControlMovement() { float h = 0; if (Input.GetKeyDown(KeyCode.RightArrow)) { h = 1; } else if (Input.GetKeyDown(KeyCode.LeftArrow)) { h = -1; } Vector3 curPos = transform.position; Vector3 targetPos = curPos; targetPos.x += h; transform.position = targetPos; if (GameController.Instance.IsValidPos(transform) == false) { targetPos.x -= h; transform.position = targetPos; } } /// <summary> /// 控制旋轉 /// </summary> private void ControlRotate() { if (Input.GetKeyDown(KeyCode.UpArrow)) { Transform rotateTrans = transform.Find("CenterPos"); transform.RotateAround(rotateTrans.position,-90); if (GameController.Instance.IsValidPos(transform) == false) { transform.RotateAround(rotateTrans.position,90); } } } /// <summary> /// 控制加速 /// </summary> private void ControlUpspeed() { if (Input.GetKeyDown(KeyCode.DownArrow)) { fallTimeval = 0.05f; } if (Input.GetKeyUp(KeyCode.DownArrow)) { fallTimeval = 0.5f; } } /// <summary> /// 下落 /// </summary> private void Fall() { Vector3 curPos = transform.position; Vector3 targetPos = curPos; targetPos.y -= 1; transform.position = targetPos; if (GameController.Instance.IsValidPos(transform) == false) { targetPos.y += 1; transform.position = targetPos; FallToBottom(); } } /// <summary> /// 下落到底部 /// </summary> private void FallToBottom() { canFall = false; GameController.Instance.CurShape = null; //方塊下落到底部時將每個方塊位置新增到地圖陣列中 GameController.Instance.AddEachBlockTransToMapArray(transform); if (GameController.Instance.IsGameover()) { GameManager.Instance.Gameover(); } } }
更多俄羅斯方塊精彩文章請點選專題:俄羅斯方塊遊戲集合 進行學習。
更多有趣的經典小遊戲實現專題,分享給大家:
C++經典小遊戲彙總
python經典小遊戲彙總
python俄羅斯方塊遊戲集合
JavaScript經典遊戲 玩不停
javascript經典小遊戲彙總
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。