前言
一直对小游戏挺感兴趣的,也尝试着做过一些小游戏,实现游戏是一个不错的提高代码基础水平的方式,因此这次挑战了一个较为困难的小游戏:消消乐。
如果仅仅是从消除方面来制作一个静态的消消乐(只有消除和补充方块的过程,但是没有任何交互和动画)其实并不算太难,只要我们能够想通方块消除(主要是三消)的原理和方块下落后的新位置,我们就可以解决这个问题。但如果我们要同时实现各个状态的动画呢?这就是一个比较复杂的问题了。
“我自己是一名从事了6年web前端开发的老程序员,今年年初我花了一个月整理了一份最适合2022年自学的web前端全套培训教程(视频+源码+笔记+项目实战),从最基础的HTML+CSS+JS到移动端HTML5以及各种框架和新技术都有整理,打包给每一位前端小伙伴,这里是前端学习者聚集地,欢迎初学和进阶中的小伙伴(所有前端教程关注我的微信公众号:web前端学习圈,关注后回复“web”即可领取
本文将从逻辑到实现步骤慢慢详细的介绍该游戏的制作过程。对了,这个游戏是完全用原生js实现的,考虑到要将游戏成品发给一些不懂程序的朋友,因此没做代码拆分,所有的代码均在一个单一的html文件上。
该游戏已放在codepen上面,点击查看游戏在线演示。有兴趣的小伙伴可以查看,如果能点一个小爱心更好呢。
游戏目前仅做了最简单的三消功能,如果有时间可以把其他交互也写出来。
游戏的准备工作
首先我们思考游戏的机制:游戏有一个“棋盘”,是一个n*m的矩形。矩形中有若干个颜色(或者类型)的方块,相同类型的方块,在一个横行或者竖行,有3个或者3个以上时,便会消除。
在部分方块消除后,这些方块上方的方块便会下坠并补充这些消除方块的缺口,同时,上方又会生成新的方块来补充下坠方块的位置,在执行完上述步骤后,便完成了一个游戏过程的循环。
总结一下
一共有3个步骤,将生成一个游戏循环:消除,下坠,补充。在补充后,如果方块们无法自然消除,循环便会结束。这时候就需要玩家来交还两个相邻方块,来人为制造可以消除的情况,以重新进入循环。
如果玩家的交换并不能使得重新进入消除循环呢?那么这个交换将重新换回原样。
基本机制思考完毕,现在开始代码构建:
首先考虑到方块们会进行大量的动画过程(主要是四种:移动,消除,下坠,冒出),于是我们使用绝对定位来安排这些方块,并且在其行类样式当中添加属性:transition,用css来实现这些方块的动画。具体实现如下:
移动:通过left和top值的改变,控制方块的移动。
消除:通过修改transform,修改为scale(0),以实现消除的动画。
下坠:通过top值的改变,同移动。
冒出:通过修改transform,将本来为scale(0)的transform值修改为scale(1),以实现冒出的动画。
考虑到这些动画是一个接一个的执行,我们应该是需要使用异步来执行这些动画的,当然使用回调函数也能实现,但回调函数可能会很麻烦,所以我们使用Promise对象来解决这些麻烦。
废话太多了!现在开始写代码。
代码实现:棋盘
首先是棋盘的实现,简单操作就定义了一个棋盘的整体结构出来。当然,给#app添加position:relative或者position:absolute是必不可少的。
<body>
<div id="app">
</div>
</body>
接下来我们用面向对象的思想,构造棋盘的具体内容:
首先一个棋盘有它的宽度和高度(x和y),我们还同时还定义它的方块大小(size)。
matrix则为之后要用到的,存放不同type的矩阵,types则为所有的棋子种类。
除此之外,还有几个属性,这些之后再说。
class GameMap {
constructor(x, y, size) {
this.x = x;
this.y = y;
this.size = size;
this.matrix = [];
this.useSwap = false;
this.handleable = true;
this.types = emojis.length;
}
}
我们再来构造“棋子”,棋子的属性很多,所以我们通过仅将options作为参数,并将options解构,来赋予棋子这些属性,这些属性分别是
class Cell {
constructor(options) {
const { position, status, type, left, top, right, bottom, instance } = options;
this.type = type;
this.position = position;
this.status = status;
this.top = top;
this.bottom = bottom;
this.left = left;
this.right = right;
this.instance = instance;
}
}
type 类型(颜色),number类型表示,相同的number即被视为同样的类型。
position 位置,用一个形如[m,n]的二维数组存储
status 状态,分为'comm