此代码存在一定的小bug,当蛇出边界之后存在一定的小问题
分析贪吃蛇功能需求:
1.食物
(1)每次生成一个,位置随意但不可超出规定范围
(2)每次蛇吃到食物之后,前一个食物消失同时新的食物又生成
(3)属性:大小、颜色、位置
2.蛇
(1)属性:长度,颜色,位置、方向
(2)每吃掉一个食物,蛇尾新增一节,默认方向向右
3.游戏对象
管理食物对象和蛇对象的生成和逻辑
良好的代码书写习惯及注意:
使用(function(){})(),开启自调用函数,启动新的局部作用域,防止命名冲突
在防止命名冲突的同时,为了使外界可以同时访问到自调用函数中的所有对象,使用Window.函数名的方式,将其悬挂到window对象上
理解此代码需要提前了解原型链的构成
在index文件中注意引用文件顺序提前用的需要先引用
解决随机生成的问题:
//使用字面量的方式创建对象,给对象的属性添加了一个 方法
(function(){
var Tools = {
getRandom:function(min,max){
//Math.random生成 [0,1)的随机数,Math.floor向下取整
//此时需要取到[min,max]的值,例如取[2,5],所以[0,1)*(5-2+1)+2=[2,6)即[2,5]
return Math.floor(Math.random()*(max-min+1)+min);
}
}
window.Tools = Tools;
})()
食物:
(function(){
//记录上一次创建的食物,为删除做准备
var elements=[];
function Food(options){
//new一个对象时如果没有传参数,此时options为空,后面的语句就会出错所以需要给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 || 'pink';
}
//应该把食物传到父容器上
Food.prototype.render = function(map){
//删除之前创建的食物
remove();
this.x = Tools.getRandom(0,map.offsetWidth/this.width-1)*this.width;
this.y = Tools.getRandom(0,map.offsetHeight/this.height-1)*this.height;
//动态创建div,也就是食物
var div = document.createElement('div');
map.appendChild(div);
elements.push(div);
//设置div的样式
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]);
//删除数组中的元素
elements.splice(i,1);
}
}
//外部无法直接访问测试代码,利用window全局对象访问
// var food = new Food();
// var map = document.getElementById('map');
// food.render(map);
window.Food = Food;
})()
//var food = new Food();
//var map = document.getElementById('map');
//food.render(map);
蛇:
(function(){
//面向对象过程中用变量来存储内容,便于后续的维护开发
var position = 'absolute';
//记录之前创建的蛇
var elements = [];
function Snake(options){
options = options || {};
//设置蛇节的大小
this.width = options.width || 20;
this.height = options.height || 20;
//设置蛇节的方向,默认往右移动
this.direction = options.direction || 'right';
//设置蛇的身体,默认有三个块
this.body = [
//第一个蛇头的位置x:3左边距离有三个方块,y:2上面距离有两个方块
{x:3,y:2,color:'lightgreen'},
{x:2,y:2,color:'white'},
{x:1,y:2,color:'white'}
];
}
//将蛇渲染到地图上
Snake.prototype.render = function(map){
//每次render渲染的时候都应该先移除掉之前创建的蛇
remove();
//要把蛇的每一个部分都渲染到地图上
//i<len比i<length的好处是,每循环一次this.body.length都会计算一次,但是如果在var中定义就只会执行一次,这样会提高效率
for(var i=0, len = this.body.length;i<len;i++){
var obj = this.body[i];
var div = document.createElement('div');
map.appendChild(div);
//记录当前的蛇
elements.push(div);
//设置样式
div.style.position = position;
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;
}
}
function remove(){
for(var i=elements.length-1;i>=0;i--){
//删除div
//删除数组中的元素
elements[i].parentNode.removeChild(elements[i]);
elements.splice(i,1);
}
}
//控制蛇移动的方法
Snake.prototype.move = function(food,map){
//控制蛇的身体移动,每次移动当前蛇节走到上一个蛇节的位置
//只取身体部分不取头部
for(var i=this.body.length-1;i>0;i--){
this.body[i].x = this.body[i-1].x;
this.body[i].y = this.body[i-1].y;
}
//控制蛇头的移动
//判断蛇移动的方向
var head = this.body[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;
}
//判断食物的坐标是否和蛇头坐标重合
if(food.x === head.x*this.width && food.y === head.y*this.height){
//让蛇身体增加一格
//获取蛇的最后一节
var last = this.body[this.body.length-1];
//将最后一节的属性作为新属性赋值给新的一节
this.body.push({
x:last.x,
y:last.y,
color:last.color
})
//随机在地图上重新生成食物
food.render(map);
}
}
//测试:先将Sanke挂到Window对象上,便于外部测试访问
window.Snake = Snake;
})()
游戏对象:
(function(){
//记录游戏对象,避免定时器this指向错误
var that;
function Game(map){
this.food = new Food();
this.snake = new Snake();
this.map = map;
that = this;
}
Game.prototype.start = function (){
//把食物和蛇渲染到地图
this.food.render(this.map);
this.snake.render(this.map);
//测试move方法
// this.snake.move();
// this.snake.render(this.map);
// this.snake.move();
// this.snake.render(this.map);
//开始游戏逻辑:让蛇移动起来;用键盘控制蛇移动的方向;当蛇遇到食物做相应的处理;当蛇遇到边界,游戏结束
runSnake();
controlSnake();
}
//通过键盘控制蛇的移动
function controlSnake(){
document.addEventListener('keydown',function(e){
//console.log(e.keyCode);
//输出按下键盘方向的键盘码:37-left,38-top,39-right,40-bottom
switch(e.keyCode){
case 37:
that.snake.direction = 'left';
break;
case 38:
that.snake.direction = 'top';
break;
case 39:
that.snake.direction = 'right';
break;
case 40:
that.snake.direction = 'bottom';
break;
}
},false);
}
//开启定时器让蛇移动,用私有函数而不是原型,因为不需要外部访问
function runSnake(){
var timerId = setInterval(function (){
//让蛇走一格,在定时器中this指向window,没法用this.sanke
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.body[0].x;
var headY = that.snake.body[0].y;
//此时有个小问题,alert之后蛇头仍然会超出边界,这是渲染问题
if(headX < 0 || headX >= maxX){
alert('Game Over');
clearInterval(timerId);
timerId = null;
}
if(headY < 0 || headY >= maxY){
alert('Game Over');
clearInterval(timerId);
timerId = null;
}
},300);
}
window.Game = Game;
})()
测试:
(function(){
//测试代码
var map = document.getElementById('map');
var game = new Game(map);
game.start();
})()
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>贪吃蛇</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="map"></div>
<script src="js/tool.js"></script>
<script src="js/food.js"></script>
<script src="js/snake.js"></script>
<script src="js/game.js"></script>
<script src="js/main.js"></script>
</body>
</html>
- JavaScript面向对象编程小游戏---贪吃蛇
1 面向对象编程思想在程序项目中有着非常明显的优势: 1- 1 代码可读性高.由于继承的存在,即使改变需求,那么维护也只是在局部模块 1- 2 维护非常方便并且成本较低. 2 这个demo是采用了 ...
- C语言用面向对象的思想写贪吃蛇
大概一年前这时候,接触C语言一个月,那时候知之甚少,对面向对象只觉”可远观而不可亵玩“,而且会看到很多言论说C语言就是面向过程的语言,C++就是面向对象的语言.不过,不记得什么时候在网上看到过一篇博文 ...
- 一个原生JS实现的不太成熟的贪吃蛇游戏
一个初初初初级前端民工 主要是记录一下写过的东西,复习用 大佬们如果看到代码哪里不符合规范,或者有更好写法的,欢迎各位批评指正 十分感谢 实现一个贪吃蛇游戏需要几步? 1.有地图 2.有蛇 3.有食物 ...
- JS仿贪吃蛇:一串跟着鼠标的Div
贪吃蛇是一款80后.90后比较熟悉的经典游戏,下面通过简单的JS代码来实现低仿版贪吃蛇效果:随着鼠标的移动,在页面中呈现所有Div块跟随鼠标依次移动,效果如下图所示. <!DOCTYPE htm ...
- 前端笔记之JavaScript面向对象(三)初识ES6&underscore.js&EChart.js&设计模式&贪吃蛇开发
一.ES6语法 ES6中对数组新增了几个函数:map().filter().reduce() ES5新增的forEach(). 都是一些语法糖. 1.1 forEach()遍历数组 forEach() ...
- JS高级---面向对象的编程思想(贪吃蛇梳理)
面向对象的编程思想(贪吃蛇梳理) 模拟贪吃蛇游戏,做的项目 地图: 宽,高,背景颜色,因为小蛇和食物都是相对于地图显示的, 这里小蛇和食物都是地图的子元素, 随机位置显示, 脱离文档流的, 地图也需要 ...
- Javascript基础示例:用JS写简易版贪吃蛇(面向对象)
废话不多说,代码如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> & ...
- js基础之面向对象
一.基本概念 Array类 ————> 不具备实际的功能,只能用来构造对象 arr对象 ————> 有实际的功能,被类给构造出来 如:var arr=new Array(); proto ...
- html5面向对象做一个贪吃蛇小游戏
canvas加面向对象方式的贪吃蛇 2016-08-25 这个小游戏可以增加对面向对象的理解,可以加强js逻辑能力,总之认真自己敲一两遍收获还是不少啊!!适合刚学canvas的同学练习!! 废话不多说 ...
- JS小游戏:贪吃蛇(附源码)
javascript小游戏:贪吃蛇 此小游戏采用的是面向对象的思想,将蛇,食物,和游戏引擎分为3个对象来写的. 为方便下载,我把js写在了html中, 源码中暂时没有注释,等有空我在添加点注释吧. 游 ...
随机推荐
- [翻译]-hugePage的简要说明--部分内容
hugePage的简要说明 本篇文档的主旨给linux内核支持的大页内存做一个简要的概述. 大页内存的实现是建立在大多数现代架构所都支持的多级页大小的特性之上的. 举例: x86架构下大部署CPU 的 ...
- reposync与createrepo创建离线yum源的方法
背景 昨天晚上进行了在线升级银河麒麟V10SP2的audit和mate-indicator的rpm包 今天想了下,如果机器无法上网. 必须得在公司内部搭建一套离线的rpm源进行处理 想了下还是使用re ...
- 万能shell 简单查看已存在日志所有的启动记录
程序将日志 自动打包成了 gz 文件, 今天突然想查查所有的日志有没有相关关键字. 第一步解压缩所有的日志 cd 到相关目录 for i in `ls` ; do gzip -d $i ; done ...
- plcTIA Portal V16找不到许可证
首先快捷键win+s唤出搜索,搜:服务 其次搜索这个服务Automation License Manager Service 右击-启动服务,然后重新启动plc即可选择CPU型号了
- python2和python3的版本历史及入门书籍
python版本历史 我们端游项目使用是python2.7版本 32位 python2 2.7.18 last version on 2020.4.20 2.7 first version on 20 ...
- @RequestBody中使用@DateTimeFormat报错:JSON parse error: Expected array or string.; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException
原因分析 根据异常提示:不匹配输入异常,指输入的参数错误,说是只支持String类型和Array数组类型的. @PostMapping("/test") public Dto ge ...
- C/C++ 获取主机网卡MAC地址
MAC地址(Media Access Control address),又称为物理地址或硬件地址,是网络适配器(网卡)在制造时被分配的全球唯一的48位地址.这个地址是数据链路层(OSI模型的第二层)的 ...
- 21.14 Python 实现Web指纹识别
在当今的Web安全行业中,识别目标网站的指纹是渗透测试的常见第一步.指纹识别的目的是了解目标网站所使用的技术栈和框架,从而进一步根据目标框架进行针对性的安全测试,指纹识别的原理其实很简单,目前主流的识 ...
- 2.5 PE结构:导入表详细解析
导入表(Import Table)是Windows可执行文件中的一部分,它记录了程序所需调用的外部函数(或API)的名称,以及这些函数在哪些动态链接库(DLL)中可以找到.在Win32编程中我们会经常 ...
- PE结构:VA&RVA&FOA 转换复习
复习一下,不然会忘 1.imagebase 映像基地址 ,默认是0x400000 2.va 虚拟地址,载入OD后的地址,已经映射到内存的地址. 计算实际装入地址 VA imagebase (映像基址) ...