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 相关文章推荐
jquery easyui的tabs使用时的问题
Mar 23 Javascript
jQuery JSON实现无刷新三级联动实例探讨
May 28 Javascript
JQuery实现表格中相同单元格合并示例代码
Jun 26 Javascript
详谈JavaScript 匿名函数及闭包
Nov 14 Javascript
什么是 AngularJS?AngularJS简介
Dec 06 Javascript
基于JavaScript实现点击页面任何位置返回
Aug 31 Javascript
通过循环优化 JavaScript 程序
Jun 24 Javascript
微信小程序身份证验证方法实现详解
Jun 28 Javascript
JS document对象简单用法完整示例
Jan 14 Javascript
vue键盘事件点击事件加native操作
Jul 27 Javascript
JavaScript ES 模块的使用
Nov 12 Javascript
vue.js watch经常失效的场景与解决方案
Jan 07 Vue.js
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
PHP中file_exists函数不支持中文名的解决方法
2014/07/26 PHP
PHP Streams(流)详细介绍及使用
2015/05/12 PHP
php从文件夹随机读取文件的方法
2015/06/01 PHP
PHP设计模式之观察者模式实例
2016/02/22 PHP
数组方法解决JS字符串连接性能问题有争议
2011/01/12 Javascript
javascript学习基础笔记之DOM对象操作
2011/11/03 Javascript
jquery选择器之基本过滤选择器详解
2014/01/27 Javascript
transport.js和jquery冲突问题的解决方法
2015/02/10 Javascript
jquery append 动态添加的元素事件on 不起作用的解决方案
2015/07/30 Javascript
js时间戳转为日期格式的方法
2015/12/28 Javascript
js密码强度检测
2016/01/07 Javascript
JQuery核心函数是什么及使用方法介绍
2016/05/03 Javascript
JS加载器如何动态加载外部js文件
2016/05/26 Javascript
BootStrap智能表单实战系列(四)表单布局介绍
2016/06/13 Javascript
基于BootStrap的Metronic框架实现页面链接收藏夹功能按钮移动收藏记录(使用Sortable进行拖动排序)
2016/08/29 Javascript
深入理解bootstrap框架之第二章整体架构
2016/10/09 Javascript
vue中如何动态绑定图片,vue中通过data返回图片路径的方法
2018/02/07 Javascript
angular6的响应式表单的实现
2018/10/10 Javascript
微信小程序 网络通信实现详解
2019/07/23 Javascript
element中Steps步骤条和Tabs标签页关联的解决
2020/12/08 Javascript
python实现的AES双向对称加密解密与用法分析
2017/05/02 Python
Flask数据库迁移简单介绍
2017/10/24 Python
tornado 多进程模式解析
2018/01/15 Python
Linux-ubuntu16.04 Python3.5配置OpenCV3.2的方法
2018/04/02 Python
解决Python3中的中文字符编码的问题
2018/07/18 Python
爬虫代理池Python3WebSpider源代码测试过程解析
2019/12/20 Python
浅谈keras 模型用于预测时的注意事项
2020/06/27 Python
keras分类之二分类实例(Cat and dog)
2020/07/09 Python
五一手机促销方案
2014/03/08 职场文书
婚礼主持词开场白
2014/03/13 职场文书
车辆年检委托书范本
2014/10/14 职场文书
幼儿园小班见习报告
2014/10/31 职场文书
薪资证明范本
2015/06/19 职场文书
python基于turtle绘制几何图形
2021/06/15 Python
关于JavaScript回调函数的深入理解
2021/06/27 Javascript
Python PIL按比例裁剪图片
2022/05/11 Python