[原创]html5游戏_贪吃蛇

代码随便写写,尚有许多不足,PC与手机端皆可运行

手机端滑屏操作,PC端方向键操作

疑问:

生成食物,与判断是否可以移动方面

有两种实现方式,

1.使用js内存,数组循环判断

2.使用dom的query方法

哪种比较快,哪种比较好?

目前的代码是用第二种方法实现

在线地址:

http://wangxinsheng.herokuapp.com/snake

截图:

部分代码:

html:

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8">
 5         <meta name="description" content="html5 snake game">
 6         <meta name="keywords" content="snake,html5,canvas,web,game">
 7         <meta name="author" content="WangXinsheng">
 8         <meta name="apple-mobile-web-app-capable" content="yes">
 9         <meta name="apple-mobile-web-app-status-bar-style" content="black">
10         <meta name="viewport" id="viewport" content="width = device-width, initial-scale = 1, minimum-scale = 1, maximum-scale = 1, user-scalable=no">
11         <meta http-equiv="X-UA-Compatible" content="chrome=1">
12         <meta http-equiv="Pragma" content="no-cache">
13         <meta http-equiv="Cache-Control" content="no-cache">
14         <meta equiv="Expires" content="0">
15         <meta http-equiv="content-script-type" content="text/javascript">
16         <title>CopyRight&copy;WangXinsheng</title>
17         <script src="game/requestNextAnimationFrame.js"></script>
18         <style type="text/css">
19          html {color:#000;background:gray;margin:0px; overflow:hidden;}
20          body {-webkit-user-select:none;margin:0px;}
21          #gameWorld {background-color:#C6EEC6}
22          #opp{color:red; font-size:30px; font-weight:bold; text-align:center;vertical-align:middle; cursor:pointer;}
23         </style>
24     </head>
25     <body>
26         <canvas id="gameWorld" style="position: absolute; left: 0px; top: 0px;">
27             <p>You need a modern browser to view this.</p>
28         </canvas>
29         <div id="opp" style="position: absolute; left: 0px; top: 0px;">点击开始游戏</div>
30         <ul style='display:none' id='dataDom'></ul>
31     </body>
32     <script src="game/snakeGame_min.js"></script>
33 </html>
View Code

js使用dom方法:

1.初期往页面放入dom

 1 /*put data dom*/
 2 var dataDom = document.getElementById("dataDom");
 3 // document.querySelector("#dataDom");
 4 var domInner = "";
 5 for(var i = 1;i<=blockWNum;i++){
 6     for(var j = 1;j<=blockHNum;j++){
 7         domInner += liStr
 8             .replace("{%x%}",i)
 9             .replace("{%y%}",j)
10             .replace("{%s%}","0");
11     }
12 }
13 dataDom.innerHTML =domInner; //domInner;

2.判断是否撞到自己

1 result = 
2 ("1"==document.querySelector("#dataDom [data-x='"+nx+"'][data-y='"+ny+"']").getAttribute("data-s"))
3 ?false
4 :true;

3.蛇移动:1)移动目的地作为头部插入蛇身体。2)删除蛇尾部

 1 switch(dir){
 2     case "N":
 3         this.body.splice(0,0,{"x":this.body[0].x,"y":this.body[0].y-1});
 4         break;
 5     case "S":
 6         this.body.splice(0,0,{"x":this.body[0].x,"y":this.body[0].y+1});
 7         break;
 8     case "W":
 9         this.body.splice(0,0,{"x":this.body[0].x-1,"y":this.body[0].y});
10         break;
11     case "E":
12         this.body.splice(0,0,{"x":this.body[0].x+1,"y":this.body[0].y});
13         break;
14     default:;
15 }
16 this.setSnakeSts(this.body[0].x,this.body[0].y,1);
17 document.querySelector("#dataDom [data-x='"+x+"'][data-y='"+y+"']").setAttribute("data-s",s);
1 this.setSnakeSts(this.body[this.body.length-1].x,this.body[this.body.length-1].y,0);
2 this.body.splice(this.body.length-1,1);

4.事件绑定

