zoukankan      html  css  js  c++  java
  • [原创]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

  • 相关阅读:
    Thymeleaf+Spring使用自己的工具类
    bootstrap 响应式布局
    bootstrap 流布局
    bootstrap 布局
    bootstrap 新建网页
    quick 定时更新函数
    acm hdoj 1157
    acm hdoj 今年暑假不ac
    quick removeTileMaptile
    quick schedule 的添加和移除
  • 原文地址:https://www.cnblogs.com/wangxinsheng/p/4351369.html
Copyright © 2011-2022 走看看