首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript贪食蛇游戏制作详解

JavaScript贪食蛇游戏制作详解

作者头像
用户1608022
发布2018-04-11 14:10:49
1.1K0
发布2018-04-11 14:10:49
举报

之前闲时开发过一个简单的网页版贪食蛇游戏程序,现在把程序的实现思路写下来,供有兴趣同学参考阅读。

代码的实现比较简单,整个程序由三个类,一组常量和一些游戏逻辑以外的初始化和控制代码组成,总共400多行JavaScript。

游戏中的三个类分别是「组成蛇身体的节点」「蛇」「贪食蛇游戏」的抽象,常量用来表示游戏中的各种状态。

先从常量讲起

首先,可以把游戏的逻辑想象成一个不断变换的数据结构,把游戏的界面想象成由一组像素格子组成的长方形,界面渲染程序定时读取游戏数据结构,将数据结构中不同的值表示成不同的颜色并画在游戏界面上。

因此,常量TRANSVERSEVERTICAL分别代表游戏数据结构的最大边界,也就是游戏界面横向和纵向的像素点个数。

常量LEFT、RIGHT、TOP、BOTTOM分别代表贪食蛇上下左右的走向

常量GAME_START、GAME_STOP、GAME_OVER代表游戏的三个状态,游戏进行中、游戏暂停中、游戏结束

游戏中的三个类是游戏的逻辑实现,相对复杂

贪食蛇蛇身由一系列相互引用的节点组成,是一个链表结构,如下图

每一个节点是SnakeNode类的一个实例

蛇身节点有四个属性

prevDirection 上一刻的蛇身走向

currDirection 当前时刻蛇身走向

next 节点的下一个节点

pos 节点的位置

六个方法

getNext 获得节点的下一个节点

setNext 设置节点的下一个节点

setDirection 设置节点的方向

getDirection 获得节点的方向

computePosition 计算节点下一刻的位置

getPosition 获得节点的位置

SnakeNode.getNextPoint 这个方法是一个静态方法, 不属于节点实例, 它的功能是根据方向计算出某一个坐标的下一个坐标, 比如说10和10是某个节点当前的坐标, 那么它向左移动一个单位后坐标就是9和10;向右移动一个单位后坐标就是11和10,同理向上和向下坐标分别是10,9和10,11。

computePosition需要特点说明一下,它在计算出自身的下一刻的位置以后,还会调用它引用的下一个节点的 computePosition方法,然后下一个节点再次执行相同的操作,一直到蛇身的最后一个节点为止,这就是链表的特性。同时如果方向发了变化,这个方法还会把当前节点的方向同步给它引用的下一个节点,就是靠这一点, 蛇身每一个节点的走向才能一致。

通过这一系列属性和方法就能表示出蛇身的节点特性了。

Snake是整条蛇的抽象表示,代码如下

这个类有三个属性

snake是蛇的脑袋节点,因为是一个链表,所以通过蛇的脑袋就可以访问到蛇的尾巴,因此,蛇的脑袋就可以表示一条蛇了。

isGameover游戏是否结束

self是实例自身的引用,跟游戏逻辑的表示没有任何关系。

八个公有方法

addNode 给蛇身增加一个结点,当蛇吃到食物时会调用这个方法,这个方法会把新的节点追加到最后一个节点(蛇尾)的后面。其中局部变量reverse是用来计算新节点的位置用的,假如当前节点的方向是向右的,那么下一个节点肯定在当前节点的左边,以此类推, reverse变量就是当前节点相反方向的值,细节请结合代码理解。

getAllNodePos 获得蛇身所有节点的位置。

getLength 获得蛇身长度(蛇身节点个数)

isGameover 游戏是否结束

move 移动蛇身,调用一次整个蛇身便移动一下,这里的移动仅仅是数据结构变化,具体效果需要将数据结构结果渲染至页面。

setDirection 设置蛇的游动方向

getHeadPos 获得蛇身的第一个节点(蛇头)的位置

getHeadDirection 获得蛇(蛇头)游动的方向

二个私有方法

checkGameover 检查游戏是否结束,分别检测游戏的第一个节点是否落在 TRANSVERSEVERTICAL常量定义的范围之外(撞墙)和是否落在蛇身节点的位置之上(咬到自己)。

getLastNode 获得蛇身的最后一个结果

通过SnakeNodeSnake这两个类,便抽象出了贪食蛇的结构和特性,但是现在这条蛇只是一个逻辑结构,是不会动的, 更不能玩。接下来我们便让这条蛇游动起来, 还可以控制它的方向, 让它去觅食并越长越长越游越快。

SnakeGame类算不上某一种结构抽象, 它仅仅是一组功能的封装, 其中包括人机交互事件、将数据结构转换成界面和一系列组成游戏的功能。此类比较复杂,就不以讲解之前两个类的方法讲解了。我们从类的实例化为入口开始讲解,然后再逐步扩展至类中的其它方法和属性。

