HTML5 游戏开发实战 | 贪吃蛇

在该游戏中,玩家操纵一条贪吃的蛇在长方形场地里行走,贪吃蛇按玩家所按的方向键折行,蛇头吃到食物(豆)后,分数加10分,蛇身会变长,如果贪吃蛇碰上墙壁或者自身的话,游戏就结束了(当然也可能是减去一条生命)。

贪吃蛇游戏的运行界面如上图所示。

01、贪吃蛇游戏设计的思路

把游戏画面看成40×30的方格。食物(豆)和组成蛇的块均在屏幕上占据一个方格。游戏设计中主要用到的4个类如下。

Farm类:主要用来显示场地,随机生成食物,初始化一条蛇。

Food类:抽象了食物(豆)的属性和动作。

Snake类:抽象了贪吃蛇的属性和动作,调用Block类来组成蛇,并处理键盘输入事件和蛇的移动。

Block类:表示组成蛇的块(实心圆)。一条蛇可以看成由许多“块”(或称节)拼凑而成,块是蛇身上最小的单位。

02、贪吃蛇游戏设计的步骤

游戏页面index.html

<!DOCTYPE html>
<html lang = "en">
< head >
<meta charset ="UTF - 8"
< title>小游戏之贪吃蛇</title>
< style>
# canvas{border: 3px solid red;</style>
</head>
< body>
<canvas id='canvas'width=800'height =00'></canvas><div id="textmsg">分数</div>
</body 

设计脚本

1. 食物(豆)类(Food)设计

在此游戏中,首先会在场地的特定位置出现一个豆,豆要不断被蛇吃掉,当豆被吃掉后,原豆消失,又在新的位置出现新的豆。这些豆都是由豆(Food)类创建的对象。

foodInit()函数用于在屏幕上显示一个豆(实心圆),设计方法是直接在场地(canvas)上画一个实心圆。

equal()函数用于判断是否与蛇身“块”node重合,也就是蛇吃到食物。

//食物类
function Food(x,y,w) {
var t= this;
t.x=x;
t.y=y;
t.w=w;//食物
//X坐标
//Y坐标
//大小
t.foodInit = function() [
//画一个实心圆
ctx.beginPath();
ctx.arc(x+w/2,y+w/2,w/2,0,360,false);ctx.fillStyle="red";
//填充颜色,默认是黑色
//画实心圆
ctx.fill();
ctx.closePath();
//判断是否重合
t.equal = function(node) 
if(this.x == node.x && this.y== node.y) return true;else(
return false;
}
}
}

 

2. 块类(Block)

在贪吃蛇游戏中,块用来构成蛇,在蛇出现时,要把构成蛇的块一个个地输出(显示),在蛇消失时,要把块消除掉,显示和消除哪一个块都要由位置决定,并且由于蛇是由多个块构成的,每个块要填到snakes数组中。

//蛇块类
function Block(x,Y,w)(
var t = this;
t.x= x;
t.y=y;
t.w= w;
//画一个蛇块
t.drawBlock = function()
ctx.beginPath();
ctx.arc(x+w/2,y+w/2,w/2,0,360,false);
//填充颜色,默认是黑色
ctx.fillStyle="blue";
ctx.fill();
//画实心圆
//清除蛇块
t.clear = function()!
ctx.fillStvle=white';
ctx.strokeStyle = white';
ctx.fillRect(x,Y,w,w);
ctx.strokeRect(x,Y, w,w);
//判断是否重合
t.equal = function(node)
if(this.x== node.x && this.y== node.y){return true;
else
return false;
}
}

 

3. 蛇类(Snake)设计

现在到了最难的步骤,就是处理蛇,一条完整的贪吃蛇是由一块一块组成的。snakes数组用于存放组成蛇的所有块;其中保存的第一个元素是蛇的头部,最后一个元素是蛇的尾巴。当蛇运动的时候,它头部增加一块而尾部减少一块。如果它吃到了豆,头部增加一块而尾部不减少。也就是说,蛇是从头部开始长的。蛇运行过程中要不断地改变方向;如果蛇头碰到了它自身,蛇就要死亡,即程序结束。

首先,画一条蛇并移动它。

