之前就想着试着开发一个“俄罗斯方块”的简单游戏,但是一直没有动手,主要之前只是光想没动手的缘故,导致一直拖延着这个想法。事实证明能动手就不要按喇叭。
下面就是在下开发后的一些想法。
1、预览
俄罗斯方块这个游戏基本都是有一个预览的功能,就是可以在游戏界面上看到下一块出现的方块是什么。
所以需要一个相当于预览的功能,这个预览功能里面会是一个随机
cubeReady () {
let random = parseInt(Math.random() * 5);
this.cubeReadyType = random;
switch (random) {
case 0: this.cubuBuildLong(); break;
case 1: this.cubuBuildBlock(); break;
case 2: this.cubuBuildConvex(); break;
case 3: this.cubuBuildSeven(); break;
case 4: this.cubuBuildAniSeven(); break;
default: break;
}
}
这个随机的意思是随机【正方形方块】,【长条】,【凸形块】,【7字块】,【反7字块】这5中形状的构建。
构建的方式并不难,不过是将4个小方块组好上述五种形式。
在代码中的cubeReadyType
是为了纪录下预览时构建的方块的类型,方便于定义我们在游戏中真正操作的方块的类型(游戏重新生成的模块,以及旋转时候的使用)。
2、游戏操作的方块
游戏操作的方块,我的做法是将预览时候构建的方块将他们的坐标集体向左移动到游戏操作界面然后纪录在一个新的数组中。
(很丑哈)在这张图中左右不同的原因的是,预览是下一阶段的方块,所以我在游戏开始和模块触底的时候,都是先调用预览功能,再调用游戏中模块构建方法,再调用预览功能。
3、触底,触碰左右边界
这个判断比较简单,但是我的做法比较呆,因为我的界面宽度是固定,所以我纪录下了边界的宽度,这样就有了左边界的坐标和右边界的坐标,以及底部的坐标。
至于判断,我是另起了一个方法,然后在移动的时候判断.
// 向下加速
goDown () {
let bottomFlag = this.cubeBoundary().bottomFlag; // 是否到达边界
let touchFlag = this.touchBottom(); // 是否触底
if (!bottomFlag && !touchFlag) {
for (let i = 0; i < 4; i++) {
this.cubeList[i].top += 20;
}
}
}
bottomFlag 个人觉得可以去除,因为当时写代码的时候,并没有去考虑如果底下已经堆积了方块的情况,所以将触底统一写在了是否触碰到了边界的方法cubeBoundary
中。
触底touchBottom
方法就是指触碰到了底下已经存在了的方块的意思以及下边界。
4、旋转方块
每种形式的方块旋转后的样子是不同的,除了正方形方块。
所以我另写了四个方法来操作其余四种方块的旋转。以下是个人旋转的处理。
对于长条方块的处理,我是先判断他们此时的状态,是横着的还是竖着的
if (this.cubeList[0].left == this.cubeList[1].left) {
changeKey = 'left';
constantKey = 'top';
}
if (this.cubeList[0].top == this.cubeList[1].top) {
changeKey = 'top';
constantKey = 'left'
}
每次旋转都是按照第三个小方块为中心旋转,我的旋转方式是通过改变坐标来实现,因为我的方块组成是由一个数组cubeList
来搭建。这个数组中的项是一个含有left,top的对象。changeKey
表示的是要改变的key,constantKey
表示的是保持与第三个小方块一致的key。
凸形方块的旋转,我是将凸形方块底部三个小方块中的中间小方块作为旋转点。旋转的过程中,我以三种情况来进行,
if (this.cubeList[i].left < this.cubeList[1].left) {
this.cubeList[i].left = this.cubeList[1].left;
this.cubeList[i].top = this.cubeList[1].top - 20;
} else if (this.cubeList[i].left == this.cubeList[1].left) {
if (this.cubeList[i].top < this.cubeList[1].top) {
this.cubeList[i].left = this.cubeList[1].left + 20;
} else {
this.cubeList[i].left = this.cubeList[1].left - 20;
}
this.cubeList[i].top = this.cubeList[1].top;
} else {
this.cubeList[i].left = this.cubeList[1].left;
this.cubeList[i].top = this.cubeList[1].top + 20;
}
根据其余三个小方块与那中间小方块的left的比值来进行变换。
7形方块和反7形的旋转,则是以7字顺数第三个作为旋转点,同样也是按照left的比值来判断,唯一要注意的地方是这两种形状在横躺状态下top的比值。
以上便是我旋转的思路,只不过这样的方式很冗杂笨重,所以就不贴上代码了。
5、消除
所谓的消除,我的思路是,把相同top值的小方块,如果他们刚好挤满了一行,那就把这一行消除掉。
我在进行消除前,把我触底时堆积的数组allList
进行一个排序,让他们根据top值由大到小排序。目的是方便在消除后,将后续循环到的小方块向下移位。只要有消除,后面的项便将top值加上20(因为我的小方块宽高为20)。
allList
在每一次触底的时候都会添加项进去,而这些项就是在游戏界面中未被消除的部分。
6、背景图
上面的界面图中,背景是网格的状态,这并不是一张图片,也不是众多span
标签之类构建的。
而是使用css来进行构建的。
background-image: linear-gradient(90deg, rgba(200, 0, 0, 0.15) 10%, rgba(0, 0, 0, 0) 10%),
linear-gradient(rgba(200, 0, 0, 0.15) 10%, rgba(0, 0, 0, 0) 10%);
background-size: 20px 20px;
以上6点便是此次俄罗斯方块编写的一些“读后感”,总体来讲,还有很多可以提升的地方,功能的实现应该有更加简洁有效的方式。
第一次写这样的总结,写的实属**,还望看到的人见谅,也希望大家也能帮忙提些更好的实现方法。