JS做贪吃蛇小游戏(源码)

news2025/3/20 5:04:08

一、HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<link rel="stylesheet" href="./../css/index.css">
</head>
<body>
	<div class="container">
		<!-- 开始按钮 -->
		<button class="start"></button>
		<!-- 暂停按钮 -->
		<button class="pause"></button>
	</div>
	<script src="../js/config.js"></script>
	<script src="../js/index.js"></script>
</body>
</html>

二、css代码

html,body{
	margin: 0;
	padding:0 ;
}
/*容器样式*/
.container{
	width: 600px;
	height: 600px;
	background: #225675;
	border: 20px solid #7dd9ff;
	margin: 100px auto;
	position: relative;
}
/*按钮公共样式*/
button{
	border:none;
	outline: none;
	position: absolute;
	left: 50%;
	top: 50%;
	transform: translate(-50%,-50%);
}
/*开始按钮*/
.start{
	width: 200px;
	height: 200px;
	background: url(./../img/start.webp) center no-repeat;
	background-size: 100% 100%;
	display: block;
}
/*暂停按钮*/
.pause{
	width: 80px;
	height: 80px;
	background: url(./../img/b.webp) center no-repeat;
	background-size: 100% 100%;
	display: none;
}

三、JS代码

1.index.js

//绘制蛇的方法
function drawSnake(snake){
	for(var i=0;i<snake.snakePos.length;i++){
		if(!snake.snakePos[i].domConent){
			// 如果进入此if,说明是第一次创建蛇
			snake.snakePos[i].domConent=document.createElement("div");
			snake.snakePos[i].domConent.style.position="absolute";
			snake.snakePos[i].domConent.style.width=snakeBody+"px";
			snake.snakePos[i].domConent.style.height=snakeBody+"px";
			snake.snakePos[i].domConent.style.left=snake.snakePos[i].x*snakeBody+"px";
			snake.snakePos[i].domConent.style.top=snake.snakePos[i].y*snakeBody+"px";
			if(snake.snakePos[i].flag==='head'){
				//进入此if说明是蛇头
				snake.snakePos[i].domConent.style.background=`
					url("../img/a.webp") center/contain no-repeat
				`;
				//根据方向进行旋转
				switch(snake.direction.flag){
					case "top":{
						snake.snakePos[i].domConent.style.transform=`rotate(-90deg)`;
						break;
					}
					case "bottom":{
						snake.snakePos[i].domConent.style.transform=`rotate(90deg)`;
						break;
					}
					case "left":{
						snake.snakePos[i].domConent.style.transform=`rotate(180deg)`;
						break;
					}
					case "right":{
						snake.snakePos[i].domConent.style.transform=`rotate(0deg)`;
						break;
					}
				}
			}else{
				//说明是蛇身
				snake.snakePos[i].domConent.style.background="#e69009";
				snake.snakePos[i].domConent.style.borderRadius="50%"
			}
		}
		//需要将创建的DOM 元素添加到容器当中
		document.querySelector(".container").append(snake.snakePos[i].domConent)
	}
}

//绘制食物的方法
function drawFood(){
	//1.食物是随机的
	//2.食物不能再蛇头或蛇身的位置
	while(true){
		//构成一个死循环,直到生成符合要求的食物坐标才能退出
		var isRepeat=false//默认生成的坐标是符合要求的
		//随机生成一个坐标
		food.x=Math.floor(Math.random()*tr+0)
		food.y=Math.floor(Math.random()*tr+0)
		//查看是否符合要求
		for(var i=0;i<snake.snakePos.length;i++){
			if(snake.snakePos[i].x===food.x&&snake.snakePos[i].y===food.y){
				//当前生成的食物,和蛇的坐标冲突了
				isRepeat = true;
				break; //跳出for循环
			}
		}
		if(!isRepeat){
			break;//跳出while循环
		}
	}
	//整个while循环跳出来以后u,食物的坐标一定是ok的
	if(!food.domConent){
		food.domConent = document.createElement("div")
		food.domConent.style.width = snakeBody+"px";
		food.domConent.style.height = snakeBody+"px";
		food.domConent.style.position = "absolute";
		food.domConent.style.background=`
			url("../img/apple.webp") center/contain no-repeat
		`;
		document.querySelector(".container").append(food.domConent);
	}
	food.domConent.style.left = food.x * snakeBody + "px";
	food.domConent.style.top = food.y * snakeBody + "px";
}


