js实现简单贪吃蛇游戏


Posted in Javascript onMay 15, 2020

本文实例为大家分享了js实现简单贪吃蛇游戏的具体代码,供大家参考,具体内容如下

上下左右键控制方向使贪吃蛇吃葡萄
吃5个葡萄,游戏结束时左上角为总得分。

运行结果:

js实现简单贪吃蛇游戏

界面和css代码这里就不加赘述了,主要贴js代码(加了注释):

var config = {
 width: 20, //一个格子的宽度
 height: 20, //一个格子的高度
 tr: 30, //行数
 td: 30 //列数
}
var snake = null, //Snake的实例
 food = null, //Food的实例
 game = null; //游戏的实例

//我们把蛇移动的整个区域设置成一个具有30列30行的网格坐标
//方块(格子)坐标位置
/**
0,0 (0,0)
20,0 (1,0)
40,0 (2,0)
*/
function Square(x, y, className) {
 this.x = x*config.width;
 this.y = y*config.height;
 this.className = className;
 this.contentDom = document.createElement('div');//该位置的方块对应的DOM元素
 this.contentDom.className = this.className;
 this.parent = document.getElementsByClassName("innerSnake")[0];

}
Square.prototype.create = function() { //创建方块并添加到页面
 this.contentDom.style.position = 'absolute';
 this.contentDom.style.width = config.width + 'px';
 this.contentDom.style.height = config.height + 'px';
 this.contentDom.style.left = this.x + 'px';
 this.contentDom.style.top = this.y + 'px';

 this.parent.appendChild(this.contentDom);
};
Square.prototype.remove = function() { //移除方块
 this.parent.removeChild(this.contentDom);
};

//蛇
function Snake() {
 this.head = null; //蛇头
 this.tail = null; //蛇尾
 this.pos = []; //二维数组,存储蛇身上每个节点(方块)
 this.directionKey = { //存储蛇走的方向
 left: { //往左走
 x: -1, //横坐标减1,一个坐标表示一个格子
 y: 0, //纵坐标不变
 rotate: 90
 },
 right: { //往右走
 x: 1,
 y: 0,
 rotate: -90
 },
 up: { //往上走
 x: 0,
 y: -1,
 rotate: 180
 },
 down: { //往下走
 x: 0,
 y: 1,
 rotate: 0 //蛇头图片方向,顺时针为正
 }
 }
}
Snake.prototype.init = function() { //初始化蛇
 //蛇头
 var snakeHead = new Square(2,0,"head");
 snakeHead.create(); //将蛇头添加到界面
 this.head = snakeHead; //存储蛇头信息
 this.pos.push([2,0]); //存储蛇头坐标

 //蛇的第1节身体
 var snakeBody1 = new Square(1,0,"body");
 snakeBody1.create(); //将蛇的第一节身体添加到界面
 this.pos.push([1,0]);

 //蛇的尾巴
 var snakeTail = new Square(0,0,"body");
 snakeTail.create(); //将蛇尾添加到界面
 this.tail = snakeTail; //存储蛇尾信息
 this.pos.push([0,0]);

 //形成链表关系
 snakeHead.prev = null; //蛇头的前面没有元素,指向null
 snakeHead.next = snakeBody1; //蛇头的后面有一节身体,其.next指针指向后面那节身体

 snakeBody1.prev = snakeHead; //蛇的第一节身体,.prev指向前面的蛇头snakeHead
 snakeBody1.next = snakeTail; //蛇的第一节身体,.next指向后面的身体,此时是蛇尾snakeTail

 snakeTail.prev = snakeBody1; //蛇尾,.prev指向前面的蛇身体snakeBody1
 snakeTail.next = null; //蛇尾后面没有元素,指向Null

 //初始蛇的走向,后面想改变蛇的走向即改变this.direction
 this.direction = this.directionKey.right; //默认向右走

};

//获取蛇头下一个位置对应的元素,根据元素做下一个动作
Snake.prototype.getNextPos = function() {
 var nextPos = [ //获取蛇头走的下一个点的坐标
  this.head.x / config.width + this.direction.x,
  this.head.y / config.height + this.direction.y
 ];

 //判断下一个点是自己or食物or围墙or无障碍?
 var self = false; //设置下一个点是否是自己
 this.pos.forEach(function(val) { //val即二位数组中的一个坐标
 if(val.toString() === nextPos.toString()) { //下一个坐标等于蛇全部身体的一个,即下一个点是自己
    self = true;
  }
 });
 if(self) {
 // console.log('撞到自己了!');
 this.collide.end.call(this); //game over

 return;
 } else if(nextPos[0] < 0 || nextPos[1] < 0 || nextPos[0] > config.td-1 || nextPos[1] > config.tr-1) {
 // console.log('撞到墙壁了!');
 this.collide.end.call(this); //game over

 return;
 } else if (food && food.pos[0] === nextPos[0] && food.pos[1] === nextPos[1]) {
 console.log('撞到食物了!');
 this.collide.eat.call(this);
 } else {
 // console.log('啥都没遇到!');
 this.collide.move.call(this, false); //注意:.call(this)重新设置this指向,使其指向当前实例对象Snake
 }
 

};

