【Unity游戏】——1.俄罗斯方块
搭建场景
使用任意方块、纯色瓦片或者其他图形作为背景,设置其大小与目标大小一致或者更大,设置左下角为场景顶点,并放置在(0,0)处。调整摄像机至合适位置。
制作游戏预制体
每个方块预制体包含有4个小方块以及一个围绕旋转的节点。先设置一个小方块的坐标为(0,0),在此基础上摆放其他小方块,设置一个合适的旋转节点。
脚本
思路
实现方块自由下落 -> Block.cs
实现方块左右移动、加速下落、旋转 -> Block.cs
限制方块移动范围 -> Block.cs
把方块加入到场景中 -> Board.cs
禁用该方块的脚本 -> Block.cs
检测方块是否满行 -> Board.cs
满行则消除该行 -> Board.cs
下移该行上面的方块 -> Board.cs
实现代码
Block.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum MoveType
{Move,Rotate,MoveDown,MoveRight,MoveLeft,Stop
}public class Block : MonoBehaviour
{private float timer = 0;private float moveSpeed = 0.8f;private float moveDownSpeed = 0.2f;private bool isCanMove = true;private Transform rotatePoint = null;private MoveType moveType = MoveType.Move;private void Start(){Init();}private void Update(){if (isCanMove){if (Input.GetKeyDown(KeyCode.W)){controlMove(MoveType.Rotate);}if (Input.GetKeyDown(KeyCode.S)){controlMove(MoveType.MoveDown);}if (Input.GetKeyUp(KeyCode.S)){controlMove(MoveType.Move);}if (Input.GetKeyDown(KeyCode.A)){controlMove(MoveType.MoveLeft);}if (Input.GetKeyDown(KeyCode.D)){controlMove(MoveType.MoveRight);}TryMove(MoveType moveType);}}// 初始化方块public void Init(){// 初始化旋转点rotatePoint = transform.GetChild(transform.childCount - 1);}// 改变移动类型private void controlMove(MoveType moveType){if (isCanMove){this.moveType = moveType;}}// 方块移动private void TryMove(MoveType moveType = MoveType.Move){switch (moveType){case MoveType.Move:MoveFall();break;case MoveType.Rotate:Rotate();break;case MoveType.MoveDown:MoveDown();break;case MoveType.MoveLeft:MoveLeft();break;case MoveType.MoveRight:MoveRight();break;case MoveType.Stop:Stop();break;}}// 检查方块是否可以移动private bool IsCanMove(){// 检查是否超出边界for (int i = 0; i < transform.childCount - 1; i++){int roundX = Mathf.RoundToInt(transform.GetChild(i).position.x);int roundY = Mathf.RoundToInt(transform.GetChild(i).position.y);if (roundY < 0 || roundX < 0 || roundX >= 10){return false;}// 检查是否与其他方块重叠if (Board.grid[roundX, roundY] != null){return false;}}return true;}// 方块下落private void MoveFall(){timer += Time.deltaTime;if (timer >= moveSpeed){transform.position += Vector3.down;if (!IsCanMove()){transform.position -= Vector3.down;moveType = MoveType.Stop;}timer = 0;}}// 方块加快下落private void MoveDown(){timer += Time.deltaTime;if (timer >= moveDownSpeed){transform.position += Vector3.down;if (!IsCanMove()){transform.position -= Vector3.down;moveType = MoveType.Stop;}timer = 0;}}// 方块向左移动private void MoveLeft(){transform.position += Vector3.left;if (!IsCanMove()){transform.position -= Vector3.left;}moveType = MoveType.Move;}// 方块向右移动private void MoveRight(){transform.position += Vector3.right;if (!IsCanMove()){transform.position -= Vector3.right;}moveType = MoveType.Move;}// 方块旋转private void Rotate(){transform.RotateAround(rotatePoint.position, Vector3.forward, -90);if (!IsCanMove()){transform.RotateAround(rotatePoint.position, Vector3.forward, 90);}moveType = MoveType.Move;}// 方块停止private void Stop(){isCanMove = false;// Debug.Log("Stop");for (int i = 0; i < transform.childCount - 1; i++){int roundX = Mathf.RoundToInt(transform.GetChild(i).position.x);int roundY = Mathf.RoundToInt(transform.GetChild(i).position.y);// 添加方块到Board中Board.Instance.AddBlock(roundX, roundY, transform.GetChild(i));}// 检查游戏是否结束Debug.Log("检查游戏是否结束!");Board.Instance.IsGameOver(transform);// 消除行Debug.Log("检查是否消除行!");Board.Instance.CheckLine();// 生成新方块Board.Instance.SpawnBlock();enabled = false;}
}
Board.cs
这里继承了一个单例模式的泛型类,简而言之就是这里需要创建单例模式。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Board : SingletonMono<Board>
{public static int width = 10;public static int height = 15;public static Transform[,] grid = new Transform[width, height + 5];private int randIndex; // 随机生成方块的索引private float timer = 0f; // 计时器private float countdown = 1f;// 倒计时private GameObject generatorPoint;private Vector3 createPos;private GameObject[] blocks;private List<GameObject> blockList;protected override void Awake(){base.Awake();Init();}private void Start(){// Debug.Log(blockList.Count);SpawnBlock();}private void Update(){timer += Time.deltaTime;if (timer >= countdown){ClearNullBlock();timer = 0;}}// 初始化private void Init(){generatorPoint = new GameObject();createPos = new Vector3(width / 2 - 1, height + 1, 0);generatorPoint.transform.position = createPos;// generatorPoint.transform.parent = transform;blockList = new List<GameObject>();blocks = Resources.LoadAll<GameObject>("Prefabs/Block");foreach (GameObject block in blocks){blockList.Add(block);}}// 生成方块public void SpawnBlock(){randIndex = Random.Range(0, blockList.Count);if (blockList[randIndex].GetComponent<Block>() == null){blockList[randIndex].AddComponent<Block>();}Instantiate(blockList[randIndex], generatorPoint.transform.position, Quaternion.identity, transform);}// 添加方块public void AddBlock(int x, int y, Transform block){grid[x, y] = block.transform;}// 检查游戏是否结束public void IsGameOver(Transform block){if (block.position.y >= createPos.y){Debug.Log("Game Over");}}// 检查是否有可以消除的行public void CheckLine(){for (int i = height - 1; i >= 0; i--){if (IsLineFull(i)){RemoveLine(i);}}}// 检查行是否满private bool IsLineFull(int y){for (int i = 0; i < width; i++){if (grid[i, y] == null){return false;}}return true;}// 消除方块public void RemoveLine(int x){for (int i = 0; i < width; i++){Destroy(grid[i, x].gameObject);grid[i, x] = null;}MoveBlockdown(x);}// 下移方块public void MoveBlockdown(int h){for (int i = h; i < height; i++){for (int j = 0; j < width; j++){if (grid[j, i] != null){grid[j, i - 1] = grid[j, i];grid[j, i] = null;grid[j, i - 1].position += Vector3.down;}}}}// 清理空对象private void ClearNullBlock(){for (int i = 1; i < transform.childCount; i++){if (transform.GetChild(i).childCount == 1){Destroy(transform.GetChild(i).gameObject);}}}
}
了解更多
【日志】unity俄罗斯方块(一)——边界限制检测-CSDN博客【日志】unity俄罗斯方块(二)——方块碰撞检测-CSDN博客