// 初始化游戏
function initGame(){
	// 1.初始化地图
	for(var i=0;i<tr;i++){
		for(var j=0;j<td;j++){
			gridData.push({
				x:j,
				y:i
			})
		}
	}
	// console.log(gridData) 
	//2.绘制蛇
	drawSnake(snake);
	//3.绘制食物 
	drawFood()
}
// 碰撞检测
function isCollide(newHead){
	var collideCheckInfo={
		isCollide:false,  //是否碰撞墙壁蛇身
		isEat:false       //是否迟到食物
	}
	// 是否碰到墙壁
	if(newHead.x<0||newHead.x>=td||newHead.y<0||newHead.y>=tr){
		collideCheckInfo.isCollide =true;
		return collideCheckInfo;
	}
	//检测是否碰到自己
	for(var i=0 ; i<snake.snakePos.length;i++){
		if(snake.snakePos[i].x === newHead.x && snake.snakePos[i].y===newHead.y){
			collideCheckInfo.isCollide=true;
			return collideCheckInfo;
		}
	}
	// 检测是否吃到东西
	if(newHead.x === food.x&&newHead.y===food.y){
		collideCheckInfo.isEat =true;
		score++;  //分数自增
	}
	return collideCheckInfo;
}

// 蛇的移动
function snakeMove(){
	
	var oldHead =snake.snakePos[snake.snakePos.length-1]
	//根据方向计算出新的蛇头坐标
	var newHead ={
		domConent:"",
		x : oldHead.x + snake.direction.x,
		y : oldHead.y + snake.direction.y,
		flag:"head",
	}
	// 首先先进行碰撞检测,看计算出来的新的蛇头有没有碰上食物,蛇身体,墙壁
	var collideCheckResult= isCollide(newHead);
	if(collideCheckResult.isCollide){
		//说明碰墙le
		// console.log("碰墙")
		if(window.confirm(`游戏结束,您当前的得分为${score}分,是否要重新开始游戏`)){
			//重新开始游戏
			// console.log("重新开始游戏")
			document.querySelector(".container").innerHTML=`
				<!-- 开始按钮 -->
				<button class="start" style="display:none"></button>
				<!-- 暂停按钮 -->
				<button class="pause" style="display:none"></button>
			`;
			score =0;
			snake ={
				//设一开始移动的方向
				direction:directionNumber.right,
				//蛇的初始位置
				snakePos:[
					{x:0,y:0,domConent:"",flag:"body"},
					{x:1,y:0,domConent:"",flag:"body"},
					{x:2,y:0,domConent:"",flag:"body"},
					{x:3,y:0,domConent:"",flag:"head"}
				]
			};
			food = {
				x:0 , y:0  ,domConent:""
			};
			initGame();
		}else{
			//结束游戏
			document.onkeydown = null;
			clearInterval(timerStop)
			// console.log("取消游戏")
		}
		return;
	}

	//将旧的头修改为身体
	oldHead.flag = "body";
	oldHead.domConent.style.background ="#e69009";
	oldHead.domConent.style.borderRadius ="50%";
	snake.snakePos.push(newHead);
	// 判段是否吃到东西
	if(collideCheckResult.isEat){
		//重新生成新的食物
		drawFood();
	}else{
		//没有吃到,移除最后一个
		document.querySelector(".container").removeChild(snake.snakePos[0].domConent)
		snake.snakePos.shift();
	}
	// 重新绘制蛇
	drawSnake(snake);
}

//
function startGame(){
	timerStop = setInterval(function(){
		snakeMove()
	},time)
}