//处理碰撞后的事件
Snake.prototype.collide = {
 /*
 碰到自己or墙壁,游戏结束end();
 碰到食物,eat();
 啥都没遇到,move();
 */
 move: function(isEat) { //isEat 是否吃了食物,不是则删除蛇尾
 /*
 掐头去尾:
 create新蛇头,remove旧蛇头;
 create一个新身体,放在(替代)旧蛇头的位置;
 remove蛇尾,蛇尾prev的元素变成新蛇尾
 */
 var x = this.head.x / config.width + this.direction.x,
  y = this.head.y / config.height + this.direction.y;
 //声明一个新身体
 var newBody = new Square(this.head.x/config.width, this.head.y/config.height, "body");
 //更新链表关系
 newBody.next = this.head.next;
 newBody.next.prev = newBody;
 newBody.prev = null;

 this.head.remove(); //删除旧蛇头
 newBody.create(); //添加蛇身体,替代在旧蛇头位置

 //声明一个新蛇头(下一个走的点)
  var newHead = new Square(x, y, "head");
  //更新链表关系
  newHead.prev = null;
  newHead.next = newBody;
  newBody.prev = newHead;

  this.pos.unshift([x, y]); //更新蛇节点的坐标this.pos
  this.head = newHead; //更新this.head的信息
  
  newHead.contentDom.style.transform = `rotate(${this.direction.rotate}deg)`
  newHead.create(); //添加蛇头

  //删除蛇尾:吃食物则不删
  if(!isEat) { //没有吃食物,删除蛇尾
  this.tail.remove();
  this.tail = this.tail.prev;

  this.pos.pop(); //更新蛇节点坐标
  }
  // console.log(this.pos); //打印数组,验证
 },
 eat: function() {
 this.collide.move.call(this, true); //传参true,表示此时为吃操作
 food.remove(); //删除被吃掉的食物
 game.score ++; //记录分数
 createFood(); //此时再随机产生一个食物
 },
 end: function() {
 console.log('end');
 game.gameOver();
 }

}

snake = new Snake();

//创建食物
function createFood() {
 var x = null, y = null;
 var include = true; //表示食物的位置是否在蛇身上
 var random = function(max, min) { //产生一个随机数
 return Math.floor(Math.random()*(max - min + 1))
 };
 while(include) {
 x = random(config.tr - 1, 0);
 y = random(config.td - 1, 0);

 snake.pos.forEach(function(val) {
 if(x != val[0] && y != val[1]) {
 include = false;
 }
 });
 }

 //生成食物
 food = new Square(x, y, "food");
 food.pos = [x, y]; //记录食物坐标
 food.create();
}

//游戏逻辑
function Game() {
 this.score = 0; //分数
 this.timer = null; //计时器
}
Game.prototype.init = function() {
 snake.init();
 // snake.getNextPos(); //获取下一个点坐标
 createFood();

 document.onkeydown = function(event) {
 if(event.which == 37 && snake.direction != snake.directionKey.right) { 
  //鼠标左键,蛇不能是正在往右走
 snake.direction = snake.directionKey.left;
 } else if (event.which == 38 && snake.direction != snake.directionKey.down) { 
 //鼠标上键
 snake.direction = snake.directionKey.up;
 } else if (event.which == 39 && snake.direction != snake.directionKey.left) { 
 //鼠标右键
 snake.direction = snake.directionKey.right;
 } else if (event.which == 40 && snake.direction != snake.directionKey.up) { 
 //鼠标下键
 snake.direction = snake.directionKey.down;
 }
 }
 this.start();
};
game = new Game();
//开始游戏
Game.prototype.start = function() {
 this.timer = setInterval(function() {
 snake.getNextPos(); //获取下一个坐标点,做下一步动作
 }, 200);
};
//游戏结束
Game.prototype.gameOver = function() {
 console.log("gameOver");
 clearInterval(this.timer);
 var gameOver = document.querySelector('.gameOver');
 var gameScore = document.querySelector('.gameOver .score');
 gameOver.style.display = 'block'; //显示游戏结束界面
 gameScore.innerHTML = `${this.score}`; //将分数记入该界面
};

