Unity實現(xiàn)俄羅斯方塊游戲
本文實例為大家分享了Unity實現(xiàn)俄羅斯方塊游戲的具體代碼,供大家參考,具體內(nèi)容如下
一、演示
二、實現(xiàn)思路
創(chuàng)建每一個方塊可移動到的位置點,可以理解為創(chuàng)建一個游戲地圖,從(0,0)點開始依次向x軸和y軸延伸,例如x最大為9,y最大為19,則創(chuàng)建了一個20行10列的地圖
制作每一個形狀的預(yù)制體,Shape是每一個整體形狀,Block是每一塊小方塊,CenterPos代表這個形狀的旋轉(zhuǎn)中心
創(chuàng)建GameController腳本控制游戲邏輯,掛載到面板物體上。創(chuàng)建Shape腳本控制每個形狀的操作,掛載到每個形狀上
在GameController腳本中編寫生成形狀的邏輯
//當(dāng)前方塊 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; }
但是此時形狀是可以無限下落的,到達(dá)底部也不會停止下落,所以我們需要編寫判定能否下落的方法
在GameController腳本編寫方法判定能否下落的邏輯,需要判定兩點,每個方塊的位置是否到達(dá)邊界和每個方塊的位置是否存在于地圖數(shù)組中,注意必須對每個方塊的位置進(jìn)行四舍五入取整操作
public const int row_max = 23; public const int column_max = 10; public Transform[,] mapArray = new Transform[column_max, row_max];//地圖數(shù)組(保存每個方塊的位置信息) /// <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> /// 判斷是否到達(dá)邊界 /// </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; }
現(xiàn)在形狀與形狀之間并不會疊加,而是會重疊在一起,在GameController腳本中編寫方法,將每個方塊位置添加到地圖數(shù)組中(注意必須對每個方塊的位置進(jìn)行四舍五入取整操作)
/// <summary> /// 將每個方塊位置添加到地圖數(shù)組中 /// </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; } }
當(dāng)形狀下落到底部時,將每一個方塊的位置添加到地圖數(shù)組中
/// <summary> /// 下落到底部 /// </summary> private void FallToBottom() { canFall = false; GameController.Instance.CurShape = null; //方塊下落到底部時將每個方塊位置添加到地圖數(shù)組中 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; } }
控制形狀的旋轉(zhuǎn)
private void Update() { //控制旋轉(zhuǎn) ControlRotate(); } /// <summary> /// 控制旋轉(zhuǎn) /// </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, Vector3.forward, 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; } }
判斷整行的消除
先去判斷是否有行滿了,如果有則進(jìn)行消除操作,消除時先刪除掉當(dāng)前行的每一個方塊再將地圖數(shù)組中當(dāng)前行置空,之后再將滿的行的上面行依次向下移動一行
/// <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; //當(dāng)前方塊 public Shape CurShape { get; set; } /// <summary> /// 初始化數(shù)據(jù) /// </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> /// 判斷是否到達(dá)邊界 /// </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> /// 將每個方塊位置添加到地圖數(shù)組中 /// </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 - 1] = 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(); //控制旋轉(zhuǎn) 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> /// 控制旋轉(zhuǎn) /// </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, Vector3.forward, 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; //方塊下落到底部時將每個方塊位置添加到地圖數(shù)組中 GameController.Instance.AddEachBlockTransToMapArray(transform); if (GameController.Instance.IsGameover()) { GameManager.Instance.Gameover(); } } }
更多俄羅斯方塊精彩文章請點擊專題:俄羅斯方塊游戲集合 進(jìn)行學(xué)習(xí)。
更多有趣的經(jīng)典小游戲?qū)崿F(xiàn)專題,分享給大家:
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
c# NPOI 如何在指定單元格導(dǎo)入導(dǎo)出圖片
這篇文章主要介紹了c# NPOI 如何在指定單元格導(dǎo)入導(dǎo)出圖片,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下2021-03-03C#使用channel實現(xiàn)Plc異步任務(wù)之間的通信
在C#的并發(fā)編程中,Channel是一種非常強大的數(shù)據(jù)結(jié)構(gòu),用于在生產(chǎn)者和消費者之間進(jìn)行通信,本文將給大家介紹C#使用channel實現(xiàn)Plc異步任務(wù)之間的通信,文中有相關(guān)的代碼示例供大家參考,感興趣的朋友跟著小編一起來看看吧2024-05-05