// 绑定事件
function bindEvent(){
	// 首先是键盘事件,用户按上下左右,蛇可以移动
	document.onkeydown = function(e){
		// console.log(e.key)
		if((e.key === "ArrowUp" || e.key.toLocaleLowerCase() === "w")&&snake.direction.flag !== "bottom"){
			//用户按下上建
			snake.direction=directionNumber.top;
			 event.preventDefault(); // 阻止方向键默认行为(如页面滚动)
		}
		if((e.key === "ArrowDown" || e.key.toLocaleLowerCase() === "s")&&snake.direction.flag !=="top"){
			//用户按下下建
			snake.direction=directionNumber.bottom;
			 event.preventDefault(); // 阻止方向键默认行为(如页面滚动)

		}
		if((e.key === "ArrowLeft" || e.key.toLocaleLowerCase() === "a")&&snake.direction.flag !== "right"){
			//用户按下左建
			snake.direction=directionNumber.left;
			 event.preventDefault(); // 阻止方向键默认行为(如页面滚动)

		}
		if((e.key === "ArrowRight" || e.key.toLocaleLowerCase() === "d")&&snake.direction.flag !== "lefts"){
			//用户按下右建
			snake.direction=directionNumber.right;
			 event.preventDefault(); // 阻止方向键默认行为(如页面滚动)
		}
		// snakeMove();
	}
	//2.计时器自动调用蛇移动的方法
	startGame();
	//3.点击整个容器的时候可以暂停和重新开始游戏
	document.querySelector(".container").onclick = function(e){
		//这里是通过事件委托的形式,判断用户究竟点击的时候container容器还是暂停按钮,从而做出不同的操作
		if(e.target.className === "container"){
			//做暂停操作
			document.querySelector(".pause").style.display = 'block';
			clearInterval(timerStop);
		}else{
			//恢复游戏操作
			document.querySelector(".pause").style.display = 'none';
			startGame();
		}	
	}
}
// 主方法
function main(){
	//用户点击了开始游戏之后,再做后续的工作
	document.querySelector(".start").onclick= function(e){
		e.stopPropagation();
		document.querySelector(".start").style.display="none"
		//1.初始化游戏
		initGame();
		// 2.绑定事件
		bindEvent();
	}
	
}
main();

2.config.js(游戏相关设置)

// 游戏相关的配置


var gridData = [];//存储地图对象
// 整个网格的行与列
var tr = 30;
var td = 30;

//蛇的身体大小
var snakeBody = 20;

// 新的蛇头和旧的蛇头之间的关系
var directionNumber={
	// 我们在确定新的蛇头的时候,会拿下面的对象和旧蛇头做一个计算,从而得出新蛇头的位置
	left:{x:-1,y:0,flag:"left"},
	right:{x:1,y:0,flag:"right"},
	top:{x:0,y:-1,flag:"top"},
	bottom:{x:0,y:1,flag:"bottom"}
}

//蛇相关的配置信息
var snake ={
	//设一开始移动的方向
	direction:directionNumber.right,
	//蛇的初始位置
	snakePos:[
		{x:0,y:0,domConent:"",flag:"body"},
		{x:1,y:0,domConent:"",flag:"body"},
		{x:2,y:0,domConent:"",flag:"body"},
		{x:3,y:0,domConent:"",flag:"head"}
	]
}
//食物的相关配置信息
var food = {
	x:0 , y:0  ,domConent:""
}
//游戏分数
var  score= 0
//停止计时器
var timerStop = null
//计时器事件
var time=100

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

烽火HG680-KB_海思HI3798MV310_安卓9.0_U盘强刷固件包及注意点说明

之前发布过这个固件包&#xff0c;关于烽火HG680-KA&#xff0f;HG680-KB_海思HI3798MV310_安卓9.0_U盘强刷固件包详细说明一下&#xff0c;汇总总结一些常遇到的情况&#xff0c;这次固件会分开发布&#xff0c;以免混淆。 上一个帖子地址&#xff1a;烽火HG680-KA&#xff0…

