当前位置: 首页 > news >正文

【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博客

http://www.xdnf.cn/news/1205209.html

相关文章:

  • 【大模型LLM】梯度累积(Gradient Accumulation)原理详解
  • 软件设计师-知识点记录
  • creating and using sequence
  • AI论文阅读方法+arixiv
  • Redis未授权访问的利用的几种方法原理以及条件
  • yolo 目标检测600类目标
  • STM32中集成USB驱动
  • STM32 USB HOST 驱动FT232 USB转串
  • Android 解析 TrafficDescriptor 的 OSAPP 信息
  • OpenLayers 综合案例-区域掩膜
  • [机缘参悟-237]:AI人工神经网络与人类的神经网络工作原理的相似性
  • SpringBoot数学实例:高等数学实战
  • 7.项目起步(1)
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现面部口罩的检测识别(C#代码,UI界面版)
  • 数据结构(动态数组)
  • HTML应用指南:利用GET请求获取全国小米之家门店位置信息
  • 第4章唯一ID生成器——4.2 单调递增的唯一ID
  • 【Zustand】从复杂到简洁:Zustand 状态管理简化实战指南
  • 绿算技术携手昇腾发布高性能全闪硬盘缓存设备,推动AI大模型降本增效
  • Laravel 分页方案整理
  • 安宝特新闻丨Vuzix与Wyr.Ai合作推出基于M400眼镜的全新一代质检平台
  • springboot校园外卖配送系统
  • 【设计模式】状态模式 (状态对象(Objects for States))
  • Linux应用程序架构与软件包管理
  • Redis实战(3)-- 高级数据结构zset
  • MySQL5.7主从延迟高排查优化思路
  • Qt:盒子模型的理解
  • 电流变送器电路的分析与计算
  • TCPIP之常用协议
  • LeetCode--50.Pow(x,n)