目录
- 前言
- 游戏的准备工作
- 总结一下
- 棋盘
- 渲染画面
- 动画效果
- genCollapse()
- genDownfall()
- genEmerge()
- 整合效果
- genLoop()
- genSwap()
前言
一直对小游戏挺感兴趣的,也尝试着做过一些小游戏,实现游戏是一个不错的提高代码基础水平的方式,因此这次挑战了一个较为困难的小游戏:消消乐。
如果仅仅是从消除方面来制作一个静态的消消乐(只有消除和补充方块的过程,但是没有任何交互和动画)其实并不算太难,只要我们能够想通方块消除(主要是三消)的原理和方块下落后的新位置,我们就可以解决这个问题。但如果我们要同时实现各个状态的动画呢?这就是一个比较复杂的问题了。
本文将从逻辑到实现步骤慢慢详细的介绍该游戏的制作过程。对了,这个游戏是完全用原生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 状态,分为'common' 普通 'collapse' 崩塌 'emerge' 冒出,一共三种
top 棋子上方的棋子对象,值也是一个Cell实例,如果棋子上方没有棋子,那它就是undefined
left 棋子的左侧棋子对象
right 棋子的右侧棋子对象
bottom 棋子的下方棋子对象
instance 根据上述属性刻画出的真实的棋子的DOM对象,最终这些对象会在GameMap中展现出来
在这里我们使用emoji表情来展现这些棋子,我们定义全局变量emojis:
const emojis = ['