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

  

  

思想:

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

、设计食物:属性宽、高

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

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

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

、添加定时器,绑定按键

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

构造函数 ,是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与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. 使用asp.net core 3.0 搭建智能小车1

    跟随.net core 3.0 一起发布的System.Device.Gpio 1.0已经可以让我们用熟悉的C#原汁原味的开发莓派上面的GPIO了.并且在 Iot.Device.Bindings这个包 ...

  2. 第三十七章 POSIX线程(一)

    POSIX线程库相关介绍   与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都有"pthread_"开头   要使用这些函数库,都需要加入头文件"<pth ...

  3. 使用Java调用exe可执行文件

    一.出发点 平日里,我们看到了很多已经成型的可执行文件,而且经过了一定的封装.因为开源的关系,大多时候可以自己使用eclipse进行编译,但也常常遇到不如直接调用更加方便的情况.那么这时候,我个人需要 ...

  4. Appium的加载过程

    appium运行流程 Appium的加载过程如上图. 1)调用Android adb完成基本的系统操作: 2)向Android上部署bootstrap.jar: 3)Bootstrap.jar For ...

  5. 【java基础】程序员你真的理解反射机制吗?

    目录 前言 1.反射的概述 2.正式使用反射之前很有必要了解的Class类 3.反射的使用 前言 很多讲解反射的博客文章并没有详细讲解Class类,~当然包括之前的我也一样~,这样的文章只会让反射徒有 ...

  6. 三分钟学会Redis在.NET Core中做缓存中间件

    大家好,今天给大家说明如何在.NET Core中使用Redis,我们在想要辩论程序的好与坏,都想需要一个可视化工具,我经常使用的是一位国内大牛开发的免费工具,其Github地址为: https://g ...

  7. Android 开发中是否应该使用枚举?

    本文由咕咚发布在个人博客,转载请注明出处. 本文永久地址:https://gudong.name/2019/11/04/use-enum-or-not.html 在 Android 官方文档推出性能优 ...

  8. 『题解』洛谷P1063 能量项链

    原文地址 Problem Portal Portal1:Luogu Portal2:LibreOJ Portal3:Vijos Description 在\(Mars\)星球上,每个\(Mars\)人 ...

  9. MySQL系列:Windows 下 MySQL 8.X 的安装

    之前一直使用的是MySQL5.7,但由于MySQL增加了一些新特性,所以选择了更新. 下载MySQL 进入MySQL官网下载地址,选择Windows (x86, 64-bit), ZIP Archiv ...

  10. 深入理解java继承从“我爸是李刚”讲起

    目录 1.继承的概述 2.关于继承之后的成员变量 3.关于继承之后的成员方法 4.关于继承之后的构造方法 5.关于继承的多态性支持的例子 6.super与this的用法 前言 本文主要多方面讲解jav ...