纯HTML5制作围住神经猫游戏-附源码下载


Posted in Javascript onAugust 23, 2015

HTML5围住神经猫游戏网页版是一款基于HTML5、jquery、Typescript等技术制作的围住神经猫游戏。

先给大家附上演示和源码下载,点击这里  查看演示     下载源码

去年风靡微信朋友圈的小游戏“围住神经猫”,我也试着做了一下。游戏是用Egret引擎开发的,因为Egret是用Typescript语言构建的,因此这里游戏也是用Typescript来开发的。

游戏规则:

点击画面上的灰色格子,慢慢将神经猫围起来抓住。如果猫到达游戏区边缘则游戏失败。

准备素材

在网上搜索“围住神经猫”游戏,打开一个,并打开调试界面,从network中或者resource中把猫、灰色圆圈、橙色圆圈等图片扒下来保存到本地。

需要注意的是,Egret新的MovieCilp架构设计以及MovieClip数据格式标准都与早期有些不同,我从网上扒下来的已经不适用了,根据新的数据格式标准做修改后mc的json文件如下:

{"mc":{
 "stay":{
 "frameRate":20,
 "labels":[],
 "frames":[
   {"res":"stay0000","x":0,"y":0},
   {"res":"stay0001","x":0,"y":0},
   {"res":"stay0002","x":0,"y":0},
   {"res":"stay0003","x":0,"y":0},
   {"res":"stay0004","x":0,"y":0},
   {"res":"stay0005","x":0,"y":0},
   {"res":"stay0006","x":0,"y":0},
   {"res":"stay0007","x":0,"y":0},
   {"res":"stay0008","x":0,"y":0},
   {"res":"stay0009","x":0,"y":0},
   {"res":"stay0010","x":0,"y":0},
   {"res":"stay0011","x":0,"y":0},
   {"res":"stay0012","x":0,"y":0},
   {"res":"stay0013","x":0,"y":0},
   {"res":"stay0014","x":0,"y":0},
   {"res":"stay0015","x":0,"y":0}
 ]
 }},
 "res":{
  "stay0000": {"x":0,"y":0,"w":61,"h":93},
  "stay0001": {"x":61,"y":0,"w":61,"h":93},
  "stay0002": {"x":122,"y":0,"w":61,"h":93},
  "stay0003": {"x":183,"y":0,"w":61,"h":93},
  "stay0004": {"x":0,"y":93,"w":61,"h":93},
  "stay0005": {"x":61,"y":93,"w":61,"h":93},
  "stay0006": {"x":122,"y":93,"w":61,"h":93},
  "stay0007": {"x":183,"y":93,"w":61,"h":93},
  "stay0008": {"x":0,"y":186,"w":61,"h":93},
  "stay0009": {"x":61,"y":186,"w":61,"h":93},
  "stay0010": {"x":122,"y":186,"w":61,"h":93},
  "stay0011": {"x":183,"y":186,"w":61,"h":93},
  "stay0012": {"x":0,"y":279,"w":61,"h":93},
  "stay0013": {"x":61,"y":279,"w":61,"h":93},
  "stay0014": {"x":122,"y":279,"w":61,"h":93},
  "stay0015": {"x":183,"y":279,"w":61,"h":93}
 }}

编写代码

主要总结下我在开发过程中遇到的主要的两个难题。

问题一,猫该如何逃跑?

在这个游戏中,每个圆圈都可能有三种状态

可通行,灰色圆圈表示

有路障,不可行,橙色圆圈表示

被猫占领,灰色圆圈,猫的动画叠置于其上

每当点击了灰色圆圈,就会将其变成橙色圆圈即路障状态,同时猫会紧跟着点击的动作也向周边走一步。

行走方向

游戏区由9*9个圆圈组成,偶数行缩进圆圈半径大小的宽度,这样的布局导致,猫理论上可以有6个行走方向(每次只能走一步),分别是左,左上,右上,右,右下,左下,如这些位置上的圆圈为路障状态,则相应方向不可通行。

如果这六个方向的邻居有五个都为路障,那当然很好选择线路,剩下的那个就是唯一的出路了,但是显然情况不可能如此简单。我们遇到的更多的情况是,六个方向的邻居上,有直接为路障状态的(那自然绝对不走这一步),有是可通行状态的,但是彼此向边缘的可达性不同。

 纯HTML5制作围住神经猫游戏-附源码下载

比如上图中,目前,猫的左方向走三步即可到达边缘,右上、右下向走四步可达,左上、右方向上可走一步但即遇路障,左下方向走三步遇路障。这时候我们当然应该为这六个方向的优先级排个序。

优先级

