给大家分享一下这几天我研究的一个贪吃蛇,挺简单的,但是实现起来其实有点绕的,我给大家附上完整代码,一起分析学习一下,主要用的是构造函数。

  

  

思想:

、设计蛇:属性有宽、高、方向、状态(有多少节),方法:显示,跑

、设计食物:属性宽、高

、显示蛇:根据状态向地图里加元素

、蛇跑起来:下一节到前一节的位置,蛇头根据方向变,删除原来的蛇,新建蛇;当出界时,死亡,初始化;当蛇头吃到自己的时候,死亡,初始化

、食物被吃掉,蛇加一节,去掉原来的食物,生成新的食物

、添加定时器,绑定按键

这里先给大家简单的说一下构造函数:

构造函数 ,是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载

new data();

然后开始我们的贪吃蛇之旅:

1.设置变量,定义蛇的初始状态

  // 设置蛇的宽、高、默认走的方向
this.width = 10;
this.height = 10;
this.direction = 'right'; // 记住蛇的状态,当吃完食物的时候,就要加一个,初始为3个小点为一个蛇,
this.body = [
{x:2, y:0}, // 蛇头,第一个点
{x:1, y:0}, // 蛇脖子,第二个点
{x:0, y:0}, // 蛇尾,第三个点
];

这里面我会在代码里做详细的解释,大家注意看!!!!

2.显示蛇

  for (var i=0; i<this.body.length; i++) {
if (this.body[i].x != null) { // 当吃到食物时,x==null,不能新建,不然会在0,0处新建一个
var s = document.createElement('div');//创建元素节点
// 将节点保存到状态中,以便于后面删除
this.body[i].flag = s;
// 设置宽高
s.style.width = this.width + 'px';
s.style.height = this.height + 'px';
s.style.borderRadius = "50%";
s.style.background = "rgb(" + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + ")";//这个就是一个随机颜色
// 设置位置
s.style.position = 'absolute';
s.style.left = this.body[i].x * this.width + 'px';
s.style.top = this.body[i].y * this.height + 'px';//设置每一个舍身的位置
// 添加进去
map.appendChild(s);//把元素追加到div中
}
}

这里使用到for循环,为每一个对象创建一个flag对象,也就是蛇身。

3.让蛇动起来

我的想法就是让后一个元素到前一个元素来,然后这样蛇就动起来了,

 // 后一个元素到前一个元素的位置
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;
//这里就相当于是后一个元素到前一个元素 这样让小蛇动起来
}

4.调整蛇头方向

 // 根据方向处理蛇头
switch(this.direction)
{
//这里不仅调整蛇头方向,还为迟到的食物赋值 下边会有解释
case "left":
this.body[0].x -= 1;
break;
case "right":
this.body[0].x += 1;
break;
case "up":
this.body[0].y -= 1;
break;
case "down":
this.body[0].y += 1;
break;
}

5.判断吃到食物和吃到自己和撞墙的事件

这里提醒一下呢就是,不管你是吃到食物了还是撞墙了还是吃到自己了你到要重新创建蛇。

然后呢我会在代码里标注清楚每一个代码的作用。

  // 判断是否出界,一蛇头判断,出界的话,