//蛇类
function Snake(x,y  len,speed) {
var t = this;
t.x=x;
t.y=y;
t.dir='R';
t.len = len;
//dir 方向,R'向右
var nx = x;ny =y;
//初始蛇最初 len(5)块,并启动定时
t.init = function()
for(var i=0;i< len; i++){
var tempBlock = new Block(nx,ny,gridWidth);tempBlock.drawBlock();nx-= gridWidth;
snakes.push(tempBlock);
snake interval = setInterval(t.move,speed);//定时移动蛇
}

 然后,识别键盘事件,修改移动方向dir,初始移动dir方向为'R'(向右)。

//取得键盘方向
document.onkevdown = function(e)
var code = e.keyCode;
t.odir = t.dir;
switch(code)
case 37:
t.dir='L';
break;case 38:
t.dir='u';break;
case 39:
t.dir='R';break;case 40 :
t.dir='D';
//向左键
//向上键
//向右键
//向下键
break;
}
}

 

以下主要是让蛇动的move()函数。主要是根据原来蛇头snakes[0]的位置和移动方向确定新的蛇头位置,绘制新的蛇头,并清除原来的蛇尾即达到移动效果。

在蛇移动时,判断蛇头是否和食物相撞,是否碰撞到了场地的壁以及是否与自己相撞。

