javascript实现贪吃蛇经典游戏


Posted in Javascript onApril 10, 2020

js面向对象编程之贪吃蛇,供大家参考,具体内容如下

首先:面向对象编程,我们要找到项目中具体的对象,此处为(食物(food),蛇(snake),游戏本身(game))也可不把游戏本身作为对象,逻辑体现出来即可。

接着分析每个对象的具体的属性及方法:
1)food 对象:属性有:位置,大小,颜色;方法有:渲染在页面,随机不同位置生成;
2)snake对象:属性有:位置,大小,总节数(计分方便),颜色;方法有:渲染在页面,移动(移动过程中判断其它)。
3)game对象:游戏逻辑的编写;

ok 开敲:

1)简单的静态页面编写(地图)

(1)html

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <link rel="stylesheet" href="css/index.css" >
 <script src="js/food.js"></script>
 <script src="js/snake.js"></script>
 <script src="js/game.js"></script>
 <script src="js/main.js"></script>
 <title>贪吃蛇</title>
</head>
<body>
 <div class="map"></div>
</body>
</html>

(2)css(如果用边框来作为限制的边界,那么box-sizing属性是必不可少的(以免食物和蛇头坐标之间存在误差))

* {
 margin: 0;
 padding: 0;
}

.map {
 position: relative;
 height: 600px;
 width: 800px;
 border: 1px solid #333;
 margin: 0 auto;
 /* 盒子模型去除边框 */
 box-sizing: border-box;
}

2)food对象编写(细节处含注释)

//cwen加载页面所有元素
window.addEventListener('load', function() {

 //cwen自调用函数,开启一个新的作用域,避免命名冲突
 (function() {

 //cwen定义全局变量
 //实物数组
 var elements = [];
 //cwen实物
 function Food(options) {
  options = options || {};
  this.x = options.x || 0;
  this.y = options.y || 0;
  this.width = options.width || 20;
  this.height = options.height || 20;
  this.color = options.color || 'yellow';
 }


 //cwen随机数函数
 function getRandom(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
 }
 //cwen渲染
 Food.prototype.render = function(map) {
  //删除之前的食物
  remove();
  //todo动态创建div实物
  var div = document.createElement('div');
  map.appendChild(div);
  //把div添加给数组
  elements.push(div);
  //todo随机设置x,y的值(实物的位置)-----在map中生成随机位置
  // ! 值 = Math.floor(Math.random() * 可能值得总数 + 第一个可能的值)
  this.x = getRandom(0, map.offsetWidth / this.width - 1) * this.width;
  this.y = getRandom(0, map.offsetHeight / this.height - 1) * this.height;
  div.style.position = 'absolute';
  div.style.left = this.x + 'px';
  div.style.top = this.y + 'px';
  div.style.width = this.width + 'px';
  div.style.height = this.height + 'px';
  div.style.backgroundColor = this.color;
 }

 function remove() {
  //为了删除干净,从索引最大的开始循环删除
  for (var i = elements.length - 1; i >= 0; i--) {
  //删除遍历到的div
  elements[i].parentNode.removeChild(elements[i]);
  //删除数组中的元素1)第几个开始,2)要删除个数
  elements.splice(i, 1);
  }
 }

 //把Food开放出去
 window.Food = Food;
 })()
 
 //cwen测试
 // var map = document.querySelector('.map');
 // var options = { x: 20, y: 20, width: 30, height: 30, color: 'green' };
 // //todo不传值默认为自定义food
 // var food = new Food();
 // food.render(map);
})

3)snake对象编写()