//开启游戏
function startGame() {
 var startBtn = document.querySelector('.btn button');
 var snakeWrap = document.querySelector('.snakeWrap');
 startBtn.onclick = function() {
 startBtn.parentNode.style.display = 'none'; //隐藏开始游戏界面
  snakeWrap.style.display = 'block'; //显示进入游戏的界面
  game.init();

 }
}
startGame();

主要用到链表数据结构

更多有趣的经典小游戏实现专题,也分享给大家:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
新增加的内容是如何将div的scrollbar自动移动最下面
Jan 02 Javascript
深入理解JavaScript系列(29):设计模式之装饰者模式详解
Mar 03 Javascript
js控住DOM实现发布微博效果
Aug 30 Javascript
自制微信公众号一键排版工具
Sep 22 Javascript
JavaScript中关于for循环删除数组元素内容时出现的问题
Nov 21 Javascript
JQuery查找子元素find()和遍历集合each的方法总结
Mar 07 Javascript
layui选项卡效果实现代码
May 19 Javascript
js通过Date对象实现倒计时动画效果
Oct 27 Javascript
vue 开发一个按钮组件的示例代码
Mar 27 Javascript
vue elementUI使用tabs与导航栏联动
Jun 21 Javascript
Node.js API详解之 Error模块用法实例分析
May 14 Javascript
JavaScript实现五子棋小游戏
Oct 26 Javascript
Javascript执行流程细节原理解析
May 14 #Javascript
使用npm命令提示: 'npm' 不是内部或外部命令,也不是可运行的程序的处理方法
May 14 #Javascript
javascript中的offsetWidth、clientWidth、innerWidth及相关属性方法
May 14 #Javascript
vue组件系列之TagsInput详解
May 14 #Javascript
ant-design-vue按需加载的坑的解决
May 14 #Javascript
JavaScript数组排序功能简单实现
May 14 #Javascript
Typescript3.9 常用新特性一览(推荐)
May 14 #Javascript
You might like
php 格式化数字的时候注意数字的范围
2010/04/13 PHP
thinkphp的静态缓存用法分析
2014/11/29 PHP
php页面跳转session cookie丢失导致不能登录等问题的解决方法
2016/12/12 PHP
PHP ADODB实现分页功能简单示例
2018/05/25 PHP
php ajax confirm 删除实例详解
2019/03/06 PHP
php的优点总结 php有哪些优点
2019/07/19 PHP
一个可以兼容IE FF的加为首页与加入收藏实现代码
2009/11/02 Javascript
点击进行复制的JS代码实例
2013/08/23 Javascript
倒记时60刷新网页的js代码
2014/02/18 Javascript
理解JavaScript中worker事件api
2015/12/25 Javascript
Javascript点击按钮随机改变数字与其颜色
2016/09/01 Javascript
原生JS与jQuery编写简单选项卡
2017/10/30 jQuery
详解最新vue-cli 2.9.1的webpack存在问题
2017/12/16 Javascript
微信小程序实现的涂鸦功能示例【附源码下载】
2018/01/12 Javascript
微信小程序异步API为Promise简化异步编程的操作方法
2018/08/14 Javascript
vue form check 表单验证的实现代码
2018/12/09 Javascript
Vue项目总结之webpack常规打包优化方案
2019/06/06 Javascript
webpack4.0+vue2.0利用批处理生成前端单页或多页应用的方法
2019/06/28 Javascript
《javascript设计模式》学习笔记七:Javascript面向对象程序设计组合模式详解
2020/04/08 Javascript
使用konva和vue-konva库实现拖拽滑块验证功能
2020/04/27 Javascript
[01:10:58]Spirit vs NB Supermajor小组赛 A组败者组决赛 BO3 第二场 6.2
2018/06/03 DOTA
[01:09:13]DOTA2-DPC中国联赛 正赛 CDEC vs XG BO3 第三场 1月19日
2021/03/11 DOTA
Python中的super()方法使用简介
2015/08/14 Python
特征脸(Eigenface)理论基础之PCA主成分分析法
2018/03/13 Python
Python序列循环移位的3种方法推荐
2018/04/09 Python
Python退火算法在高次方程的应用
2018/07/26 Python
python3中rank函数的用法
2019/11/27 Python
Python Mock模块原理及使用方法详解
2020/07/07 Python
Python实现冒泡排序算法的完整实例
2020/11/04 Python
css3背景_动力节点Java学院整理
2017/07/11 HTML / CSS
波兰多品牌运动商店:StreetStyle24.pl
2020/09/22 全球购物
写出二分查找算法的两种实现
2013/05/13 面试题
大学生优秀自荐信范文
2014/02/25 职场文书
网络舆情信息简报
2015/07/21 职场文书
MySQL系列之六 用户与授权
2021/07/02 MySQL
Python实现自动玩连连看的脚本分享
2022/04/04 Python