【Unity】俄罗斯方块

张开发
2026/4/12 1:58:15 15 分钟阅读

分享文章

【Unity】俄罗斯方块
要有意识的开始让自己比较全局视角地做一个项目所以这个项目先从游戏玩法等说明开始虽然俄罗斯方块是所有人都清楚的但正是如此才可以更直接的看出差异游戏规则1. 有一块用于摆放方块的平面虚拟场地其标准大小行宽为10列高为20以一个小方块为一个单位。2. 有一组由4个方块组成的规则图形​共有7种分别以I、J、L、S、T、Z、O这7个字母的形状来命名如图3-2所示。3. 玩家可以进行如下操作。◆ 以90度为单位旋转方块◆ 以格子为单位左右移动方块◆ 让方块加速下落。方块移到区域最下方或者着地到其他方块上无法移动时就会固定在该处而新的方块会出现在区域上方开始落下。4. 当区域中的某一行格子全部由方块填满则该行方块会消失并成为玩家的得分。删除的行越多得分越高。当方块堆到区域最上方而无法消除时则该游戏结束。设计思路1、游戏平台的生成一般都是竖着放所以可以在平台左侧或右侧增加个面板统计分数或提示下一个方块的形状大概是下面这样的2、随机生成方块用一个数组存放7种方块组用生成随机数的方式选择生成方块组形状增强功能的话可以做个hold将某个方块存储下来以及显示下一个方块的形状这样的增强功能但基础版就是随机生成3、方块上挂载脚本可以旋转加速下落边界判断还有消除4、消除得分统计我看了下传统的实现思路是把场地看作是一个10*20的坐标系每一个方块由4个子方块构成每个方块就是坐标系中的一个点通过把所有方块放在一个10*20的数组里,最后通过遍历数组判断是否一整行都有方块有的话就消除方块并把数据都往下移动一个位置。程序实现没想到这个过程耗时4-5个小时接下来看下有哪些收获1、因为实现的思路是用格子整个容器是一个10*20的200个格子的容器边界就直接通过宽高判断sprite的position是否超出这个地方也是下面讲的要偏移的原因否则会出现sprite有一半卡在外面的情况但是我们的Sprite方块是以中心点去看坐标的所以我们需要把容器的左下角作为零点坐标但是因为sprite的中心点也在零点坐标就需要给整个容器偏移下使得方块可以在容器内对齐走格子不会出现错位的情况所以在看到很多教程上面相机的position都有个0.5的偏移才知道是为了对齐教程上也没细说。这个地方视频比较好理解可以参考ytb上的这个https://www.youtube.com/watch?vT5P8ohdxDjo 3:35 开始的说明2、在sprite的方块上直接挂脚本负责方块的左右移动按“S”键向下的时候给个加速按“W”键向上的时候给方块做旋转1加速这个地方直接用时间间隔判断即每1S向下移动一个身位判断如果按了“S”则把时间间隔改短这个地方视频里的写法很好。if(Time.time - lastTime (Input.GetKey(KeyCode.S)? fallTime/10: fallTime)) { this.transform.position new Vector3(0,-1,0); if (!ValidMove()) { this.transform.position - new Vector3(0,-1,0); } lastTime Time.time; }2旋转这个地方也花了一些时间这个地方主要是本地坐标和世界坐标的知识点因为方块是不规则的形状所以要根据图形的重心点进行旋转实现方式就是给每个prefab配置一个旋转点因为旋转点是基于object本地的位置然后再使transform.TransformPoint(transPoint) 转换成世界坐标用transform.RotateAround 进行旋转else if (Input.GetKeyDown(KeyCode.W)) { this.transform.RotateAround(transform.TransformPoint(transPoint),new Vector3(0,0,1),90); if(!ValidMove()) this.transform.RotateAround(transform.TransformPoint(transPoint),new Vector3(0,0,1),-90); }3最后一个点是让sprite之间可以叠起来这个我做之前就预想过是遍历数组的形式来实现通过把所有的sprite最终的位置每个子方块都记录到数组里这样就可以知道哪个地方可以继续叠加哪个不行了本来还想说形状不一致应该很难写但其实一个方法就可以了public void AddTOGrid() { foreach(Transform children in transform) { int roundX Mathf.RoundToInt(children.transform.position.x); int roundY Mathf.RoundToInt(children.transform.position.y); grid[roundX,roundY] children; } }思路是在方块下落的update里判断最后落底的那一步如果没有办法再移动了说明定型了就把位置信息写到数组里因为有个判断边界的方法再在这个方法里面加个判断除了触碰到边界如果这个数组的位置已经有占位的了就相当于也是一个边界了这样不规则的图形也是一样有一个子方块碰到的话就可以停止了秒啊最后消除的思路就是把数组从上往下遍历同一行都有方块占了的话就删除接着有2种玩法一个是悬空的方块不会往下落一个是会往下落对应的去更新数组即可因为数据上是记录的Transform组件移除后就可以对应删除object。这块没写等后面接着弄。把我做的这个放github上有需要的自取。https://github.com/DeanShi1992/TETRIS-Test

更多文章