window.addEventListener('load', function() {
 (function() {
 //记录蛇的每一节
 var elements = [];
 //cwen立即执行函数,开启新的作用于,避免命名冲突
 function Snake(options) {
  options = options || {};
  //对象(蛇)每节的大小
  this.width = options.width || 20;
  this.height = options.height || 20;
  //cwen蛇的总节数(计分)
  this.mark = options.mark || 0;
  //对象的移动方向
  this.direction = options.direction || 'right';
  //对象的身体(蛇节)
  this.kont = [{ x: 3, y: 2, color: 'red' }, { x: 2, y: 2, color: 'black' }, { x: 1, y: 2, color: 'black' }];
 }

 //cwen渲染对象
 Snake.prototype.render = function(map) {
  //移除之前的蛇
  remove();
  //循环输出对象的身体(蛇节)
  for (var i = 0, len = this.kont.length; i < len; i++) {
  var obj = this.kont[i];
  var div = document.createElement('div');
  map.appendChild(div);
  //将蛇节添加入数组
  elements.push(div);
  //添加样式
  div.style.position = 'absolute';
  div.style.width = this.width + 'px';
  div.style.height = this.height + 'px';
  div.style.left = obj.x * this.width + 'px';
  div.style.top = obj.y * this.height + 'px';
  div.style.backgroundColor = obj.color;
  }
 }

 //cwen控制蛇移动的方法
 //todo传参food,map 在game中调用move方法也要传入相应参数
 Snake.prototype.move = function(food, map) {
  //控制蛇节的移动(当前蛇节到下一个蛇节的位置)
  for (var i = this.kont.length - 1; i > 0; i--) {
  this.kont[i].x = this.kont[i - 1].x;
  this.kont[i].y = this.kont[i - 1].y;
  }

  //判断并控制蛇头移动,判断蛇头移动方向
  var head = this.kont[0];
  switch (this.direction) {
  case 'right':
   head.x += 1;
   break;
  case 'left':
   head.x -= 1;
   break;
  case 'top':
   head.y -= 1;
   break;
  case 'bottom':
   head.y += 1;
   break;
  }


  //蛇头碰到食物时处理
  // cwen判断蛇头是否和食物坐标重合
  var headX = head.x * this.width;
  var headY = head.y * this.height;
  if (headX == food.x && headY == food.y) {
  //1,增加蛇节(找到最后一根蛇节,然后添加给创建的蛇数组)
  var last = this.kont[this.kont.length - 1];
  this.kont.push({ x: last.x, y: last.y, color: last.color });
  //cwen求出蛇节的总个数(计分)
  var mark = this.mark++;
  //2,重新渲染食物
  food.render(map);
  }
 }


 //删除之前的蛇
 function remove() {
  for (var i = elements.length - 1; i >= 0; i--) {
  elements[i].parentNode.removeChild(elements[i]);
  elements.splice(i, 1);
  }
 }

 //把Snake构造函数暴露出去
 window.Snake = Snake;
 })()
 //测试
 // var map = document.querySelector('.map');
 // var snake = new Snake();
 // snake.render(map);
})

4)game对象编写,其中一个为无敌版(含细节注释)