if (this.body[0].x < 0 || this.body[0].x > 79 || this.body[0].y < 0 || this.body[0].y > 39) {
clearInterval(timer); // 清除定时器,
alert("你瞎吗?撞死了!");
// 删除旧的
for (var i=0; i<this.body.length; i++) {
if (this.body[i].flag != null) { // 如果刚吃完就死掉,会加一个值为null的
map.removeChild(this.body[i].flag);
}
}
//这里呢一定要删除 之后 初始化一下 因为上边的this.display() 为每一个body对象都添加了一个flag 所以这里删除原本的蛇 重新初始化一下蛇
this.body = [ // 回到初始状态,
{x:2, y:0},
{x:1, y:0},
{x:0, y:0}
];
this.direction = 'right';
this.display(); // 显示初始状态
return false; // 结束
} // 判断蛇头吃到食物,xy坐标重合,
if (this.body[0].x == food.x && this.body[0].y == food.y) {
// 蛇加一节,因为根据最后节点定,下面display时,会自动赋值的
this.body.push({x:null, y:null, flag: null}); //在这里 看了上边的小伙伴可能会有疑惑 this.display 函数里面生成小蛇的判断是x!=null 那我吃到实物以后push进去的都是null 为什么还会创建出来????
//这里呢大家就注意看 this.run() 这个方法 他让后一个元素到前一个元素来 然后你新添加的这一截蛇它会被替换为蛇头 然后进入 下边的switch语句 x,y都会变为-1 或者是1 那么这个时候在走上边的 this.display() 就可以生成一个新的小蛇。 // 清除食物,重新生成食物
map.removeChild(food.flag);
food.display();
}
// 吃到自己死亡,从第五个开始与头判断,因为前四个永远撞不到
for (var i=4; i<this.body.length; i++) {
if (this.body[0].x == this.body[i].x && this.body[0].y == this.body[i].y) {
clearInterval(timer); // 清除定时器,
alert("傻子!你怎么能吃自己呢?");
// 删除旧的
for (var i=0; i<this.body.length; i++) {
if (this.body[i].flag != null) { // 如果刚吃完就死掉,会加一个值为null的
map.removeChild(this.body[i].flag);
}
}
this.body = [ // 回到初始状态,
{x:2, y:0},
{x:1, y:0},
{x:0, y:0}
];
this.direction = 'right';
this.display(); // 显示初始状态
return false; // 结束
}
} // 先删掉初始的蛇,在显示新蛇
for (var i=0; i<this.body.length; i++) {
if (this.body[i].flag != null) { // 当吃到食物时,flag是等于null,且不能删除
map.removeChild(this.body[i].flag);
}
}
// 重新显示蛇
this.display();

6.构造食物

食物呢,我们就是创建一个,当蛇吃到食物,也就是蛇头与食物的xy坐标一样后删除食物,然后随机新建一个食物

   this.width = 10;