996引擎 - 红点系统

996引擎 - 红点系统 总结NPC 红点(TXT红点)Lua 红点1. Red_Point.lua2. UI_Ex.lua参考资料以下内容是在三端 lua 环境下测试的 总结 红点系统分几个部分组成。 M2中设置变量推送。 配置红点表。 Envir\Data\cfg_redpoint.xls 2.1. UI元素中找到ID填写 ids 列。 主界面挂载…

3.17BUUCTF练习day1

BUUCTF练习day1 [极客大挑战 2019]EasySQL1&#xff08;字符型&#xff0c;账号密码型&#xff0c;get型&#xff09; 判断闭合方式 在用户名输入1‘&#xff0c;此时密码先输入任何数字时&#xff0c;出现语法错误 说明闭合方式为单引号闭合&#xff0c;在判断完闭合方式后…

【贪心算法】柠檬水找零

1.题目解析 860. 柠檬水找零 - 力扣&#xff08;LeetCode&#xff09; 2.讲解算法原理 分情况讨论 5---》直接收下 10---》找五元&#xff0c;收下 20----》105△ ----》555 由于5元更有用&#xff0c;则尽可能保留5元 3.代码 class Solution {public boolean lemonadeCh…

黑马跟学.苍穹外卖.Day08

黑马跟学.苍穹外卖.Day08 苍穹外卖-day8课程内容1. 工作台1.1 需求分析和设计1.1.1 产品原型1.1.2 接口设计 1.2 代码导入1.2.1 Controller层1.2.2 Service层接口1.2.3 Service层实现类1.2.4 Mapper层 1.3 功能测试1.3.1 接口文档测试1.3.2 前后端联调测试 1.4 代码提交 2. Ap…

ABAP语言的动态编程(4) - 综合案例:管理费用明细表

本篇来实现一个综合案例&#xff1a;管理费用明细表。报表在实际项目中&#xff0c;也有一定的参考意义&#xff0c;一方面展示类似的报表&#xff0c;比如管理费用、研发费用等费用的明细&#xff0c;使用业务比较习惯的展示格式&#xff1b;另一方面正好综合运用前面学习的动…

通过Geopandas进行地理空间数据可视化

目录 引言 安装与导入 数据加载与探索 数据预处理 基本地图可视化 添加其他数据到地图上 空间分析与查询 地图叠加与分组 空间缓冲区 交互式地图可视化 实际应用案例 城市规划 环境监测 结论 引言 在数据科学领域,地理空间数据可视化扮演着至关重要的角色。它不…

在Vue3中使用Echarts的示例