window.addEventListener('load', function() {
 (function() {
 //改变计时器内this指向
 var that;

 function Game(map) {
  // var options = { x: 20, y: 20, width: 30, height: 30, color: 'green' };
  this.food = new Food();
  this.snake = new Snake();
  this.map = map;
  that = this;
 }
 //cwen渲染
 Game.prototype.start = function() {
  // 1.把食物和蛇渲染到页面
  this.food.render(this.map);
  this.snake.render(this.map);
  // 2.游戏逻辑编写
  //让蛇动起来
  //判断地图边界
  // runSnake();
  //todo判断玩法(两种模式,原理一样)
  goInput();
  //通过键盘控制蛇头方向
  //! keydown();
  //蛇头碰到食物时处理
  //在snake.js中判断
 }

 function goInput() {
  var it = prompt('try:\n 经典玩法请按1\n 无敌玩法请输入(博主最帅)\n')
  if (it == 1) {
  runSnake();
  keydown();
  } else if (it == '博主最帅') {
  runSnake1();
  keydown1();
  } else {
  alert('you input could not be found!!!');
  goInput();
  }
 }


 //让蛇动起来
 function runSnake() {
  var timeId = setInterval(function() {
  // var a = mark;
  that.snake.move(that.food, that.map);
  that.snake.render(that.map);

  //判断地图边界
  var maxX = (that.map.offsetWidth) / that.snake.width;
  var maxY = (that.map.offsetHeight) / that.snake.height;
  var headX = that.snake.kont[0].x;
  var headY = that.snake.kont[0].y;
  if (headX < 0 || headX >= maxX) {
   alert('Game Over ' + '得分为 ' + that.snake.mark);
   clearInterval(timeId);
  } else if (headY < 0 || headY >= maxY) {
   alert('Game Over ' + '成绩为 ' + that.snake.mark);
   clearInterval(timeId);
  }
  }, 150)
 }


 //无敌版本蛇运动
 function runSnake1() {
  var timeId1 = setInterval(function() {
  that.snake.move(that.food, that.map);
  that.snake.render(that.map);

  //判断地图边界
  var maxX = (that.map.offsetWidth - that.snake.width) / that.snake.width;
  var maxY = (that.map.offsetHeight - that.snake.height) / that.snake.height;
  var headX = that.snake.kont[0].x;
  var headY = that.snake.kont[0].y;

  if (headX < 0) {
   that.snake.kont[0].x = (that.map.offsetWidth - that.snake.width) / that.snake.width;
  } else if (headX > maxX) {
   that.snake.kont[0].x = 0;
  } else if (headY < 0) {
   that.snake.kont[0].y = (that.map.offsetHeight - that.snake.height) / that.snake.height;
  } else if (headY > maxY) {
   that.snake.kont[0].y = 0;
  }
  }, 50)
 }



 //通过键盘控制蛇头方向
 function keydown() {
  document.addEventListener('keydown', function(e) {
  //通过事件对象判断按了哪个键 37left,38top,39right,40bottom
  // console.log(e.keyCode);
  //其在走的同时按下反方向无用
  if (e.keyCode == 37 && that.snake.direction != 'right') {
   that.snake.direction = 'left';
  } else if (e.keyCode == 38 && that.snake.direction != 'bottom') {
   that.snake.direction = 'top';
  } else if (e.keyCode == 39 && that.snake.direction != 'left') {
   that.snake.direction = 'right';
  } else if (e.keyCode == 40 && that.snake.direction != 'top') {
   that.snake.direction = 'bottom';
  }
  });
 }


 function keydown1() {
  document.addEventListener('keydown', function(e) {
  //通过事件对象判断按了哪个键 37left,38top,39right,40bottom
  // console.log(e.keyCode);
  //无敌版本四面八方任你行
  if (e.keyCode == 37) {
   that.snake.direction = 'left';
  } else if (e.keyCode == 38) {
   that.snake.direction = 'top';
  } else if (e.keyCode == 39) {
   that.snake.direction = 'right';
  } else if (e.keyCode == 40) {
   that.snake.direction = 'bottom';
  }
  });
 }


 //把Game开放
 window.Game = Game;
 })()
})

5)main开启游戏

window.addEventListener('load', function() {
 (function(window, undefind) {
 //测试
 var map = document.querySelector('.map');
 var game = new Game(map);
 game.start();

 })(window, undefined)
})

last but not least
*建议把所有js文件写在同一个js文件中,可以大大提高加载速度。注意在每个立即执行函数前加上‘ ;',以免出错。

小编还为大家准备了精彩的专题:javascript经典小游戏汇总

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

