Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >JavaScript贪食蛇游戏制作详解

JavaScript贪食蛇游戏制作详解

作者头像
用户1608022
发布于 2018-04-11 06:10:49
发布于 2018-04-11 06:10:49
1.2K0
举报

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

代码的实现比较简单,整个程序由三个类,一组常量和一些游戏逻辑以外的初始化和控制代码组成,总共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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【C语言】实践:贪吃蛇小游戏(附源码)
贪吃蛇小游戏想必大家都玩过吧,现在就要C语言代码来实现一下贪吃蛇小游戏
星辰与你
2024/10/17
5890
【C语言】实践:贪吃蛇小游戏(附源码)
大二必做项目贪吃蛇超详解之下篇游戏核心逻辑实现
现在我们解释一下Snake结构体中的_SleepTime是怎么控制速度的。 首先我们要明确:程序的运行速度是非常快的,对于贪吃蛇这样的小项目来说,所有的代码都可以看作是瞬间完成的,如果直接执行,那贪吃蛇一定会在我们反应过来之前直接死亡,所以说我们需要使用Sleep函数让函数停下来一会儿来控制速度。
fhvyxyci
2024/09/24
1560
大二必做项目贪吃蛇超详解之下篇游戏核心逻辑实现
贪吃蛇小游戏
秦jh
2024/01/19
1800
C语言项目实战——贪吃蛇
贪吃蛇是一款经典的休闲益智类电子游戏,通常用C语言实现时,会涉及到以下几个主要部分:
鲜于言悠
2024/03/20
5870
C语言项目实战——贪吃蛇
国庆节前端技术栈充实计划(4):用H5撸一个贪吃蛇游戏
第一种是笔者小时候在掌上游戏机最先体验到的(不小心暴露了年龄),具体玩法是蛇吃完一定数量的食物后就通关,通关后速度会加快;第二种是诺基亚在1997年在其自家手机上安装的游戏,它的玩法是吃到没食物为止。笔者要实现的就是第二种玩法。
疯狂的技术宅
2019/03/27
8050
国庆节前端技术栈充实计划(4):用H5撸一个贪吃蛇游戏
c语言实现贪吃蛇小游戏
如果运行之后出现的是上面的界面,就需要更改一下,鼠标右键点击控制台顶端,再点击设置
2的n次方
2024/10/15
950
c语言实现贪吃蛇小游戏
【C语言】【数据结构】项目实践——贪吃蛇游戏(超详细)
贪吃蛇是一款休闲益智类游戏,有PC和手机等多平台版本。既简单又耐玩。该游戏通过控制蛇头方向吃食物,从而使得蛇变得越来越长,贪吃蛇是久负盛名的游戏,它也和俄罗斯方块,扫雷等游戏位列经典游戏的行列。
用户11290673
2024/09/25
5820
【C语言】【数据结构】项目实践——贪吃蛇游戏(超详细)
laya游戏开发之贪吃蛇大作战(二)—— 贪吃蛇客户端
下面将介绍联网版贪吃蛇大作战的客户端代码,本项目用 laya 引擎开发,typescript 作为开发语言,具体的技术选型及项目准备可参考 上一篇文章
siri
2022/11/18
1.7K1
laya游戏开发之贪吃蛇大作战(二)—— 贪吃蛇客户端
C语言——贪吃蛇
Windows可以给我们提供各种服务(每一个服务就是一个函数),可以帮应用程序达到开启视窗、描绘图形、使用周边设备等目的。这些函数的服务对象是应用程序(Application),所以便称之为ApplicationProgrammingInterface,简称API函数。。
HZzzzzLu
2024/11/26
1400
C语言——贪吃蛇
【游戏制作】使用Python创建一个美观的贪吃蛇游戏,附完整代码
在开始编写代码之前,我们需要确保安装了必要的库。我们将使用tkinter和ttkbootstrap库。
命运之光
2024/08/02
3890
【游戏制作】使用Python创建一个美观的贪吃蛇游戏,附完整代码
大二必做项目贪吃蛇超详解之中篇游戏设计与分析
我们最终的贪吃蛇界面是这个样子,可以发现这和之前写的C语言项目的最大不同就在于文字不是依次排列的,那我们的地图应该如何布置呢?
fhvyxyci
2024/09/24
1700
大二必做项目贪吃蛇超详解之中篇游戏设计与分析
【C语言】打造你的专属贪吃蛇
我们如果要在控制台上打印宽字符’●’或者’★’,汉字也是宽字符,就需要修改本地适配环境,在main函数中://修改适配本地的中文环境 setlocale(LC_ALL, "");,使用该函数要包含#include<locale.h> 头文件
大耳朵土土垚
2024/05/30
1240
【C语言】打造你的专属贪吃蛇
【C语言项目】贪吃蛇(下)
在上一篇博文中我们介绍了GetAsyncKeyState函数,我们封装一个宏可以判断某个键是否被按下
s-little-monster
2024/06/06
1080
【C语言项目】贪吃蛇(下)
c语言及数据结构实现简单贪吃蛇小游戏
十进制颜色代码:void color(int c) { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c); }
羑悻的小杀马特.
2025/01/23
1480
c语言及数据结构实现简单贪吃蛇小游戏
【C语言项目】贪吃蛇(上)
使用C语言在Windows环境的控制台中模拟实现贪吃蛇游戏 功能: ①贪吃蛇地图 ②蛇的移动 ③蛇吃食物 ④蛇撞墙或者撞到自己死亡 ⑤计算得分 ⑥暂停游戏 ⑦加速蛇身 ⑧计算得分
s-little-monster
2024/06/06
2020
【C语言项目】贪吃蛇(上)
java贪吃蛇小游戏(详解)[通俗易懂]
首先给出代码下载地址(含素材):https://share.weiyun.com/8hkvy1Ja
全栈程序员站长
2022/09/07
1.8K0
java贪吃蛇小游戏(详解)[通俗易懂]
贪吃蛇穿墙代码_C语言贪吃蛇实现暂停功能
此外,我们还需要两个结构体,分别用于存储蛇头的信息和蛇身的信息。蛇头结构体当中存储蛇头当前所在的坐标,以及当前蛇身的长度。
全栈程序员站长
2022/10/04
2.7K0
贪吃蛇穿墙代码_C语言贪吃蛇实现暂停功能
【网页游戏】Vue3 + Typescript 自己动手实现一个贪吃蛇
还记得刚上大学的时候,第一节编程课,老师说:"不要让我抓到你们玩游戏,否则玩什么就让你们写什么"。当时什么也不会,也不敢玩。
一尾流莺
2022/12/10
1.1K0
【网页游戏】Vue3 + Typescript 自己动手实现一个贪吃蛇
【C语言】项目实践-贪吃蛇小游戏(Windows环境的控制台下)
Windows 这个多作业系统除了协调应用程序的执行、分配内存、管理资源之外, 它同时也是⼀个很大的服务中心,这个服务中心提供了多种服务(每⼀种服务就是⼀个函数),调用这些服务可以帮应用程序达到开启视窗、描绘图形、使用周边设备等目的,由于这些函数服务的对象是应用程序(Application), 所以便称之为 Application Programming Interface,简称 API 函数。WIN32 API也就是Microsoft Windows 32位平台的应用程序编程接口。
ZLRRLZ
2024/12/13
6140
【C语言】项目实践-贪吃蛇小游戏(Windows环境的控制台下)
C语言基于控制台实现简单的贪吃蛇游戏的步骤和核心机制
用一个二维数组存储地图,一个二维数组存储地图上的数字对应的值,方便用中文替换,或者以后用贴图或者加上颜色渲染
晨星成焰
2024/05/05
3740
C语言基于控制台实现简单的贪吃蛇游戏的步骤和核心机制
推荐阅读
相关推荐
【C语言】实践:贪吃蛇小游戏(附源码)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档