var game = new SnakeGame();

实例化对象,调用构造函数后,类的几个属性被声明或初始化。

snake 也就是Snake类的实例

moveTimer 使蛇身运动的setTimeout函数的返回值, clearTimeout此值后,表示游戏暂停

randomTimer 随机产生食物的setInterval函数的返回值,clearInterval后停止生成食物,表示游戏暂停

foods 食物,因为会有多个食物产生,因为初始化为数组来存放食物

status 游戏状态,初始化状态为暂停中

context 游戏界面的canvas对象

self 没有表示实例自身, 跟游戏不相关

onEatOne 并不是属性, 而是游戏的一个事件, 当蛇吃到食物时, 此函数(事件)会被调用以用来通知监听者

game.initialize("snake");

初始化游戏,initialize方法的参数是游戏界面的canvas的元素ID,这个方法的细节如下

执行的操作分别是

  1. 实例化蛇的第一个节点,事实上刚开始也只有一个节点,位置设置在界面的中间。
  2. 随机生成一个方向并设置
  3. 实例化Snake类,以head(第一个节点)作为构造函数参数
  4. 引用canvas,获取canvascontext对象

至此,游戏已经初始化完成,然而,此刻的游戏是静止的,我们还需要调用start方法让游戏开始

此方法执行的操作分别是

  1. 将游戏的状态设置成 GAME_START常量的值(表示游戏开始)
  2. 让蛇身持续移动
  3. 每5秒生成一个食物
  4. 绑定交互事件,也就是我们用键盘的方向键上下左右控制蛇游动的方向的事件

先看被setTimeout调用的move方法

  1. 方法里面还有一次setTimeout调用,起的到作用和setInterval相同
  2. 设置蛇游动的方向
  3. 调用蛇的move方法移动
  4. 获得蛇头的位置,检查它是否与物品的位置重叠,假如重叠那么表示蛇吃到了食物,因为会调用蛇的addNode方法为蛇增加一个结点,并且触发onEatOne事件用来通知外部的事件监听,再将初吃掉的食物从食物列表中拿掉
  5. 判断游戏是否结束,假如没结束那么就执行draw方法将数据结果渲染至游戏界面

再来看 computeMoveInterval 方法,这个方法是setTimeout的第二个参数,在这里表达的意思就是定时执行move方法的时间间隔。

随着游戏的进行,游戏的级别会增加,随着级别增加, 这个值越小, 也就是说move方法被执行的频率就越高,因此蛇游动的速度会越快, 游戏难度也就越大。

createFood每5秒被调用一次生成一个食物

蛇身体所占的位置和已有食物的位置被排除掉,显然食物不能生成在已被占用的位置上。

最后,我们来讲一下draw方法,它的作用是将游戏的数据结构转换为可视化界面

将游戏结构转换成draw方法可用的数据结构还需要调用两个方法,分别是getMaparrayToMap

arrayToMap的作用其实是将一个一维数组转换为二维数组(并不是真正的二维数组,但是为了方便表达就借用二维数组这种结构),只是JavaScript的二维数组表示的有点奇葩,是一个map,所以这个函数的名称就被命名为arrayToMap

getMap函数的逻辑如下

  1. 建一个二维数组,元素个数等于TRANSVERSE * VERTICAL
  2. 获取蛇身所占的位置列表,转换成二维数组
  3. 获得食物所占的位置列表,转换成二维数组
  4. 通过null、snake、food三种值区分空、蛇身节点、食物

最终的数组结构从可视的角度来表示大概是这个样子

[null,null,null,null,null,

null,null,null,food,null,

null,null,null,null,null,

null,null,food,null,null,

null,null,snake,snake,null,

null,null,snake,null,null]

这个结构会随着move方法的调用而不断变化, draw方法就不断的将数据结构渲染至canvas上,整条蛇因此也就动了起来。

最后我们来看bindEvent方法

这个方法很简单,就是用来监听方向键的事件,然后控制蛇的方向以达到操作游戏的效果。

至此,整个游戏的逻辑也就开发完成了。麻雀虽小,但五脏俱全,这个游戏玩法虽然很少,但确实是一个正儿八经的贪食蛇游戏。附上可运行的源代码的链接地址 http://pan.baidu.com/s/1o7VIcWy 就一个html文件

游戏是我多年前写的,代码略显青涩,函数和变量的命名也是词不达意,但大致意思能表达清楚,大家就将就着看吧。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-03-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 带你撸出一手好代码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
腾讯云小微
腾讯云小微,是一套腾讯云的智能服务系统,也是一个智能服务开放平台,接入小微的硬件可以快速具备听觉和视觉感知能力,帮助智能硬件厂商实现语音人机互动和音视频服务能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档