搭建场景
使用任意方块、纯色瓦片或者其他图形作为背景,设置其大小与目标大小一致或者更大,设置左下角为场景顶点,并放置在(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博客