Javascript 相关文章推荐
IE8 兼容性问题(属性名区分大小写)
Jun 04 Javascript
始终在屏幕中间显示Div的代码(css+js)
Mar 10 Javascript
JS防止用户多次提交的简单代码
Aug 01 Javascript
js实现的点击数量加一可操作数据库
May 09 Javascript
jquery实现人性化的有选择性禁用鼠标右键
Jun 30 Javascript
js中iframe调用父页面的方法
Oct 30 Javascript
node.js中的buffer.copy方法使用说明
Dec 14 Javascript
JavaScript在form表单中使用button按钮实现submit提交方法
Jan 23 Javascript
Angularjs+bootstrap+table多选(全选)支持单击行选中实现编辑、删除功能
Mar 27 Javascript
JS中数据结构之栈
Jan 01 Javascript
详解Nuxt.js中使用Element-UI填坑
Sep 06 Javascript
小程序识别身份证,银行卡,营业执照,驾照的实现
Nov 05 Javascript
javascript设计模式 ? 原型模式原理与应用实例分析
Apr 10 #Javascript
Quasar Input:type=&quot;number&quot; 去掉上下小箭头 实现加减按钮样式功能
Apr 09 #Javascript
vue中的过滤器及其时间格式化问题
Apr 09 #Javascript
微信小程序保存图片到相册权限设置
Apr 09 #Javascript
微信小程序仿通讯录功能
Apr 09 #Javascript
vue cli4下环境变量和模式示例详解
Apr 09 #Javascript
微信小程序实现组件顶端固定或底端固定效果(不随滚动而滚动)
Apr 09 #Javascript
You might like
使用Smarty 获取当前日期时间和格式化日期时间的方法详解
2013/06/18 PHP
Laravel 中使用 Vue.js 实现基于 Ajax 的表单提交错误验证操作
2017/06/30 PHP
xml文档转换工具,附图表例子(hta)
2010/11/17 Javascript
js常用数组操作方法简明总结
2014/06/20 Javascript
js生成验证码并直接在前端判断
2015/05/15 Javascript
使用jspdf生成pdf报表
2015/07/03 Javascript
jquery实现清新实用的网页菜单效果
2015/08/28 Javascript
WordPress中鼠标悬停显示和隐藏评论及引用按钮的实现
2016/01/12 Javascript
如何高效率去掉js数组中的重复项
2016/04/12 Javascript
Angularjs结合Bootstrap制作的一个TODO List
2016/08/18 Javascript
基于JS组件实现拖动滑块验证功能(代码分享)
2016/11/18 Javascript
简单实现jQuery多选框功能
2017/01/09 Javascript
canvas绘制一个常用的emoji表情
2017/03/30 Javascript
input type=file 选择图片并且实现预览效果的实例
2017/10/26 Javascript
vue父组件点击触发子组件事件的实例讲解
2018/02/08 Javascript
jQuery实现鼠标响应式透明度渐变动画效果示例
2018/02/13 jQuery
JavaScript 预解析的4种实现方法解析
2019/09/03 Javascript
Vue.js原理分析之nextTick实现详解
2020/09/07 Javascript
[01:03:36]Ti4 循环赛第三日DK vs Titan
2014/07/12 DOTA
[07:55]2014DOTA2 TI正赛第三日 VG上演推进荣耀DKEG告别
2014/07/21 DOTA
Python中删除文件的程序代码
2011/03/13 Python
使用Python进行新浪微博的mid和url互相转换实例(10进制和62进制互算)
2014/04/25 Python
python实现写数字文件名的递增保存文件方法
2018/10/25 Python
python将字母转化为数字实例方法
2019/10/04 Python
python循环输出三角形图案的例子
2019/11/22 Python
Python之Matplotlib文字与注释的使用方法
2020/06/18 Python
pyqt5 textEdit、lineEdit操作的示例代码
2020/08/12 Python
Get The Label中文官网:英国运动时尚购物平台
2017/04/19 全球购物
PHP如何自定义函数
2016/09/16 面试题
Python如何实现单例模式
2016/06/03 面试题
毕业实习评语
2014/02/10 职场文书
离职证明范本(5篇)
2014/09/19 职场文书
初中教师个人工作总结
2015/02/10 职场文书
公务员年度个人总结
2015/02/12 职场文书
担保书格式范文
2015/09/22 职场文书
详解Redis瘦身指南
2021/05/26 Redis