//移动蛇
t.move = function()
var newHead;
//是否碰撞到了场地的壁
if(snakes0].x+ snakes0].w >= canvas.width snakes0].x- snakes0].w<0snakes[0].y- snakes[0].w < 0 snakes[0].y + snakes[0].w > canvas.height)(gameover();
else{//根据原来蛇头 snakes[0]的位置和移动方向确定新的蛇头位置
if(t.dir=='R'){newHead= new Block(snakes[0].x + gridWidth,snakes[0].y,gridWidth);) else if (t.dir =='L')(
newHead = new Block(snakes[0].x- gridWidth,snakes[0].y,gridWidth);else if (t.dir==D') !
newHead = new Block(snakes[0].x,snakes[0].y + gridWidth,gridWidth);else if (t.dir==u') !
newHead= new Block(snakes[0].x,snakes[0].y- gridwidth,gridWidth)
//禁止反向跑
if(newHead.x == snakes[1].x && newHead.y == snakes[1].y)t.dir = t.odir;return;
//画新的蛇头newHead.drawBlock();//追加到数组中(长度会自动加)snakes.unshift(newHead);//清除原来尾部snakes[snakes.length - 17.clear();//并从数组中移除(长度会自动减)snakes.pop()
//清除(蛇尾)块
/判断食物是否和蛇头相撞
for(var i=0;i< foods.length; i++)if(foods[ i].equal( snakes[0]))
//给蛇增加长度
t.growth();
score= score +10:
textmsq.innerHTML = score +“分”
t.len = t.len + 1;
//蛇生长方法
//增加 10 分
//显示分数
clearInterval(snake interval);
//速度加快snake interval = setInterval(t.move,speed);
speed = speed < 20 ? speed : speed -10;
//判断是否与自己相撞
for(var i=1;i< snakes.length; i++)if(snakesil.equal(snakes[0T)) gameover();
)//move()函数结束

用于实现蛇生长growth()函数的具体功能是当蛇吃到一个豆后,蛇就要在它的尾巴上增加一块即蛇增长。设计思路是找到蛇尾snakes[snakes.length-1],根据蛇尾与蛇的倒数第2块snakes[snakes.length-2]的位置关系,计算出蛇尾新增一块的位置。

 

//给蛇增加长度(在尾巴加)
t.growth = function()
 var tail1 = snakes[ snakes.length - 1];
var tai12 = snakes[snakes.ength - 2];
var addBlock;
if(tai11.x== tai12.x) 
{
if(tail1.y>= tail2.y)
}
addBlock =new Block(tail1.x,tail1.y + gridWidth,gridWidth);
else
addBlock =new Block(tail1.x,tail1.y-gridWidth,gridWidth);
else
if(tai11.x>= tail2.x)
addBlock =new Block(tail1.x + gridWidth,tail1.y,gridWidth);
else
addBlock =new Block(tail1.x-gridWidth,tail1.y,gridWidth);
//数组加入尾部
snakes.push(addBlock);addBlock.drawBlock();
console.log(snakes.length);
)//growth()函数
* snake 类结束 */

 

4. 场地类(Farm)设计

为游戏的主场地,豆要在此范围内出现,蛇要在此范围内运行,显示场地内的所有对象、场地边框、豆和蛇。

//场地类,生成一个画布和豆、蛇
function Farm()
var t = this;
ctx.fillStyle ='white';
ctx.fillRect(0,0,canvas.width,canvas.height);foods =l;//有环莲浮墩甘伴榜机郧扒唉癌挨膊鞍皑傲卑唉扮诚成一个食物t.addfood = function()var x= parseInt(canvas.width / gridWidth * Math.random()) * gridWidth;var y=parseInt(canvas.height / gridWidth * Math.random()) * gridWidth;var food = new Eood(x,y,gridWidth);food把椽斌新foodInit();
//重新初始化豆数组,不要把前一次游戏的数组元素遗留
foods.push(food);
//重新初始化蛇身(块)数组,不要把前一次游戏的数组元素遗留snakes =;//更新速度 500 毫秒(即移动速度)
t.snake= new Snake(100,100,5,500); //初始 5 节长度,位置(100,100)处//*彼啊画钻班等滁癌报蛇t.snake.init();
}

 

5. 主程序

在游戏开始后,要首先初始化场地Farm类,显示场地内的所有对象,场地边框、豆和蛇。同时要2秒随机产生一个新豆并显示。

var canvas = document.getElementById("canvas”)
var ctx = canvas.getContext( 2d');
var gridWidth = 20;
var score = 0;
var foods = new Array(),snakes = new Array();//开始游戏
function gameStart(
var farm = new Farm();
//放豆和蛇的数组
//2 秒产生一个豆
food interval = setInterval(farm.addfood,2000);
gameStart();
//结束
function gameover()var judge = confirm("游戏结束,是否重新开始”);score =0;
textmsg.innerHTML = score +“分clearInterval(snake interval);
//清除产生蛇移动定时
//清除产生新豆定时
clearInterval(food interval);
if(!judge){
//选择不重新开始
return false;
gameStart();
}

至此,贪吃蛇游戏编写完成。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/33040.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

企业级微服务架构实战项目--xx优选-用户登录

一 用户登录的触发页面 1.登录常量 2.登录地址 3.配置域名 4.启动程序 触发连接小程序后端的登录接口 小程序controller的登录方法

XR云新未来圆桌精彩回顾 | XR应用场景迭代下的新商业模式

6月15日&#xff0c;由平行云联合首都在线共同主办&#xff0c;中关村软件园协办&#xff0c;以“XR云新未来|弹性算力赋能可交互、沉浸式商业实践”为主题的XR行业交流盛会在北京成功举办。 本次会议我们邀请到平行云科技创始人兼CEO 李岩、XREAL 云XR负责人 吴维、瑞帆科技…

利用SQL注入漏洞登录后台

所谓SQL注入&#xff0c;就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串&#xff0c;最终达到欺骗服务器执行恶意的SQL命令&#xff0c;比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的&#xff0c;这类表单特别容易受到SQ…

LLM-Client一个轻量级的LLM集成工具

大型语言模型(llm)已经彻底改变了我们与文本交互的方式&#xff0c;OpenAI、Google、AI21、HuggingfaceHub、Anthropic和众多开源模型提供了不同的功能和优势。但是每个模型都有其独特的体系结构、api和兼容性需求&#xff0c;集成这些模型是一项耗时且具有挑战性的任务。 所以…

【spring cloud学习】4、创建服务提供者

注册中心Eureka Server创建并启动之后&#xff0c;接下来介绍如何创建一个Provider并且注册到Eureka Server中&#xff0c;再提供一个REST接口给其他服务调用。 首先一个Provider至少需要两个组件包依赖&#xff1a;Spring Boot Web服务组件和Eureka Client组件。如下所示&…

跑步适合戴哪种耳机不掉、公认最好的运动耳机推荐

我们都知道&#xff0c;运动往往让人感到枯燥无味&#xff0c;于是很多人选择听音乐来赋予运动更多乐趣。对于那些热爱运动并经常锻炼的朋友们来说&#xff0c;选择一款出色的运动耳机来提升体验是非常重要的。然而&#xff0c;面对市面上众多的选择&#xff0c;该如何下手呢&a…

ubuntu安装WPS2019以及解决缺少字体问题

环境&#xff1a;ubuntu22.04.2 LTS 步骤&#xff1a; 1.去官网下载最新的WPS&#xff0c;官网地址如下&#xff1a;WPS Office 2019 for Linux-支持多版本下载_WPS官方网站 2.sudo dpkg -i 安装包.deb 3.安装完成&#xff0c;首次用WPS打开某个文档&#xff0c;会出现如下报…

Navicat连接oracle

1、官网下载oracle instant client客户端&#xff08;版本自选&#xff09; Oracle Instant Client Downloads 下载后解压 2、navicat配置 在工具-> 选项 -> OCI 或环境中&#xff0c;选择在步骤 1 解压目录的 oci.dll 3、重新启动 Navicat 4、配置oracle连接即可 参考…

C++类与对象(下)

类与对象&#xff08;下&#xff09; 1.再谈构造函数1.1构造函数体赋值1.2初始化列表1.3explicit关键字 2.static成员2.1概念2.2特性 3.有元3.1有元函数3.2有元类 4.内部类4.1概念及特性 5.匿名对象6.拷贝对象时的一些编译器优化7. 再次理解类和对象 1.再谈构造函数 1.1构造函…

oracle 重复启动监听程序故障

又是一起 oracle 无法连接问题&#xff0c;检查配置都是正常的。 原来是碰到一个oralce的bugl了。 还真就是这个问题&#xff0c;子进程一kill掉&#xff0c;就恢复了。

【Spring Clound】Nacos高可用集群搭建与使用

文章目录 一、Nacos 简介二、Nacos 安装2.1、Nacos 环境依赖2.2、Nacos 服务端安装 三、Nacos 部署3.1、单实例部署3.2、 集群部署3.2.1、集群架构3.2.2、模拟部署 四、微服务集成Nacos4.1、依赖组件版本选型4.2、注册中心4.2.1、服务提供者4.2.2、服务消费者4.2.3、服务调用4.…

目标检测模型中的Bells and wisthles

目标检测模型中的Bells and wisthles 目标检测模型中的Bells and wisthles1. Data augmentation 数据增强2. Multi-scale Training/Testing 多尺度训练/测试3. Global Context 全局语境4. Box Refinement/Voting 预测框微调/投票法5. OHEM 在线难例挖掘6. Soft NMS 软化非极大抑…

二.《UE4奥丁》解密哈希ID

哈希表概念 1.相信大家经常在UE4或者UE5游戏逆向中遇到下面的代码段 $ > > 41:8B42 0C > mov eax,dword ptr ds:[r10C] > $4 > 3B05 AE589B04 > cmp eax,dword ptr ds:[7FF7B68B74F4] …

观察级水下机器人使用系列之三黑白和彩色摄像机

本文主要讲Valor配套的黑白和彩色摄像机&#xff0c;它们都是imenco公司生产的&#xff0c;黑白照相机型号是Night Shark&#xff0c;彩色照相机型号是Blacktip SharkII&#xff0c;令人奇怪的是黑白照相机比彩色照相机大多了&#xff0c;见下图大的照相机是黑白照相机。 正在上…

Audio API 实现音频播放器

市面上实现音频播放器的库有很多&#xff0c;比如wavesurfer.js、howler.js等等&#xff0c;但是都不支持大音频文件处理&#xff0c;100多M的文件就有可能导致程序崩溃。总之和我目前的需求不太符合&#xff0c;所以打算自己实现一个音频播放器&#xff0c;这样不管什么需求 在…

NLP入门:word2vec self-attention transformer diffusion的技术演变

这一段时间大模型的相关进展如火如荼&#xff0c;吸引了很多人的目光&#xff1b;本文从nlp领域入门的角度来总结相关的技术路线演变路线。 1、introduction 自然语言处理&#xff08;Natural Language Processing&#xff09;&#xff0c;简称NLP&#xff0c;是通过统计学、…

使用Docker Swarm部署PXC+HAProxy高可用集群(三节点)

使用Docker Swarm部署PXCHAProxy高可用集群&#xff08;三节点&#xff09; 1. 部署规划 当前规划中&#xff0c;只启动一个HAProxy服务&#xff0c;主要用来做MySQL节点的负载均衡和代理&#xff0c;但是HAProxy可能会出现单点故障&#xff0c;后续需要启动多个HAProxy节点&…

【网络知识面试】初识协议栈和套接字及连接阶段的三次握手

接上一篇&#xff1a;【网络面试必问】浏览器如何委托协议栈完成消息的收发 1. 协议栈 一直对操作系统系统的内核协议栈理解的模模糊糊&#xff0c;借着这一篇博客做一下简单梳理。 我觉得最直白的理解&#xff0c;内核协议栈就是操作系统中的一个网络控制软件&#xff0c;就是…

Web测试的主要内容和测试方法有哪些?

Web测试的主要内容&#xff1a; 一、输入框 二、搜索功能 三、增加、修改功能 四、删除功能 五、注册、登录模块 六、上传图片测试 七、查询结果列表 八、返回键检查 九、回车键检查 十、刷新键检查 Web测试的测试方法&#xff1a; 1.在测试时&#xff0c;与网络有关的步骤或者…

mybatis-plus在实际开发中的应用

文章目录 前言一、实体类的注解二、Req查询条件三、Controller接口四、Service接口五、Service接口实现类六、Mapper接口七、枚举的使用总结 前言 最近的项目是使用mybatis-plus作为持久层框架&#xff0c;前面也记录过mybatis-plus的基本使用&#xff0c;此次记录一下本次项目…