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 相关文章推荐
多种方法实现load加载完成后把图片一次性显示出来
Feb 19 Javascript
JS倒计时代码汇总
Nov 25 Javascript
js实现图片旋转 js滚动鼠标中间对图片放大缩小
Jul 05 Javascript
zTree异步加载展开第一级节点的实现方法
Sep 05 Javascript
JS实现十字坐标跟随鼠标效果
Dec 25 Javascript
jQuery实现菜单的显示和隐藏功能示例
Jul 24 jQuery
vue生命周期实例小结
Aug 15 Javascript
require.js 加载过程与使用方法介绍
Oct 30 Javascript
详解在vue-test-utils中mock全局对象
Nov 07 Javascript
JS+canvas画布实现炫酷的旋转星空效果示例
Feb 13 Javascript
小程序多图列表实现性能优化的方法步骤
May 28 Javascript
Javascript数组及类数组相关原理详解
Oct 29 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循环语句笔记(foreach,list)
2011/11/29 PHP
php引用计数器进行垃圾收集机制介绍
2012/09/19 PHP
一组PHP加密解密函数分享
2014/06/05 PHP
Thinkphp中volist标签mod控制一定记录的换行BUG解决方法
2014/11/04 PHP
ThinkPHP2.x防范XSS跨站攻击的方法
2015/09/25 PHP
PHP删除字符串中非字母数字字符方法总结
2019/01/20 PHP
JavaScript中的细节分析
2012/06/30 Javascript
js截取中英文字符串、标点符号无乱码示例解读
2014/04/17 Javascript
Google官方支持的NodeJS访问API,提供后台登录授权
2014/07/29 NodeJs
前端js文件合并的三种方式推荐
2016/05/19 Javascript
微信小程序 生命周期详解
2016/10/12 Javascript
微信小程序 详解Page中data数据操作和函数调用
2017/01/12 Javascript
Javascript基础回顾之(二) js作用域
2017/01/31 Javascript
js实现文字列表无缝滚动效果
2017/06/23 Javascript
Javascript 一些需要注意的细节(必看篇)
2017/07/08 Javascript
Vue单页应用引用单独的样式文件的两种方式
2018/03/30 Javascript
使用vue-cli脚手架工具搭建vue-webpack项目
2019/01/14 Javascript
node.js 基于cheerio的爬虫工具的实现(需要登录权限的爬虫工具)
2019/04/10 Javascript
javascript实现对话框功能警告(alert 消息对话框)确认(confirm 消息对话框)
2019/05/07 Javascript
解决axios post 后端无法接收数据的问题
2019/10/29 Javascript
Vue中多元素过渡特效的解决方案
2020/02/05 Javascript
Python实现身份证号码解析
2015/09/01 Python
Python复制文件操作实例详解
2015/11/10 Python
Python 探针的实现原理
2016/04/23 Python
Python编程之变量赋值操作实例分析
2017/07/24 Python
选择python进行数据分析的理由和优势
2019/06/25 Python
Python绘图实现显示中文
2019/12/04 Python
ipython jupyter notebook中显示图像和数学公式实例
2020/04/15 Python
新加坡航空官方网站:Singapore Airlines
2016/10/13 全球购物
英国最大的婴儿监视器网上商店:Baby Monitors Direct
2018/04/24 全球购物
关于九一八事变的演讲稿2014
2014/09/17 职场文书
学前班语言教学计划
2015/01/20 职场文书
我们的节日元宵节活动总结
2015/02/06 职场文书
道德与公民自我评价
2015/03/09 职场文书
详解python网络进程
2021/06/15 Python
mybatis源码解读之executor包语句处理功能
2022/02/15 Java/Android