花5个小时撸了一个码了个码,源码文档开源
最近羊了个羊爆火网络,其实这个程序本来不难,但是怎么火起来的,可能研究人性方面更多吧。
作为程序员,三天也撸了一个程序,号称"码了个码"! 一、演示地址
https://www.coderutil.com/game/mlgm
二、源代码下载
点赞转发本文后私信【929 】即可下载代码和操作文档三、技术栈
只是为了实现那么要效果,不涉及服务端交互,纯前段实现:H5、CSS3、JS、Jquery、layui 四、游戏逻辑
根本逻辑: 本质上跟以前的大家玩的消消乐逻辑是比较相似的,有一些元素,选中3个可以抵消,直到游戏面板所有元素全部消除可通关;
羊了个羊: 他的通过难点在于是有多层叠加、只有上面压着的元素被拿掉下面的才可以点击。其他的也都是比较常规的设计; 五、实现整体思路
我准备单从比较核心的这几个问题来进行分享:多层叠加面板设计与实现、随机元素分布、元素点击事件、操作结果校验!
5.1 多层面板的实现
这里我选用了一种简单的叠加效果:固定5层叠加,示意图:
5.2 随机元素分布
游戏元素对象创建
首选我需要定义一个游戏元素对象,GameItem: id、name、icon、color
游戏元素个数以及初始化创建
OK,有了元素对象我准备先创建一个Array容器用来保存本局游戏初始化生成的所有元素:
这里遇到一个问题:需要生成多少个元素?需要几种元素?因为我们看到羊了个羊游戏元素对象并不是填充满的,有很多空位。于是乎为了简单,我自己固定定义了一种规则:
按照我现在个字的设计:8 * 8,7 * 7,6 * 6,5 * 5, 4 * 4,下来全部填满有 190个位置;然后我需要空出来一些位置,怎么空这里就有点玄幻了,我设计了这样的规则: (8*8 - 12) + (7*7 - 10) + (6*6 - 8) + (5*5 - 6) + (4*4 - 4)共 150个元素,每三个一组的话有50队可消除的元素;
我这里一共设计了10种元素icon,在简单一点即,没中元素生成15个即150个;
好了,规则清晰了,可以去初始化游戏元素了,定义了一个items数组、initGameData()方法: /*** * 游戏网格 * 1、每层格子抽象为一个矩阵/数组, 共 4 层: [8, 8], [7, 7], [6, 6], [5, 5], [4, 4] * 2、每层初始化规则:(64 - 12) + (49 - 10) + (36 - 8) + (25 - 6) + (16 - 4)共 150个元素 50队 * 3、一共设置了10中图标元素,目前是写死的,固定规则:分别5组 10 * 5 * 3 = 150个 */ function GameGrid() { /*** * 实际元素个数 * @type {number} */ var size = 0; /** 初始化所有元素 **/ var items = new Array(); /*** * 初始化游戏数据 * @returns {any[]} */ this.initGameData = function() { var idx = 0; for (var i = 0; i < this.initSize(); i++) { idx = Math.floor(i / 15); var id = i; var name = idx; var icon = "/game/icon/"+(idx + 1)+".png"; var color = colors[idx]; // 加入游戏元素容器 items.add(new GameItem(id, name, icon, color)); } console.log("完成游戏元素初始化.") return items; } }
游戏元素分布
目前为止,我已经拿到了一个items里面有150个游戏元素的数组对象、还有页面上1 ~ 5 层p面板;现在需要考虑怎么把游戏元素放进去,并且随机、随机位置、随机空位置。
这里先对5个p从数据角度做个抽象:我们把每个p落点抽象为一个矩阵(二维数组),矩阵的值由0,1组成,1代表这个位置有元素、0代表是空位。
我们已最上层为例子来看:
创建5个矩阵、且需要按照我们的上述的规则随机生成5个0 1 矩阵,大小分别为 8 * 8,7 * 7,6 *6, 5*5,4*4: /*** * 初始化游戏网格 */ this.initGameGrid = function () { /*** * 初始化 1 - 5 层矩阵, 每次初始化元素位置都是随机的 * *^* 这里X、Y、矩阵0数量直接写死吧,懒得定义了 */ matrix1 = this.initMatrix(8, 8, 12); matrix2 = this.initMatrix(7, 7, 10); matrix3 = this.initMatrix( 6, 6, 8); matrix4 = this.initMatrix(5, 5, 6); matrix5 = this.initMatrix(4, 4, 4); } /*** * 初始化一个 X * Y 的 0、1 矩阵:1代表有元素,0 无元素, * @param x x轴个数 * @param y y轴个数 * @param emptySize 空个数,即位置0的个数 */ this.initMatrix = function (x, y, emptySize) { // 初始化一个 X * Y 的值为1的矩阵 var matrix = new Array(); for (var i = 0; i < x; i++) { matrix[i] = new Array(); for (var j = 0; j < y; j++) { matrix[i][j] = 1; } } // 随机生成emptySize个随机位置,设置值为0,代表没有元素 var validateArr = new Array(); // 娇艳重复的 for (var i = 0; i < emptySize; i++) { var randomArr = getRandom(x, y, validateArr); matrix[randomArr[0]][randomArr[1]] = 0; } return matrix; }
元素矩阵落位
ok, 矩阵有了,元素也有了,可以做元素填充了:其实就是把items:Array中的150个元素依次顺序的分布到这5个矩阵当中即可。
这里有个小问题: 现在的items:Array元素顺序每次还是固定的,即使矩阵0 1落位是随机的,但是玩两把下来还是会发现规律,解决办法也很简单,在落位之前我们先对items顺序做一次打乱: /*** * 打乱arr顺序 */ this.sort = function () { var length = this.size(), randomIndex, temp; while (length) { randomIndex = Math.floor(Math.random() * (length--)); temp = items[randomIndex]; items[randomIndex] = items[length]; items[length] = temp; } } /**。打乱元素随机位置 **/ this.sort();
到目前为止我们已经完成了面板叠加、随机游戏元素以及游戏元素的落位展示:
5.3 点击事件
这个操作的核心所在,我们需要实现:
1、点击元素将元素移动到底部选中区
2、元素消失后,需要判断被它压着的元素是否暴露出来了,及是否可以点击
3、也就是下一步的校验:判断是否有可以消除的,以及是否Game Over
点击事件这里不展开写了,我们只关心这里的一个难点问题: 点击上层后需要校验下层是否暴露出来:
思路,需要两步:第一步获取需要校验的底层元素、娇艳底层元素是否完全暴露。
点击上层元素(x,y),获取可能被它盖住的底层元素:
在不考虑特殊情况的前提下点击上层(x, y),我们需要校验直接( 注意:每次我们只需要关心直接下层即可 )下层的(x,y)(x+1,y) (x, y+1), (x+1, y+1)
判断下层的四个元素是否完全暴露:
需要注意的是每个元素又可能被上层的4个元素盖住(最大情况下)
到这里基本上就ok了,可能有人会好奇你的点击不可点击是怎么实现的:
我就是给每个元素家里一个span蒙层,每次在点击元素的时候判断这个元素是否有span这个子元素 .disable-click { position: absolute; left: 0px; top: 0px; width: 100%; height: 100%; background-color: black; opacity: 0.6; } $(".grid-game-item").on("click", function () { var disableClick = $(this).children(".disable-click").length > 0; if (disableClick) { // 不能点击 return; } /** 点击后的处理 **/ }
因为点击后的处理,包括上述的底层是否暴露可以点击的代码逻辑比较多,所以就不贴了,感兴趣的兄弟可以自己下载源代码查看:
https://www.coderutil.com/resource/view?resid=RESOURCE_1f801b03cbdd445795ce3c6800fe9002
5.4 操作校验
操作校验主要有三个校验:
1、是否可以消除: 校验选中的元素是否可以消除:根据元素的name属性来判断
2、校验GameOver: 满足7个 & 不满足消除条件
3、游戏通关: 面板内所有元素都消除干净