我是这样设定优先级顺序的:

一路通行的方向>会出现路障的方向,如此图中左、右上、右下>左上、右、左下

一路通行的方向中,离边缘越近优先级越高,如此图中左>右上、右下

会出现路障的方向中,可走的步数越多优先级越高,如此图中左下>右、左上

下面将这些约定的可达性用数值来体现以便比较,设这个值为accessibility,值越大优先级越高。

一路通行的方向

accessibility = 1/stepToEdge; //stepToEdge表示离边缘还有几步

会出现路障的方向

accessibility = (-1)/stepToBlock;//stepToBlock表示离路障的距离

接下来考虑分母如果为0怎么办,在第一种情况中,分母为0,表示猫当前已经在边缘了,那么也不用判断优先级了,游戏已经失败了。第二种情况中,分母为0表示出门即遇路障,这个方向不用考虑了是绝对走不通的,那么它的优先级就定为-1。

这样一轮算下来,六个方向上的accessibility值分别为:

左:1/3

左上:-1

右上:1/4

右:-1

右下:1/4

左下:-1/3

这样比较下来优先级应该是左>右上>右下>左下>左上>右。

为什么左上与右,右上与右下,这两组内部的值明明一样,我们依然是排出了顺序呢?只是因为我们计算是从左方向开始顺时针旋转的。如果值一样,那就看出现的顺序了。

所以在上图中这种情况下,猫会向左走一步。

问题二,如何判断猫被围住了?

在网上玩这个游戏的时候,我发现当猫被围住的时候会换成一种“被围住”的动作,那么该如何判断猫被围住了,然后改变它的动作动画?

“被围住”与“被抓住”不一样,它早于“被抓住”的状态。当猫无路可走的时候,它就“被抓住”了,游戏获胜。而“被围住”指的是猫暂时还有路可走,但是已经被包围住了,垂死挣扎而已,如下图。

 纯HTML5制作围住神经猫游戏-附源码下载

我的思路是这样的:

从猫当前的位置找六个方向中可通行的邻居,然后从这些邻居出发,再找它们各自的可通行邻居,一直这样找下去,一边找的过程中,一边判断当前已经找到的邻居中有没有处在游戏区边缘的,如果有,那么寻找过程提前结束,判断结果是:猫没有被围住。如果直到所有的可通行邻居都找到了,里面都没有处在游戏区边缘的,那么判断结果是:猫被围住了。
接下来用代码实现这个判断过程。

首先,需要准备一个方法,判断圆圈是否已经处在圆圈边缘了,假设这个方法名及参数如下,内部实现比较简单这里就不贴了。

/*
判断传入的circle是否在边界上
 */
private isCircleAtEdge(circle:Circle):boolean {
 ...
}

再准备一个方法,获取某圆圈周围某方向的邻居。

private getCircleNeighbor(circle:Circle,direction:Direction):Circle{
  ...
}

最后,是判断的核心方法。

/*
能否在circle位置出发找到路线到达边缘
*/
private canExitAt(circle:Circle):boolean{
 var ignoreArr=[];//不用再处理的circle集合
 var toDealWithArr=[circle];//还需进行判断的circle集合
 while(true){
  if(toDealWithArr.length<1){
   return false;
  }else{
   var _first=toDealWithArr.shift();
   ignoreArr.push(_first);
   if(_first.getStatus()!==CircleStatus.Blocked&&this.isCircleAtEdge(_first)){
    return true;
   }else{
    for(var i=Direction.LEFT;i<=Direction.BOTTOM_LEFT;i++){
     var nbr=this.getCircleNeighbor(_first,i);
     if(!(ignoreArr.indexOf(nbr)>-1||toDealWithArr.indexOf(nbr)>-1))
     if(nbr.getStatus()!==CircleStatus.Available){
      ignoreArr.push(nbr);
     }else{
      toDealWithArr.push(nbr);
     }
    }
   }
  }
 }
}

在方法体的最开始,准备好两个数组,一个用来存储不用再处理的圆圈集合ignoreArr,另一个用来存储还需要进行判断的圆圈集合toDealWithArr。每找到一个可通行的邻居,首先要判断它是不是第一次出现(因为几个圆圈可能会有共同的邻居,所以一个圆圈可能因为它是多个圆圈的邻居而被找到多次),判断的标准就是它有没有出现在ignoreArr或toDealWithArr里,如果没有那么就是第一次出现,如果它是路障,那么塞到ignoreArr,如果不是路障,那么推入toDealWithArr尾部等待判断。