this.height = 10; this.display = function() {
var f = document.createElement('div');
this.flag = f;
f.style.width = this.width + 'px';
f.style.height = this.height + 'px';
f.style.background = 'red';
f.style.borderRadius = '50%';
f.style.position = 'absolute';
//设置随机位置
this.x = Math.floor(Math.random()*80);
this.y = Math.floor(Math.random()*40);
f.style.left = this.x * this.width + 'px';
f.style.top = this.y * this.height + 'px';
//把创建好的食物添加进地图里
map.appendChild(f);

7.然后我们要使用构造函数调用食物和蛇的方法

 var snake = new Snake();// 构造函数
var food = new Food();
snake.display(); // 初始化显示
food.display();

这里呢,一定要注意,他改变了this的指向,大家可以输出一下this指向,

如果直接调用函数的话,this是指向window,使用构造函数的话this就指向调用者

8.点击开始游戏添加键盘事件

 document.body.onkeydown = function(e) {
// 有事件对象就用事件对象,没有就自己创建一个,兼容低版本浏览器
var ev = e || window.event; switch(ev.keyCode)
{
case 38:
if (snake.direction != 'down') { // 不允许返回,向上的时候不能向下
snake.direction = "up";
}
break;
case 40:
if (snake.direction != "up") {
snake.direction = "down";
}
break;
case 37:
if (snake.direction != "right") {
snake.direction = "left";
}
break;
case 39:
if (snake.direction != "left") {
snake.direction = "right";
}
break;
}
};

9.设置定时器,让小蛇自己动起来

 // 点击开始时,动起来
var begin = document.getElementById('begin');
var timer;
begin.onclick = function() {
clearInterval(timer);
// 先执行run函数,把执行得到的结果,每500毫秒执行一次,不会在执行内部代码
// 小技巧,每500毫秒执行字符串,字符串执行内部代码
timer = setInterval("snake.run()", 500);
};

最后一定要记住,调用定时器前一定要先清除定时器!!!!

给大家附上完整代码:

 <!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style type="text/css">
body {
margin: 0;
padding: 0;
}
.main {
width: 800px;
height: 400px;
margin: 50px auto;
}
.btn {
width: 100px;
height: 40px;
background: red;
}
.map {
position: relative;
width: 800px;
height: 400px;
background: yellow;
}
</style>
</head>
<body>
<div class="main">
<button class="btn" id="begin">开始游戏</button>
<div class="map" id="map"></div> <script type="text/javascript">
var map = document.getElementById('map');
// 使用构造方法创建蛇,
function Snake()
{
// 设置蛇的宽、高、默认走的方向
this.width = 10;
this.height = 10;
this.direction = 'right'; // 记住蛇的状态,当吃完食物的时候,就要加一个,初始为3个小点为一个蛇,
this.body = [
{x:2, y:0}, // 蛇头,第一个点
{x:1, y:0}, // 蛇脖子,第二个点
{x:0, y:0}, // 蛇尾,第三个点
]; // 显示蛇
this.display = function() {
// 创建蛇
for (var i=0; i<this.body.length; i++) {
if (this.body[i].x != null) { // 当吃到食物时,x==null,不能新建,不然会在0,0处新建一个
var s = document.createElement('div');//创建元素节点
// 将节点保存到状态中,以便于后面删除
this.body[i].flag = s;
// 设置宽高
s.style.width = this.width + 'px';
s.style.height = this.height + 'px';
s.style.borderRadius = "50%";
s.style.background = "rgb(" + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + ")";//这个就是一个随机颜色
// 设置位置
s.style.position = 'absolute';
s.style.left = this.body[i].x * this.width + 'px';
s.style.top = this.body[i].y * this.height + 'px';//设置每一个舍身的位置
// 添加进去
map.appendChild(s);//把元素追加到div中
}
}
}; // 让蛇跑起来,后一个元素到前一个元素的位置
// 蛇头根据方向处理,所以i不能等于0
this.run = function() {
// 后一个元素到前一个元素的位置
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;
//这里就相当于是后一个元素到前一个元素 这样让小蛇动起来
} // 根据方向处理蛇头
switch(this.direction)
{
//这里不仅调整蛇头方向,还为迟到的食物赋值 下边会有解释
case "left":
this.body[0].x -= 1;
break;
case "right":
this.body[0].x += 1;
break;
case "up":
this.body[0].y -= 1;
break;
case "down":
this.body[0].y += 1;
break;
} // 判断是否出界,一蛇头判断,出界的话,
if (this.body[0].x < 0 || this.body[0].x > 79 || this.body[0].y < 0 || this.body[0].y > 39) {
clearInterval(timer); // 清除定时器,
alert("你瞎吗?撞死了!");
// 删除旧的
for (var i=0; i<this.body.length; i++) {
if (this.body[i].flag != null) { // 如果刚吃完就死掉,会加一个值为null的
map.removeChild(this.body[i].flag);
}
}
//这里呢一定要删除 之后 初始化一下 因为上边的this.display() 为每一个body对象都添加了一个flag 所以这里删除原本的蛇 重新初始化一下蛇
this.body = [ // 回到初始状态,
{x:2, y:0},
{x:1, y:0},
{x:0, y:0}
];
this.direction = 'right';
this.display(); // 显示初始状态
return false; // 结束
} // 判断蛇头吃到食物,xy坐标重合,
if (this.body[0].x == food.x && this.body[0].y == food.y) {
// 蛇加一节,因为根据最后节点定,下面display时,会自动赋值的
this.body.push({x:null, y:null, flag: null}); //在这里 看了上边的小伙伴可能会有疑惑 this.display 函数里面生成小蛇的判断是x!=null 那我吃到实物以后push进去的都是null 为什么还会创建出来????
//这里呢大家就注意看 this.run() 这个方法 他让后一个元素到前一个元素来 然后你新添加的这一截蛇它会被替换为蛇头 然后进入 下边的switch语句 x,y都会变为-1 或者是1 那么这个时候在走上边的 this.display() 就可以生成一个新的小蛇。 // 清除食物,重新生成食物
map.removeChild(food.flag);
food.display();
}
// 吃到自己死亡,从第五个开始与头判断,因为前四个永远撞不到
for (var i=4; i<this.body.length; i++) {
if (this.body[0].x == this.body[i].x && this.body[0].y == this.body[i].y) {
clearInterval(timer); // 清除定时器,
alert("傻子!你怎么能吃自己呢?");
// 删除旧的
for (var i=0; i<this.body.length; i++) {
if (this.body[i].flag != null) { // 如果刚吃完就死掉,会加一个值为null的
map.removeChild(this.body[i].flag);
}
}
this.body = [ // 回到初始状态,
{x:2, y:0},
{x:1, y:0},
{x:0, y:0}
];
this.direction = 'right';
this.display(); // 显示初始状态
return false; // 结束
}
} // 先删掉初始的蛇,在显示新蛇
for (var i=0; i<this.body.length; i++) {
if (this.body[i].flag != null) { // 当吃到食物时,flag是等于null,且不能删除
map.removeChild(this.body[i].flag);
}
}
// 重新显示蛇
this.display(); }
} // 构造食物
function Food()
{
this.width = 10;
this.height = 10; this.display = function() {
var f = document.createElement('div');
this.flag = f;
f.style.width = this.width + 'px';
f.style.height = this.height + 'px';
f.style.background = 'red';
f.style.borderRadius = '50%';
f.style.position = 'absolute';
//设置随机位置
this.x = Math.floor(Math.random()*80);
this.y = Math.floor(Math.random()*40);
f.style.left = this.x * this.width + 'px';
f.style.top = this.y * this.height + 'px';
//把创建好的食物添加进地图里
map.appendChild(f);
}
} var snake = new Snake();// 构造函数
var food = new Food();
snake.display(); // 初始化显示
food.display(); // 给body加按键事件,上下左右
document.body.onkeydown = function(e) {
// 有事件对象就用事件对象,没有就自己创建一个,兼容低版本浏览器
var ev = e || window.event; switch(ev.keyCode)
{
case 38:
if (snake.direction != 'down') { // 不允许返回,向上的时候不能向下
snake.direction = "up";
}
break;
case 40:
if (snake.direction != "up") {
snake.direction = "down";
}
break;
case 37:
if (snake.direction != "right") {
snake.direction = "left";
}
break;
case 39:
if (snake.direction != "left") {
snake.direction = "right";
}
break;
}
}; // 点击开始时,动起来
var begin = document.getElementById('begin');
var timer;
begin.onclick = function() {
clearInterval(timer);
// 先执行run函数,把执行得到的结果,每500毫秒执行一次,不会在执行内部代码
// 小技巧,每500毫秒执行字符串,字符串执行内部代码
timer = setInterval("snake.run()", 500);
}; </script>
</div>
</body>
</html>

