当前位置 : 主页 > 网络编程 > JavaScript >

基于JS实现的消消乐游戏的示例代码

来源:互联网 收集:自由互联 发布时间:2023-01-19
目录 前言 游戏的准备工作 总结一下 棋盘 渲染画面 动画效果 genCollapse() genDownfall() genEmerge() 整合效果 genLoop() genSwap() 前言 一直对小游戏挺感兴趣的,也尝试着做过一些小游戏,实现游
目录
  • 前言
  • 游戏的准备工作
    • 总结一下
  • 棋盘
    • 渲染画面
      • 动画效果
        • 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 = [' 
      上一篇:教你巧用 import.meta 实现热更新的问题
      下一篇:没有了
      网友评论