复习及今日介绍(贪吃蛇游戏):
注:主要是利用 案例理解面向对象的思想。
案例:
画地图:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>这是网页标题</title> 6 <style> 7 .map{ 8 width: 800px; 9 height: 600px; 10 background-color: #ccc; 11 position: relative; /*注意,蛇 和 食物都是脱离文档流的,它们的父类也要脱离,并且是相对定位*/ 12 } 13 </style> 14 </head> 15 <body> 16 <!-- 地图--> 17 <div class="map"></div> 18 19 20 21 <script src="js/common.js"></script> 22 <script> 23 24 </script> 25 26 </body> 27 </html>
创建食物:
食物都是先删掉(当蛇碰到食物时删!)之前的食物,然后再创建一个新的。
两种自调用方式:
下面的方式更好一些。
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>这是网页标题</title> 6 <style> 7 .map{ 8 width: 800px; 9 height: 600px; 10 background-color: #ccc; 11 position: relative; 12 } 13 </style> 14 </head> 15 <body> 16 <!-- 地图--> 17 <div class="map" id="map"></div> 18 19 20 21 <script src="js/common.js"></script> 22 <script> 23 //1食物 食物就是一个对象,有宽,有高,有颜色,有横纵坐标 。 24 (function () { //它也是自调用函数 。 25 var arrs_Food = []; //用来存放每个小食物! 26 //食物类 27 function Food(x, y, width, height, color) { 28 this.x = x || 0; 29 this.y = y || 0; 30 this.width = width || 20; 31 this.height = height || 20; 32 this.color = color || "green"; 33 } 34 //为Food原型添加 初始化函数,以便能够显示在 地图上! 35 Food.prototype.init = function(map){ 36 removeFood(); //每次init() 前都首先清空所有食物,然后再创建一个。 37 38 //创建div 食物 39 var divFood = document.createElement("div"); 40 divFood.style.width = this.width + "px"; 41 divFood.style.height = this.height +"px"; 42 43 //横纵坐标 要是随机值,而且食物要脱离文档流。 44 var min_w = 0; //[0,39] 45 var max_w = map.offsetWidth/ this.width -1; 46 var min_h = 0; //[0.29] 47 var max_h = map.offsetHeight/this.height -1; 48 this.x = parseInt( Math.random()*(max_w-min_w+1)+min_w); 49 this.y = parseInt( Math.random()*(max_h-min_h+1)+min_h); 50 divFood.style.left = this.x*this.width +"px"; 51 divFood.style.top = this.y*this.height +"px"; 52 divFood.style.position = "absolute"; 53 divFood.style.backgroundColor = this.color; 54 map.appendChild(divFood); 55 arrs_Food.push(divFood); 56 }; 57 58 //如果多次调用init() 的话,会产生多个食物在界面上,如何解决? 59 //定义一个 私有的函数 用来清除食物--1,数组中清除 2,地图上也不显示 60 function removeFood(){ 61 /*该函数 外部无法访问!!!*/ 62 for (var i =0;i<arrs_Food.length;i++){ 63 //1,地图上不再显示该元素。 64 arrs_Food[i].parentNode.removeChild(arrs_Food[i]); 65 //2,数组中也要删除这个食物 66 arrs_Food.splice(i,1); //从数组中删除该索引的 元素。 67 } 68 } 69 70 71 //为了能在外面使用Food , 将食物类 绑定到window上 72 window.Food = Food; 73 }()); 74 75 //创建对象 food 76 var food = new Food(); //默认参数! 77 food.init(document.querySelector(".map")); //通过类选择器 获取地图的div对象 78 //food.init(document.querySelector(".map")); //通过类选择器 获取地图的div对象 79 80 81 82 83 </script> 84 85 </body> 86 </html>
创建小蛇:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>这是网页标题</title> 6 <style> 7 .map{ 8 width: 800px; 9 height: 600px; 10 background-color: #ccc; 11 position: relative; 12 } 13 </style> 14 </head> 15 <body> 16 <!-- 地图--> 17 <div class="map" id="map"></div> 18 19 20 21 <script src="js/common.js"></script> 22 <script> 23 //1食物 食物就是一个对象,有宽,有高,有颜色,有横纵坐标 。 24 (function () { //它也是自调用函数 。 25 var arrs_Food = []; //用来存放每个小食物! 26 //食物类 27 function Food(x, y, width, height, color) { 28 this.x = x || 0; 29 this.y = y || 0; 30 this.width = width || 20; 31 this.height = height || 20; 32 this.color = color || "green"; 33 } 34 //为Food原型添加 初始化函数,以便能够显示在 地图上! 35 Food.prototype.init = function(map){ 36 removeFood(); //每次init() 前都首先清空所有食物,然后再创建一个。 37 38 //创建div 食物 39 var divFood = document.createElement("div"); 40 divFood.style.width = this.width + "px"; 41 divFood.style.height = this.height +"px"; 42 43 //横纵坐标 要是随机值,而且食物要脱离文档流。 44 var min_w = 0; //[0,39] 45 var max_w = map.offsetWidth/ this.width -1; 46 var min_h = 0; //[0.29] 47 var max_h = map.offsetHeight/this.height -1; 48 this.x = parseInt( Math.random()*(max_w-min_w+1)+min_w); 49 this.y = parseInt( Math.random()*(max_h-min_h+1)+min_h); 50 divFood.style.left = this.x*this.width +"px"; 51 divFood.style.top = this.y*this.height +"px"; 52 divFood.style.position = "absolute"; 53 divFood.style.backgroundColor = this.color; 54 map.appendChild(divFood); 55 arrs_Food.push(divFood); 56 }; 57 58 //如果多次调用init() 的话,会产生多个食物在界面上,如何解决? 59 //定义一个 私有的函数 用来清除食物--1,数组中清除 2,地图上也不显示 60 function removeFood(){ 61 /*该函数 外部无法访问!!!*/ 62 for (var i =0;i<arrs_Food.length;i++){ 63 //1,地图上不再显示该元素。 64 arrs_Food[i].parentElement.removeChild(arrs_Food[i]); 65 //2,数组中也要删除这个食物 66 arrs_Food.splice(i,1); //从数组中删除该索引的 元素。 67 } 68 } 69 70 71 //为了能在外面使用Food , 将食物类 绑定到window上 72 window.Food = Food; 73 }()); 74 75 //创建对象 food 76 var food = new Food(); //默认参数! 77 food.init(document.querySelector(".map")); //通过类选择器 获取地图的div对象 78 // food.init(document.querySelector(".map")); 79 80 var num = 0; 81 //2小蛇 小蛇有宽,有高,有方向,宽高指的是 组成蛇身体的小方块的 宽高 82 (function () { 83 var arr_Body = []; //存放小蛇的 身体部分。 (蛇走的实质是 将头向前移,然后删除尾) 84 85 function Snake(width,height,direction) { 86 this.width = width || 20; 87 this.height = height || 20; 88 this.direction = direction ||"right"; 89 90 //小蛇的身体 91 this.body = [ 92 {x:3,y:2,color:"red"},//头 93 {x:2,y:2,color:"orange"},//身体 94 {x:1,y:2,color:"orange"},//身体 95 ]; 96 97 } 98 //为Snake的原型添加方法 99 Snake.prototype.init = function (map) { 100 num++; 101 //init 前先 remove(); 102 remove(); 103 //目前的蛇有三个部分, 三个div 104 for (var i = 0;i<this.body.length;i++){ 105 var div = document.createElement("div"); 106 //div 要脱离文档流 107 div.style.width = this.width+"px"; 108 div.style.height = this.height+"px"; 109 div.style.position = "absolute"; 110 div.style.left = this.body[i].x*this.width+num*100+"px"; 111 div.style.top = this.body[i].y*this.height +"px"; 112 div.style.backgroundColor = this.body[i].color; 113 map.appendChild(div); 114 115 116 //把div 加入到arr_Body数组中去,目的也是为了, 当多次init的时候不创建的多个 117 arr_Body.push(div); 118 } 119 120 121 }; 122 123 //定义个私有函数, 清除蛇的每个部分,达到 多次init 而不会显示多个 124 function remove(){ 125 // console.log(arr_Body.length); 126 127 var arr_len = arr_Body.length; //不能直接放下面 做判断条件 ,会出错! 128 console.log(arr_len); 129 for (var i =arr_len-1;i >=0 ;i--){ 130 console.log("ha"); 131 var div = arr_Body[i]; 132 // div.parentNode 133 div.parentElement.removeChild(div); 134 //数组中也要删掉它自己 135 arr_Body.splice(i,1); 136 } 137 // console.log(arr_Body.length); 138 } 139 window.Snake = Snake; 140 }()); 141 var snake = new Snake(); 142 snake.init(document.querySelector(".map")); 143 snake.init(document.querySelector(".map")); 144 snake.init(document.querySelector(".map")); 145 146 147 148 149 150 151 152 </script> 153 154 </body> 155 </html>
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>这是网页标题</title> 6 <style> 7 .map{ 8 width: 800px; 9 height: 600px; 10 background-color: #ccc; 11 position: relative; 12 } 13 </style> 14 </head> 15 <body> 16 <!-- 地图--> 17 <div class="map" id="map"></div> 18 19 20 21 <script src="js/common.js"></script> 22 <script> 23 //1食物 食物就是一个对象,有宽,有高,有颜色,有横纵坐标 。 24 (function () { //它也是自调用函数 。 25 var arrs_Food = []; //用来存放每个小食物! 26 //食物类 27 function Food(x, y, width, height, color) { 28 this.x = x || 0; 29 this.y = y || 0; 30 this.width = width || 20; 31 this.height = height || 20; 32 this.color = color || "green"; 33 } 34 //为Food原型添加 初始化函数,以便能够显示在 地图上! 35 Food.prototype.init = function(map){ 36 removeFood(); //每次init() 前都首先清空所有食物,然后再创建一个。 37 38 //创建div 食物 39 var divFood = document.createElement("div"); 40 divFood.style.width = this.width + "px"; 41 divFood.style.height = this.height +"px"; 42 43 //横纵坐标 要是随机值,而且食物要脱离文档流。 44 var min_w = 0; //[0,39] 45 var max_w = map.offsetWidth/ this.width -1; 46 var min_h = 0; //[0.29] 47 var max_h = map.offsetHeight/this.height -1; 48 this.x = parseInt( Math.random()*(max_w-min_w+1)+min_w); 49 this.y = parseInt( Math.random()*(max_h-min_h+1)+min_h); 50 divFood.style.left = this.x*this.width +"px"; 51 divFood.style.top = this.y*this.height +"px"; 52 divFood.style.position = "absolute"; 53 divFood.style.backgroundColor = this.color; 54 map.appendChild(divFood); 55 arrs_Food.push(divFood); 56 }; 57 58 //如果多次调用init() 的话,会产生多个食物在界面上,如何解决? 59 //定义一个 私有的函数 用来清除食物--1,数组中清除 2,地图上也不显示 60 function removeFood(){ 61 /*该函数 外部无法访问!!!*/ 62 for (var i =0;i<arrs_Food.length;i++){ 63 //1,地图上不再显示该元素。 64 arrs_Food[i].parentElement.removeChild(arrs_Food[i]); 65 //2,数组中也要删除这个食物 66 arrs_Food.splice(i,1); //从数组中删除该索引的 元素。 67 } 68 } 69 70 71 //为了能在外面使用Food , 将食物类 绑定到window上 72 window.Food = Food; 73 }()); 74 75 //创建对象 food 76 var food = new Food(); //默认参数! 77 food.init(document.querySelector(".map")); //通过类选择器 获取地图的div对象 78 // food.init(document.querySelector(".map")); //测试用 79 80 //2小蛇 小蛇有宽,有高,有方向,宽高指的是 组成蛇身体的小方块的 宽高 81 (function () { 82 var arr_Body = []; //存放小蛇的 身体部分。 处理当多次init 产生的问题! 83 84 function Snake(width,height,direction) { 85 this.width = width || 20; 86 this.height = height || 20; 87 this.direction = direction ||"right"; 88 89 //小蛇的身体 90 this.body = [ 91 {x:3,y:2,color:"red"},//头 92 {x:2,y:2,color:"orange"},//身体 93 {x:1,y:2,color:"orange"},//身体 94 ]; 95 96 } 97 //为Snake的原型添加方法 98 Snake.prototype.init = function (map) { 99 //init 前先 remove(); 100 remove(); 101 //目前的蛇有三个部分, 三个div 102 for (var i = 0;i<this.body.length;i++){ 103 var div = document.createElement("div"); 104 //div 要脱离文档流 105 div.style.width = this.width+"px"; 106 div.style.height = this.height+"px"; 107 div.style.position = "absolute"; 108 div.style.left = this.body[i].x*this.width+"px"; 109 div.style.top = this.body[i].y*this.height +"px"; 110 div.style.backgroundColor = this.body[i].color; 111 map.appendChild(div); 112 113 //把div 加入到arr_Body数组中去,目的也是为了, 当多次init的时候不创建的多个 114 arr_Body.push(div); 115 } 116 117 118 }; 119 120 //定义个私有函数, 清除蛇的每个部分,达到 多次init 而不会显示多个 121 function remove(){ 122 var arr_len = arr_Body.length; //不能直接放下面 做判断条件 ,会出错(因为下面 出现了操作 arr_Body数组,所以如果还直接让它作为条件就会出错了!!! 一定要注意)! 123 console.log(arr_len); 124 for (var i =arr_len-1;i >=0 ;i--){ 125 var div = arr_Body[i]; 126 // div.parentNode 127 div.parentElement.removeChild(div); 128 //数组中也要删掉它自己 129 arr_Body.splice(i,1); //要从后往前删! 130 } 131 } 132 window.Snake = Snake; 133 }()); 134 var snake = new Snake(); 135 snake.init(document.querySelector(".map")); 136 // snake.init(document.querySelector(".map")); //测试用 137 // snake.init(document.querySelector(".map")); 138 139 </script> 140 141 </body> 142 </html>
创建游戏对象:
通过bind( 对象 ) 是使得使用的this变为我们传入的对象:
绑定键盘按下的事件:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script> //在document任何页面 按下键盘的按键, document.onkeydown = function (evt) { // console.log(arguments.length); // 验证是否有参数传过来! console.log(evt.key); } </script> </body> </html>
完整代码:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>这是网页标题</title> 6 <style> 7 .map{ 8 width: 800px; 9 height: 600px; 10 background-color: #ccc; 11 position: relative; 12 } 13 </style> 14 </head> 15 <body> 16 <!-- 地图--> 17 <div class="map" id="map"></div> 18 <script src="js/common.js"></script> 19 <script> 20 var map = document.querySelector(".map"); 21 22 //1食物 食物就是一个对象,有宽,有高,有颜色,有横纵坐标 。 23 (function () { //它也是自调用函数 。 24 var arrs_Food = []; //用来存放每个小食物! 25 //食物类 26 function Food(x, y, width, height, color) { 27 this.x = x || 0; 28 this.y = y || 0; 29 this.width = width || 20; 30 this.height = height || 20; 31 this.color = color || "green"; 32 } 33 //为Food原型添加 初始化函数,以便能够显示在 地图上! 34 Food.prototype.init = function(map){ 35 removeFood(); //每次init() 前都首先清空所有食物,然后再创建一个。 36 37 //创建div 食物 38 var divFood = document.createElement("div"); 39 divFood.style.width = this.width + "px"; 40 divFood.style.height = this.height +"px"; 41 42 //横纵坐标 要是随机值,而且食物要脱离文档流。 43 var min_w = 0; //[0,39] 44 var max_w = map.offsetWidth/ this.width -1; 45 var min_h = 0; //[0.29] 46 var max_h = map.offsetHeight/this.height -1; 47 this.x = parseInt( Math.random()*(max_w-min_w+1)+min_w); 48 this.y = parseInt( Math.random()*(max_h-min_h+1)+min_h); 49 divFood.style.left = this.x*this.width +"px"; 50 divFood.style.top = this.y*this.height +"px"; 51 divFood.style.position = "absolute"; 52 divFood.style.backgroundColor = this.color; 53 map.appendChild(divFood); 54 arrs_Food.push(divFood); 55 }; 56 57 //如果多次调用init() 的话,会产生多个食物在界面上,如何解决? 58 //定义一个 私有的函数 用来清除食物--1,数组中清除 2,地图上也不显示 59 function removeFood(){ 60 /*该函数 外部无法访问!!!*/ 61 for (var i =0;i<arrs_Food.length;i++){ 62 //1,地图上不再显示该元素。 63 arrs_Food[i].parentElement.removeChild(arrs_Food[i]); 64 //2,数组中也要删除这个食物 65 arrs_Food.splice(i,1); //从数组中删除该索引的 元素。 66 } 67 } 68 69 70 //为了能在外面使用Food , 将食物类 绑定到window上 71 window.Food = Food; 72 }()); 73 74 //2小蛇 小蛇有宽,有高,有方向,宽高指的是 组成蛇身体的小方块的 宽高 75 (function () { 76 var arr_Body = []; //存放小蛇的 身体部分。 处理当多次init 产生的问题! 77 78 function Snake(width,height,direction) { 79 this.width = width || 20; 80 this.height = height || 20; 81 this.direction = direction ||"right"; 82 83 //小蛇的身体 84 this.body = [ 85 {x:3,y:2,color:"red"},//头 86 {x:2,y:2,color:"orange"},//身体1 87 {x:1,y:2,color:"orange"},//身体2 88 ]; 89 90 } 91 //为Snake的原型添加方法 92 Snake.prototype.init = function (map) { 93 //init 前先 remove(); 94 remove(); 95 //目前的蛇有三个部分, 三个div 96 for (var i = 0;i<this.body.length;i++){ 97 var div = document.createElement("div"); 98 //div 要脱离文档流 99 div.style.width = this.width+"px"; 100 div.style.height = this.height+"px"; 101 div.style.position = "absolute"; 102 div.style.left = this.body[i].x*this.width+"px"; 103 div.style.top = this.body[i].y*this.height +"px"; 104 div.style.backgroundColor = this.body[i].color; 105 map.appendChild(div); 106 107 //把div 加入到arr_Body数组中去,目的也是为了, 当多次init的时候不创建的多个 108 arr_Body.push(div); 109 } 110 }; 111 112 //定义个私有函数, 清除蛇的每个部分,达到 多次init 而不会显示多个. 113 function remove(){ 114 var arr_len = arr_Body.length; //不能直接放下面 做判断条件 ,会出错(因为下面 出现了操作 arr_Body数组,所以如果还直接让它作为条件就会出错了!!! 一定要注意)! 115 for (var i =arr_len-1;i >=0 ;i--){ 116 var div = arr_Body[i]; 117 // div.parentNode 118 div.parentElement.removeChild(div); 119 //数组中也要删掉它自己 120 arr_Body.splice(i,1); //要从后往前删! 121 } 122 } 123 124 //为Snake 的原型添加方法,使小蛇动起来。 125 Snake.prototype.move = function(map,food){ 126 127 //蛇身子的移动 后一个的坐标变为前一个的坐标 128 var i = this.body.length -1; //2 1 2 3 head 129 for (;i > 0;i--){ 130 this.body[i].x = this.body[i-1].x; 131 this.body[i].y = this.body[i-1].y; 132 } 133 //蛇头的移动(身子移动之后 ,头才能移动!!!) 134 switch (this.direction) { 135 case "right": this.body[0].x +=1;break; 136 case "left": this.body[0].x -=1;break; 137 case "up": this.body[0].y -=1;break; 138 case "down": this.body[0].y +=1;break; 139 } 140 //判断是否吃到食物 141 var headX = this.body[0].x; 142 var headY = this.body[0].y; 143 var foodX = food.x; 144 var foodY= food.y; 145 // console.log(headX +" "+foodX); 146 if(headX == foodX && headY == foodY){ 147 // console.log("吃到食物了"); 148 //隐藏吃到的食物,然后产生一个新的食物 149 food.init(map); //food.init() 自身就会先清理一个,然后再产生一个新的食物! 150 151 //再创建一个新的身体! 152 var lastBody = this.body[this.body.length -1]; 153 this.body.push({ //把当前最后一个身体 复制一份让后加到this.body中 154 x:lastBody.x, 155 y:lastBody.y, 156 color:lastBody.color 157 }); 158 } 159 this.init(map); 160 }; 161 window.Snake = Snake; 162 }()); 163 164 //3 游戏对象 Game 165 (function () { 166 function Game(map) { 167 this.food = new Food(); 168 this.snake = new Snake(); 169 this.map = map; 170 that = this; 171 } 172 Game.prototype.init = function () { 173 this.food.init(this.map); 174 this.snake.init(this.map); 175 this.runSnake(); 176 177 //调用获取按键的函数 178 this.bindKey(); 179 }; 180 Game.prototype.runSnake = function(){ 181 var timeId = setInterval(function () { 182 //这里的this 是window ,但是我们想用的是 Game对象。可以通过bind(that) 使这里的this不再是window! 183 this.snake.move(this.map,this.food); 184 185 //最大横坐标 maxX (0-39) 186 var maxX = this.map.offsetWidth / this.snake.width -1; 187 var maxY = this.map.offsetHeight / this.snake.height -1; 188 // console.log(maxX +"==="+maxY); 189 var headX = this.snake.body[0].x; 190 var headY = this.snake.body[0].y; 191 if(headX < 0 || headX > maxX){ 192 // console.log("超界了"); 193 window.clearInterval(timeId); 194 alert("游戏结束!"); 195 } 196 if(headY < 0 || headY > maxY){ 197 // console.log("超界了"); 198 window.clearInterval(timeId); 199 alert("游戏结束!"); 200 } 201 }.bind(that),100); 202 }; 203 204 Game.prototype.bindKey = function(){ 205 /*获取用户的按键,改变小蛇的运动方向*/ 206 document.addEventListener("keydown",function (evt) { 207 switch (evt.key) { 208 case "ArrowUp":this.snake.direction = "up";break; 209 case "ArrowDown":this.snake.direction = "down";break; 210 case "ArrowRight":this.snake.direction = "right";break; 211 case "ArrowLeft":this.snake.direction = "left";break; 212 } 213 }.bind(that),false) 214 }; 215 window.Game = Game; 216 }()); 217 218 var game = new Game(map); 219 game.init(); 220 // game.init(); //此时如果调用多次,会加快速度 ,暂时不管它! 221 // game.init(); 222 223 </script> 224 </body> 225 </html>
还可以将多个 自调用函数分到多个js文件中,分文件编写
注:缺少内容是因为误删未保存