详细的解释我已经在代码中注释,大家把代码复制下来就可以直接查看效果!!!

js贪吃蛇(构造函数)的更多相关文章

  1. JS贪吃蛇游戏

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  2. js贪吃蛇-简单版

    分享个用原生js写的贪吃蛇,最近在学java,按照当年写的 js的思路,转换成java,换汤不换药 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1 ...

  3. JS贪吃蛇小游戏

    效果图展示: 具体实现代码如下: (1)html部分 !DOCTYPE html> <html> <head> <meta charset="utf-8& ...

  4. 原生Js贪吃蛇游戏实战开发笔记

    前言 本课程是通过JavaScript结合WebAPI DOM实现的一版网页游戏---贪吃蛇的开发全过程,采用面向以象的思想设计开发.通过这个小游戏的开发, 不仅可以掌握JS的语法的应用,还可以学会D ...

  5. HTML5+CSS+JS 贪吃蛇demo

    我写博客的主要目的就是温习所学的知识,自己以前写的游戏当然不能放过! 这款网页版贪吃蛇是大一下册学习网页前端时老师教我们写的,由于那个时候初学网页前端,所以这款游戏是纯原生Java Script写的, ...

  6. js贪吃蛇源码

    1.注意,自己引入jquery,这个demo基于jquery的,我的jquery是写的本地的 2.没有写注释,看不懂的再问我吧, <!DOCTYPE html><html> & ...

  7. 原生js贪吃蛇

    <!DOCTYPE html> <html> <head> <title></title> <meta charset="u ...

  8. js贪吃蛇

    function init() { w = 40; m = 20; d = w * m / 2; food = null; dm = new ht.DataModel(); g3d = new ht. ...

  9. 前端笔记之JavaScript面向对象(三)初识ES6&underscore.js&EChart.js&设计模式&贪吃蛇开发

    一.ES6语法 ES6中对数组新增了几个函数:map().filter().reduce() ES5新增的forEach(). 都是一些语法糖. 1.1 forEach()遍历数组 forEach() ...

随机推荐

  1. IE8下Extjs报缺少':'符号错误

    先介绍下这个问题的由来: 上午其他项目组人员在rtx上问,求帮忙解决ie8兼容性问题. 然后快到饭点,知道这个bug肯定不是那么好解决,肯定不能耽误吃饭时间. 果断说,下午来弄. 下午3点开始去看这个 ...

  2. MIT线性代数:7.主变量,特解,求解AX=0

  3. 和35岁刘阿姨一起自测 Python 流程控制基本功

    0.突然降临的困惑 流程控制语句.布尔值.布尔值操作符都属于 python 的基础功.大好周末我写这篇笔记,不是为了整理这些基础知识点,而是记录几个令我突然迷惑的代码段.--代码本身很简单,但即便已经 ...

  4. 「2019.8.11 考试」一套把OI写的很诗意的题

    这次写的更惨了,T2暴力再次挂掉了. 先写了T1的75暴力,然后写了T2的70分暴力(挂成了25),T3啥也不会骗了12分.T3看完题一点思路没有,心态爆炸了,一直在观察数据,忽略的思考的重要性,以至 ...

  5. Redis实战--Redis整合SpringBoot示例

    echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! 该文章 ...

  6. F#周报2019年第45期

    新闻 邀请博客主们:2019年的F# Advent日历 宣告ML.NET 1.4 .NET Core与Jupyter笔记本 在Jupyter笔记本中使用ML.NET 用于Windows桌面的.NET ...

  7. Vue基础系列(三)——Vue模板中的数据绑定语法

    写在前面的话: 文章是个人学习过程中的总结,为方便以后回头在学习. 文章中会参考官方文档和其他的一些文章,示例均为亲自编写和实践,若有写的不对的地方欢迎大家和我一起交流. VUE基础系列目录 < ...

  8. Java基础知识之常量变量(一)

    1.什么是变量,什么是常量?java的基本数据类型是什么 变量: 会发生改变的数据,叫做变量,如自定义一个a,并且对a进行赋值操作为1,也可以让a等于2,此时a就是一个变量 常量: 不会发生改变的值, ...

  9. 为企业应用开发提速,写给企业IT部门的低代码开发基础知识

    简介:应用程序开发长期以来一直是IT部门和业务部门面临的问题. IT部门总是被新的应用程序需求弄得不堪重负.他们不可能完成业务部门想要完成的每一个项目. 同时,业务部门的用户厌倦了等待,并开始完全绕过 ...

  10. 前端与算法 leetcode 8. 字符串转换整数 (atoi)

    目录 # 前端与算法 leetcode 8. 字符串转换整数 (atoi) 题目描述 概要 提示 解析 解法一:正则 解法二:api 解法二:手搓一个api 算法 传入测试用例的运行结果 执行结果 G ...