1 if(!v){
2     document.addEventListener("keyup", onKeyPress, false);
3 }else{
4     caObj.addEventListener("touchstart", onTouchStart, false);
5     caObj.addEventListener("touchmove", onTouchMove, false);
6     caObj.addEventListener("touchend", onTouchEnd, false);
7 }
8 window.addEventListener("resize", doSize, false);

逻辑流程:

1.初期化canvas大小,位置和蛇身体单格大小

2.生成蛇,食物

3.蛇动作:可否移动,移动,吃食

4.循环动画[定期生成食物,移动操作蛇]

这个非常简单,js完整源码:

  1 ;
  2 var debug = true;
  3 var gameWorld = function () {
  4     /*function init params*/
  5     function doVarInit() {
  6         //started = true;
  7         if(debug)
  8             console.log("hello snake powered by WangXinsheng");
  9     }
 10     /*function on resize the window*/
 11     function doSize() {
 12         // should start again
 13         var minLength = window.innerWidth>window.innerHeight
 14             ?window.innerHeight
 15             :window.innerWidth,
 16             maxLength = window.innerWidth<window.innerHeight
 17             ?window.innerHeight
 18             :window.innerWidth;
 19         blockW = Math.floor(minLength / blockMinNum);
 20         var caMin = blockW * blockMinNum;
 21         var caMax = Math.floor(maxLength / blockW) * blockW;
 22 
 23         caW = window.innerWidth>window.innerHeight
 24             ?caMax
 25             :caMin;
 26         caH = window.innerWidth<window.innerHeight
 27             ?caMax
 28             :caMin;
 29 
 30         blockWNum = caW / blockW;
 31         blockHNum = caH / blockW;
 32 
 33         var top = (window.innerHeight - caH) * 0.5,
 34             left = (window.innerWidth - caW) * 0.5;
 35 
 36         //if(debug)
 37             //console.log(blockWNum,blockHNum,top,left);//
 38 
 39         caObj.width = caW;
 40         caObj.height = caH;
 41         caObj.style.width = caW + "px";
 42         caObj.style.height = caH + "px";
 43         caObj.style.left = left + "px";
 44         caObj.style.top = top + "px";
 45         oppDiv.width = caW;
 46         oppDiv.height = caH;
 47         oppDiv.style.width = caW + "px";
 48         oppDiv.style.height = caH + "px";
 49         oppDiv.style.left = left + "px";
 50         oppDiv.style.top = top + "px";
 51         oppDiv.style.lineHeight = caH + "px";
 52 
 53         
 54         /*put data dom*/
 55         var dataDom = document.getElementById("dataDom");
 56         // document.querySelector("#dataDom");
 57         var domInner = "";
 58         for(var i = 1;i<=blockWNum;i++){
 59             for(var j = 1;j<=blockHNum;j++){
 60                 domInner += liStr
 61                     .replace("{%x%}",i)
 62                     .replace("{%y%}",j)
 63                     .replace("{%s%}","0");
 64             }
 65         }
 66         dataDom.innerHTML =domInner; //domInner;
 67         //var oldDom = document.querySelector("#dataDom");
 68         //removeDom(oldDom);
 69 
 70         lastFpsUpdateTime = (+new Date);
 71         lastFpsUpdateTimeFood = (+new Date);
 72     }
 73     function setSnakeSts(x,y,s){
 74         document.querySelector("#dataDom [data-x='"+x+"'][data-y='"+y+"']").setAttribute("data-s",s);
 75     }
 76     function gen(name) {
 77         /*product object*/
 78         switch(name){
 79             case "snake":
 80                 var body = [];
 81                 body.splice(0,0,{"x":1,"y":1});
 82                 body.splice(0,0,{"x":2,"y":1});
 83                 body.splice(0,0,{"x":3,"y":1});
 84                 body.splice(0,0,{"x":4,"y":1});
 85                 setSnakeSts(1,1,1);
 86                 setSnakeSts(2,1,1);
 87                 setSnakeSts(3,1,1);
 88                 setSnakeSts(4,1,1);
 89 
 90                 snakeObj = new snake(snakeColor,true,"E",blockW,initSpeed,body);
 91                 snakeObj.draw(caCt);
 92                 break;
 93             case "food":
 94                 var allFood = document.querySelectorAll("#dataDom [data-s='0']"),
 95                     foodX,foodY,index;
 96                 if(allFood.length==1){
 97                     index = 0;
 98                 }else if(allFood.length>1){
 99                     index = Math.round(Math.random()*(allFood.length-1));
100                 }
101                 if(allFood.length>=1){
102                     foodX = parseInt(allFood[index].getAttribute("data-x"));
103                     foodY = parseInt(allFood[index].getAttribute("data-y"));
104                     allFood[index].getAttribute("data-s","2");
105                     foodObj.x = foodX;
106                     foodObj.y = foodY;
107                     foodObj.live = true;
108                 }
109                 drawFood();
110                 break;
111             default:
112         }
113     }
114     function picIsLoaded() {
115         return true;
116     }
117     function loadPics() {
118         /*load pic to objectList*/
119     }
120     function loadedImg() {
121         /*if image loaded do here*/
122     }
123     function drawObject(name){
124         /*draw object to canvas*/
125     }
126     function animate(time) {
127         if (started) {
128             var now = (+new Date);
129             if (now - lastFpsUpdateTime > snakeObj.speed) {
130                 /*animate*/
131                 if(snakeObj.canMove(snakeObj.dir,blockWNum,blockHNum)){
132                     if(snakeObj.canEat(snakeObj.dir,foodObj)){
133                         snakeObj.doEat(snakeObj.dir,foodObj);
134                     }else{
135                         snakeObj.doMove(snakeObj.dir);
136                     }
137                 }else{
138                     // over
139                     started = false;
140                     oppDiv.style.display = "block";
141                     oppDiv.innerHTML = "点击再次游戏";
142                     return;
143                 }
144                 
145                 caCt.save();
146                 caCt.fillStyle = "#C6EEC6";
147                 caCt.fillRect(0,0,caW,caH);
148                 
149                 caCt.font = '40px Helvetica';
150                 caCt.textAlign = "center";
151                 caCt.textBaseline = "middle";
152                 caCt.fillStyle = '#8CCDD8';
153                 caCt.strokeStyle = '#8CCDD8';
154                 caCt.fillText("WangXinsheng", caW/2,caH/2);
155                 caCt.strokeText("WangXinsheng", caW/2,caH/2);
156 
157                 caCt.restore();
158 
159                 snakeObj.draw(caCt);
160 
161                 // draw food
162                 drawFood();
163                 
164                 lastFpsUpdateTime = (+new Date);
165             }
166             
167             if (now - lastFpsUpdateTimeFood > snakeObj.speed*5) {
168                 if(!foodObj.live){
169                     gen("food");
170                 }else{
171                     lastFpsUpdateTimeFood = (+new Date);
172                 }
173             }
174         }
175         window.requestNextAnimationFrame(animate);
176     }
177     function drawFood(){
178         if(foodObj.live){
179             caCt.save();
180             caCt.fillStyle = foodObj.color;
181             caCt.fillRect(
182                 (foodObj.x-1)*blockW,
183                 (foodObj.y-1)*blockW,
184                 blockW,
185                 blockW
186             );
187             caCt.restore();
188         }
189     }
190     function eventBund(){
191         if(!v){
192             document.addEventListener("keyup", onKeyPress, false);
193         }else{
194             caObj.addEventListener("touchstart", onTouchStart, false);
195             caObj.addEventListener("touchmove", onTouchMove, false);
196             caObj.addEventListener("touchend", onTouchEnd, false);
197             caObj.addEventListener("touchcancel", stopEvent, false);
198             caObj.addEventListener("gesturestart", stopEvent, false);
199             caObj.addEventListener("gesturechange", stopEvent, false);
200             caObj.addEventListener("gestureend", stopEvent, false);
201         }
202         window.addEventListener("resize", doSize, false);
203     }
204     function onKeyPress(e){
205         //console.log(e);
206         var dir = "";
207         switch(e.keyCode){
208             case 38:
209                 dir =snakeObj.dir=="S"?"":"N";
210                 break;
211             case 40:
212                 dir =snakeObj.dir=="N"?"":"S";
213                 break;
214             case 37:
215                 dir =snakeObj.dir=="E"?"":"W";
216                 break;
217             case 39:
218                 dir =snakeObj.dir=="W"?"":"E";
219                 break;
220             default:;
221         }
222         if(dir!="")
223             snakeObj.dir = dir;
224     }
225     function onTouchEnd(e){
226         e.preventDefault();
227         if(mouseTObj.x!=null && mouseTObj.y!=null
228             && mouseTMObj.x!=null && mouseTMObj.y!=null){
229             var diffX = mouseTMObj.x - mouseTObj.x,
230                 diffY = mouseTMObj.y - mouseTObj.y,
231                 dir = "";
232             if(Math.abs(diffY)>Math.abs(diffX)){
233                 dir = diffY>0?"S":"N";
234             }else if(Math.abs(diffY)<Math.abs(diffX)){
235                 dir = diffX>0?"E":"W";
236             }
237             switch(dir){
238                 case "N":
239                     snakeObj.dir =snakeObj.dir=="S"?"S":"N";
240                     break;
241                 case "S":
242                     snakeObj.dir =snakeObj.dir=="N"?"N":"S";
243                     break;
244                 case "W":
245                     snakeObj.dir =snakeObj.dir=="E"?"E":"W";
246                     break;
247                 case "E":
248                     snakeObj.dir =snakeObj.dir=="W"?"W":"E";
249                     break;
250                 default:;
251             }
252             mouseTObj.x = null;
253             mouseTObj.y = null;
254             mouseTMObj.x = null;
255             mouseTMObj.y = null;
256         }
257         e.stopPropagation();
258         return false;
259     }
260     function onTouchMove(e){
261         e.preventDefault();
262         var touch = e.touches[0];
263         mouseTMObj.x = touch.pageX;
264         mouseTMObj.y = touch.pageY;
265         e.stopPropagation();
266         return false;
267     }
268     function onTouchStart(e){
269         e.preventDefault();
270         var touch = e.touches[0];
271         mouseTObj.x = touch.pageX;
272         mouseTObj.y = touch.pageY;
273         e.stopPropagation();
274         return false;
275     }
276     function stopEvent(e) { e.preventDefault(); e.stopPropagation(); }
277     var v = navigator.userAgent.toLowerCase().indexOf("android") != -1 || navigator.userAgent.toLowerCase().indexOf("iphone") != -1 || navigator.userAgent.toLowerCase().indexOf("ipad") != -1,
278     caW = window.innerWidth,
279     caH = window.innerHeight,
280     caObj = document.getElementById("gameWorld"),
281     caCt = caObj.getContext("2d"),
282     oppDiv = document.getElementById("opp"),
283     lastFpsUpdateTime = new Date,
284     lastFpsUpdateTimeFood = new Date,
285     started = false,
286     blockW = 0,
287     blockMinNum = 20,
288     blockWNum = 0,
289     blockHNum = 0,
290     snakeObj = null,
291     snakeColor = "gray",
292     initSpeed = 150,
293     liStr = "<li data-x='{%x%}' data-y='{%y%}' data-s='{%s%}'></li>", //s:0-empty,1-snake,2-food
294     foodObj = {"x":0,"y":0,"live":false,"color":"red"},
295     mouseTObj = {"x":null,"y":null},
296     mouseTMObj = {"x":null,"y":null}
297     ;
298 
299     this.init = function () {
300         //*********init params*******
301         doVarInit();
302         //*********init size and vars*******
303         doSize();
304         //*********product bell and rabit*******
305         gen("snake");
306         gen("food");
307         //gen("yyy");
308         //*********Event***********
309         eventBund();
310         //*********Gen***********
311         //*********animate***********
312         animate();
313     }
314     this.start = function(){
315         oppDiv.style.display = "none";
316         started = true;
317     }
318 }
319 
320 /*
321 * object
322 */
323 function snake(bgC,live,dir,blockW,speed,body) {
324     this.bgC = bgC; // 涂色
325     this.live=live; // 存活状态 true,false
326     this.dir=dir; // 移动方向 N,S,W,E
327     this.blockW=blockW; // 方块边大小
328     this.speed=speed; // 速度 1000
329     this.body = body; // 蛇身体
330 }
331 snake.prototype.draw = function (context) {
332     context.save();
333     context.fillStyle = "gray";
334     for(var i = 0;i<this.body.length;i++){
335         context.fillRect(
336             (this.body[i].x-1)*this.blockW,
337             (this.body[i].y-1)*this.blockW,
338             this.blockW,
339             this.blockW
340         );
341     }
342     context.restore();
343 }
344 snake.prototype.canMove = function (dir,xMax,yMax) {
345     var result = false,
346         nx = this.body[0].x,
347         ny = this.body[0].y;
348     // 边框检测
349     switch(dir){
350         case "N":
351             result = this.body[0].y==1?false:true;
352             ny--;
353             break;
354         case "S":
355             result = this.body[0].y==yMax?false:true;
356             ny++;
357             break;
358         case "W":
359             result = this.body[0].x==1?false:true;
360             nx--;
361             break;
362         case "E":
363             result = this.body[0].x==xMax?false:true;
364             nx++;
365             break;
366         default:;
367     }
368     // 自己检测
369     //console.log(document.querySelector("#dataDom [data-x='"+nx+"'][data-y='"+ny+"']").getAttribute("data-s"));
370     if(result)
371         result = 
372         ("1"==document.querySelector("#dataDom [data-x='"+nx+"'][data-y='"+ny+"']").getAttribute("data-s"))
373         ?false
374         :true;
375     return result;
376 }
377 snake.prototype.canEat = function (dir,food) {
378     var sx=this.body[0].x,
379         sy=this.body[0].y;
380     switch(dir){
381         case "N":
382             sy--;
383             break;
384         case "S":
385             sy++;
386             break;
387         case "W":
388             sx-1;
389             break;
390         case "E":
391             sx+1;
392             break;
393         default:;
394     }
395     return (food.x==sx && food.y==sy);
396 }
397 // push第一个,pop最后一个
398 snake.prototype.doMove = function (dir) {
399     this.doEat(dir,null);
400     this.setSnakeSts(this.body[this.body.length-1].x,this.body[this.body.length-1].y,0);
401     this.body.splice(this.body.length-1,1);
402 }
403 // push第一个
404 snake.prototype.doEat = function (dir,food) {
405     switch(dir){
406         case "N":
407             this.body.splice(0,0,{"x":this.body[0].x,"y":this.body[0].y-1});
408             break;
409         case "S":
410             this.body.splice(0,0,{"x":this.body[0].x,"y":this.body[0].y+1});
411             break;
412         case "W":
413             this.body.splice(0,0,{"x":this.body[0].x-1,"y":this.body[0].y});
414             break;
415         case "E":
416             this.body.splice(0,0,{"x":this.body[0].x+1,"y":this.body[0].y});
417             break;
418         default:;
419     }
420     this.setSnakeSts(this.body[0].x,this.body[0].y,1);
421     if(food!=null)
422         food.live = false;
423 }
424 snake.prototype.setSnakeSts = function(x,y,s){
425     document.querySelector("#dataDom [data-x='"+x+"'][data-y='"+y+"']").setAttribute("data-s",s);
426 }
427 
428 var gameWorldObj = null;
429 window.onload = function () {
430     document.getElementsByTagName('title')[0].innerHTML = "[WXS]贪吃蛇";
431     snakeGameGo();
432 }
433 function snakeGameGo(){
434     if(gameWorldObj == null)
435         gameWorldObj = new gameWorld();
436     gameWorldObj.init();
437     var opp = document.getElementById("opp");
438     opp.addEventListener("click", doPlay, false);
439 }
440 function doPlay(){gameWorldObj.init();gameWorldObj.start();}
View Code

运行文件下载地址:

http://download.csdn.net/detail/wangxsh42/8515975

原文地址:https://www.cnblogs.com/wangxinsheng/p/4351369.html