每次循环开始时,我们会从toDealWithArr头部弹出一个圆圈对象,对它是否在边缘做判断,如果是,那么返回true跳出循环,猫没有被围住,它可以通过某条路线到达边缘。如果toDealWithArr全部判断完了都不在边缘,那么返回false,猫被围住了,它的直接邻居及众多间接邻居中没有一个是在边缘的。

Javascript 相关文章推荐
静态页面下用javascript操作ACCESS数据库(读增改删)的代码
May 14 Javascript
JQuery 动画卷页 返回顶部 动画特效(兼容Chrome)
Feb 15 Javascript
JavaScript中setAttribute用法介绍
Jul 20 Javascript
使用jquery菜单插件HoverTree仿京东无限级菜单
Dec 18 Javascript
新手快速学习JavaScript免费教程资源汇总
Jun 25 Javascript
Treegrid的动态加载实例代码
Apr 29 Javascript
JS实现太极旋转思路分析
Dec 09 Javascript
JS实现的添加弹出层并完成锁屏操作示例
Apr 07 Javascript
jQuery+C#实现参数RSA加密传输功能【附jsencrypt.js下载】
Jun 26 jQuery
input 标签实现输入框带提示文字效果(两种方法)
Oct 09 Javascript
ionic3双击返回退出应用的方法
Sep 17 Javascript
解决vue使用vant轮播组件swipe + flex时文字抖动问题
Jan 07 Vue.js
javascript中Array()数组函数详解
Aug 23 #Javascript
jquery+css实现的红色线条横向二级菜单效果
Aug 22 #Javascript
js实现的二级横向菜单条实例
Aug 22 #Javascript
JS实现网页顶部向下滑出的全国城市切换导航效果
Aug 22 #Javascript
jquery实现点击向下展开菜单项(伸缩导航)效果
Aug 22 #Javascript
jquery实现很酷的网页顶部图标下拉菜单效果
Aug 22 #Javascript
jQuery实现向下滑出的二级菜单效果实例
Aug 22 #Javascript
You might like
PHP学习 变量使用总结
2011/03/24 PHP
php利用gd库为图片添加水印
2016/11/09 PHP
Laravel框架学习笔记之批量更新数据功能
2019/05/30 PHP
laravel框架中视图的基本使用方法分析
2019/11/23 PHP
用jquery ajax获取网站Alexa排名的代码
2009/12/12 Javascript
初窥JQuery(一)jquery选择符 必备知识点
2010/11/25 Javascript
javascript中的取反再取反~~没有意义
2014/04/06 Javascript
Jquery给基本控件的取值、赋值示例
2014/05/23 Javascript
jQuery显示和隐藏 常用的状态判断方法
2015/01/29 Javascript
js实现头像图片切割缩放及无刷新上传图片的方法
2015/07/17 Javascript
JS如何实现文本框随文本的长度而增长
2015/07/30 Javascript
Js的Array数组对象详解
2016/02/22 Javascript
深入学习AngularJS中数据的双向绑定机制
2016/03/04 Javascript
Angular.js中$apply()和$digest()的深入理解
2016/10/13 Javascript
ES6学习之变量的解构赋值
2017/02/12 Javascript
React-router 4 按需加载的实现方式及原理详解
2017/05/25 Javascript
angularjs实现猜大小功能
2017/10/23 Javascript
使用webpack3.0配置webpack-dev-server教程
2018/05/29 Javascript
js动态设置select下拉菜单的默认选中项实例
2018/08/21 Javascript
使用form-create动态生成vue自定义组件和嵌套表单组件
2019/01/18 Javascript
11个教程中不常被提及的JavaScript小技巧(推荐)
2019/04/17 Javascript
vue-cli3.0实现一个多页面应用的历奇经历记录总结
2020/03/16 Javascript
vue 封装 Adminlte3组件的实现
2020/03/18 Javascript
JavaScript使用prototype属性实现继承操作示例
2020/05/22 Javascript
Django实现图片文字同时提交的方法
2015/05/26 Python
在Django的form中使用CSS进行设计的方法
2015/07/18 Python
python 3.5下xadmin的使用及修复源码bug
2017/05/10 Python
Python3.X 线程中信号量的使用方法示例
2017/07/24 Python
python中类和实例如何绑定属性与方法示例详解
2017/08/18 Python
python的schedule定时任务模块二次封装方法
2019/02/19 Python
详解用python写网络爬虫-爬取新浪微博评论
2019/05/10 Python
python实现画循环圆
2019/11/23 Python
Python字符串格式化f-string多种功能实现
2020/05/07 Python
简单了解如何封装自己的Python包
2020/07/08 Python
如何利用python读取micaps文件详解
2020/10/18 Python
大二学生自我检讨书
2014/10/23 职场文书