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 相关文章推荐
IE与Firefox下javascript getyear年份的兼容性写法
Dec 20 Javascript
学习ExtJS form布局
Oct 08 Javascript
js Event对象的5种坐标
Sep 12 Javascript
理解javascript中的回调函数(callback)
Sep 02 Javascript
javascript for-in有序遍历json数据并探讨各个浏览器差异
Nov 30 Javascript
javascript html5实现表单验证
Mar 01 Javascript
移动端刮刮乐的实现方式(js+HTML5)
Mar 23 Javascript
浅谈vue路径优化之resolve
Oct 13 Javascript
微信小程序实现的日期午别医生排班表功能示例
Jan 09 Javascript
vue-router命名视图的使用讲解
Jan 19 Javascript
基于Vue全局组件与局部组件的区别说明
Aug 11 Javascript
Vue.js暴露方法给WebView的使用操作
Sep 07 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/03/12 PHP
php写入、删除与复制文件的方法
2015/06/20 PHP
laravel框架 api自定义全局异常处理方法
2019/10/11 PHP
你必须知道的JavaScript 中字符串连接的性能的一些问题
2013/05/07 Javascript
多次注册事件会导致一个事件被触发多次的解决方法
2013/08/12 Javascript
JS中的构造函数详细解析
2014/03/10 Javascript
JavaScript开发人员的10个关键习惯小结
2014/12/05 Javascript
概述VUE2.0不可忽视的很多变化
2016/09/25 Javascript
JS文件上传神器bootstrap fileinput详解
2021/01/28 Javascript
JS 拦截全局ajax请求实例解析
2016/11/29 Javascript
JavaScript实现短暂提示框功能
2018/04/04 Javascript
Vuex入门到上手教程
2018/06/20 Javascript
vue-cli3.0+element-ui上传组件el-upload的使用
2018/12/03 Javascript
用Electron写个带界面的nodejs爬虫的实现方法
2019/01/29 NodeJs
koa+jwt实现token验证与刷新功能
2019/05/30 Javascript
微信小程序以7天为周期连续签到7天功能效果的示例代码
2020/08/20 Javascript
design vue 表格开启列排序的操作
2020/10/28 Javascript
vue实现动态给id赋值,点击事件获取当前点击的元素的id操作
2020/11/09 Javascript
JS指定音频audio在某个时间点进行播放
2020/11/28 Javascript
[01:59][TI9趣味视频] 全明星赛奖励
2019/08/23 DOTA
编写Python脚本来获取Google搜索结果的示例
2015/05/04 Python
给Python入门者的一些编程建议
2015/06/15 Python
Python爬虫信息输入及页面的切换方法
2018/05/11 Python
Python GUI Tkinter简单实现个性签名设计
2018/06/19 Python
python bmp转换为jpg 并删除原图的方法
2018/10/25 Python
Python识别快递条形码及Tesseract-OCR使用详解
2019/07/15 Python
Python-jenkins 获取job构建信息方式
2020/05/12 Python
Python API 操作Hadoop hdfs详解
2020/06/06 Python
python使用多线程查询数据库的实现示例
2020/08/17 Python
澳大利亚的奢侈品牌:Oroton
2016/08/26 全球购物
澳大利亚吉他在线:Artist Guitars
2017/03/30 全球购物
公司出纳岗位职责
2013/12/07 职场文书
本科毕业生求职自荐信
2014/02/03 职场文书
犯错检讨书
2014/02/21 职场文书
pytest配置文件pytest.ini的详细使用
2021/04/17 Python
Java版 单机五子棋
2022/05/04 Java/Android