1.常用-引用ts文件方式 1.1 导出ts文件-一个简单的柱状图 export const baseBarChart (xdata: string[], data: number[][], legendData: string[]) > {if (data.length 0) {return noData;}// 定义颜色数组const color [#00CCCC,#FF9900,#1677DC,#FF6666,#B366FF,#666…

GHCTF web方向题解

upload?SSTI! import os import refrom flask import Flask, request, jsonify,render_template_string,send_from_directory, abort,redirect from werkzeug.utils import secure_filename import os from werkzeug.utils import secure_filenameapp Flask(__name__)# 配置…

Logic-RL:小参数qwen模型复现DeepSeek R1 zero

最近很多参照DeepSeek模型训练推理模型的工作,本文将深入 “Logic-RL: Unleashing LLM Reasoning with Rule-Based Reinforcement Learning” 的论文,该论文提出了一种Rule-Based Reinforcement Learning, Logic-RL框架,旨在提升 LLM 的逻辑推理能力,在qwen2.5-7b-instruct…

CVE-2017-5645(使用 docker 搭建)

介绍: 是一个与 Apache Log4j2 相关的安全漏洞,属于远程代码执行,它可能允许攻击者通过构造恶意的日志信息 在目标系统上执行任意代码 Log4j2 介绍 Log4j2 是 Apache 的一个日志记录工具,属于 Java 应用的日志框架,它是 Log4j 的升级版,性能更好,功能更多.它被广泛的适用于 J…

蓝桥杯备考:特殊01背包问题——》集合subset

我们划分成两个集合&#xff0c;实际上我们只需要看一部分就行了&#xff0c;也就是从集合的所有元素里挑出恰好满足集合总和的一半儿&#xff0c;当然&#xff0c;如果我们的集合总和是奇数的话&#xff0c;我们是无论如何也挑不出刚好一半儿的&#xff0c;因为我们没有小数&a…

C#设计模式Demo——MVC

设计模式Demo——MVC 1.View1.1页面示例1.2View代码1.3修改界面以及代码 2.Model3.Controller4.数据结构5.枚举类型6.工具类6.1缓存信息6.2扩展类. 文件结构图 1.View 1.1页面示例 1.2View代码 using System; using System.Data; using System.Windows.Forms; using MVC模式…

【sql靶场】第18-22关-htpp头部注入保姆级教程

目录 【sql靶场】第18-22关-htpp头部注入保姆级教程 1.回顾知识 1.http头部 2.报错注入 2.第十八关 1.尝试 2.爆出数据库名 3.爆出表名 4.爆出字段 5.爆出账号密码 3.第十九关 4.第二十关 5.第二十一关 6.第二十二关 【sql靶场】第18-22关-htpp头部注入保姆级教程…

LabVIEW棉花穴播器排种自动监测系统

一、项目背景与行业痛点 1. 农业需求驱动 我国棉花主产区&#xff0c;种植面积常年超250万公顷&#xff0c;传统人工播种存在两大核心问题&#xff1a; 效率瓶颈&#xff1a;人均日播种面积不足0.5公顷&#xff0c;难以匹配规模化种植需求&#xff1b; 精度缺陷&#xff1a;人…

【程序人生】成功人生架构图(分层模型)

文章目录 ⭐前言⭐一、根基层——价值观与使命⭐二、支柱层——健康与能量⭐三、驱动层——学习与进化⭐四、网络层——关系系统⭐五、目标层——成就与财富⭐六、顶层——意义与传承⭐外层&#xff1a;调节环——平衡与抗风险⭐思维导图 标题详情作者JosieBook头衔CSDN博客专家…

速通大厂测开

最近26届暑期实习招聘和25届春招已经开始&#xff0c;测开学习圈也有同学拿到offer了 今天分享一位25届秋招圈友快速拿到大厂测开offer的经历&#xff0c;希望对大家有所帮助 我是某211本科生&#xff0c;在去年暑假准备考研的间隙意外收获了某大厂测开实习offer&#xff0c;…

基于Netty实现高性能HTTP反向代理

以下将分步骤实现一个基于Netty的高性能HTTP反向代理&#xff0c;支持动态路由、负载均衡和基础鉴权功能。 1. 项目依赖配置&#xff08;Maven&#xff09; 2. 定义路由规则 3. 实现HTTP反向代理服务端 4. 实现反向代理处理器 5. 实现基础鉴权 6. 性能优化策略 连接池管理…

【NLP 37、实践 ⑨ NER 命名实体识别任务 LSTM + CRF 实现】

难过的事情我要反复咀嚼&#xff0c;嚼到它再也不能困扰我半分 —— 25.3.13 数据文件&#xff1a; 通过网盘分享的文件&#xff1a;Ner命名实体识别任务 链接: https://pan.baidu.com/s/1fUiin2um4PCS5i91V9dJFA?pwdyc6u 提取码: yc6u --来自百度网盘超级会员v3的分享 一、配…

再学:函数可见性、特殊函数、修饰符

目录 1.可见性 2.合约特殊函数 constructor && getter 3. receive && fallback 4.view && pure 5.payable 6.自定义函数修饰符 modifier 1.可见性 public&#xff1a;内外部 private&#xff1a;内部 external&#xff1a;外部访问 internal&…