代码改变世界

用Js写的贪吃蛇游戏

2015-07-22 12:00  熠旸  阅读(895)  评论(0编辑  收藏  举报
  1. <!doctype html>  
  2.   
  3. <html>  
  4.   
  5. <head><title>snake</title>  
  6.   
  7. <script>  
  8.   
  9. function Snake(canvas){  
  10.   
  11.     this.canvas = canvas;  
  12.   
  13.     this.length = 0;  
  14.   
  15.     this.direction = 'down';  
  16.   
  17.     this.body = [],  
  18.   
  19.     this.head = function(){  
  20.   
  21.         return this.length == 0 ? null : this.body[0];  
  22.   
  23.     };  
  24.   
  25.     this.isAlive = true;  
  26.   
  27.     this.onDie = null;  
  28.   
  29.     this.onEat = null;  
  30.   
  31.     this.speed = 200;  
  32.   
  33.     this.auto = null;  
  34.   
  35.     this.turnLeft = function(){  
  36.   
  37.         if(this.direction == 'left' || this.direction == 'right'){  
  38.   
  39.             return;  
  40.   
  41.         }else{  
  42.   
  43.             this.direction = 'left';  
  44.   
  45.         }  
  46.   
  47.     };  
  48.   
  49.     this.turnRight = function(){  
  50.   
  51.         if(this.direction == 'left' || this.direction == 'right'){  
  52.   
  53.             return;  
  54.   
  55.         }else{  
  56.   
  57.             this.direction = 'right';  
  58.   
  59.         }  
  60.   
  61.     };  
  62.   
  63.     this.turnUp = function(){  
  64.   
  65.         if(this.direction == 'up' || this.direction == 'down'){  
  66.   
  67.             return;  
  68.   
  69.         }else{  
  70.   
  71.             this.direction = 'up';  
  72.   
  73.         }  
  74.   
  75.     };  
  76.   
  77.     this.turnDown = function(){  
  78.   
  79.         if(this.direction == 'up' || this.direction == 'down'){  
  80.   
  81.             return;  
  82.   
  83.         }else{  
  84.   
  85.             this.direction = 'down';  
  86.   
  87.         }  
  88.   
  89.     };  
  90.   
  91.     this.moveTo = function(x, y){  
  92.   
  93.         this.canvas.clsCanvas(this);  
  94.   
  95.         this.body.pop();  
  96.   
  97.         this.length--;  
  98.   
  99.         this.grow(x, y);  
  100.   
  101.         this.canvas.drawSnake(this);  
  102.   
  103.     };  
  104.   
  105.     this.grow = function(bX, bY){  
  106.   
  107.         var head = {  
  108.   
  109.             x : bX,  
  110.   
  111.             y : bY  
  112.   
  113.         };  
  114.   
  115.         this.body.unshift(head);  
  116.   
  117.         this.length++;  
  118.   
  119.     };  
  120.   
  121.     this.stepWalk = function(){  
  122.   
  123.         if(!this.isAlive){return;}  
  124.   
  125.         if(!this.head()){  
  126.   
  127.             throw new Error('this snake is not initialized');  
  128.   
  129.         }  
  130.   
  131.         var nextBlock, head = this.head();  
  132.   
  133.         var nX = head.x, nY = head.y;  
  134.   
  135.         switch(this.direction){  
  136.   
  137.             case 'down':  
  138.   
  139.                 nY = head.y + 1;  
  140.   
  141.                 break;  
  142.   
  143.             case 'up':  
  144.   
  145.                 nY = head.y - 1;  
  146.   
  147.                 break;  
  148.   
  149.             case 'left':  
  150.   
  151.                 nX = head.x - 1;  
  152.   
  153.                 break;  
  154.   
  155.             case 'right':  
  156.   
  157.                 nX = head.x + 1;  
  158.   
  159.                 break;  
  160.   
  161.         }  
  162.   
  163.         if(nX 1 || nY 1 || nX > canvas.width || nY > canvas.height || this.contains(nX, nY)){  
  164.   
  165.             this.isAlive = false;  
  166.   
  167.             if(this.onDie){this.onDie();}  
  168.   
  169.         }else{  
  170.   
  171.             nextBlock = this.canvas.getBlock(nX, nY);  
  172.   
  173.             if(this.canvas.isFoodBlock(nextBlock)){  
  174.   
  175.                 nextBlock.setAttribute('food','');  // the food has been eaten  
  176.   
  177.                 this.grow(nX, nY);  
  178.   
  179.                 if(this.onEat){this.onEat();}  
  180.   
  181.                 var t = this;  
  182.   
  183.                 setTimeout(function(){t.stepWalk();},80 );  
  184.   
  185.             }else{  
  186.   
  187.                 this.moveTo(nX, nY);  
  188.   
  189.             }  
  190.   
  191.         }  
  192.   
  193.     };  
  194.   
  195.     this.autoWalk = function(){  
  196.   
  197.         var snake = this;  
  198.   
  199.         this.auto = setInterval(function(){  
  200.   
  201.                                 if(snake.isAlive){  
  202.   
  203.                                     snake.stepWalk();  
  204.   
  205.                                 }else{  
  206.   
  207.                                     clearInterval(snake.auto);  
  208.   
  209.                                 }  
  210.   
  211.                             }, this.speed );  
  212.   
  213.     };  
  214.   
  215.     this.contains = function(x,y){  
  216.   
  217.             var len = this.length, snakeBody = this.body, b;  
  218.   
  219.             for(var i=0;i<len;i++){  
  220.   
  221.                 b = snakeBody[i];  
  222.   
  223.                 if(b.x == x && b.y == y){  
  224.   
  225.                     return true;  
  226.   
  227.                 }  
  228.   
  229.             }  
  230.   
  231.             return false;  
  232.   
  233.     };  
  234.   
  235.     this.init = function(length){  
  236.   
  237.         if(length<this.canvas.height){  
  238.   
  239.             for(var i=0; i<length;i++){  
  240.   
  241.                 this.grow(1, i+1);  
  242.   
  243.             }  
  244.   
  245.         };  
  246.   
  247.         this.canvas.drawSnake(this);  
  248.   
  249.         this.canvas.createFood();  
  250.   
  251.     },  
  252.   
  253.     this.pause = function(){  
  254.   
  255.         if(this.auto){  
  256.   
  257.             clearInterval(this.auto);  
  258.   
  259.             this.auto = null;  
  260.   
  261.         }  
  262.   
  263.     };    
  264.   
  265. }  
  266.   
  267. function SnakeCanvas(div){  
  268.   
  269.     this.target = div;  
  270.   
  271.     this.createView();  
  272.   
  273. }  
  274.   
  275. SnakeCanvas.prototype = {  
  276.   
  277.     width: 20,  
  278.   
  279.     height: 16,  
  280.   
  281.     currentSnake : null,  
  282.   
  283.     createView : function(){  
  284.   
  285.         var i = 0, span;  
  286.   
  287.         addClass(this.target, 'target');  
  288.   
  289.           
  290.   
  291.         while(i 320){  
  292.   
  293.             span = document.createElement('span');  
  294.   
  295.             span.id = 'span_' + (++i);  
  296.   
  297.             addClass(span, 'blocks');  
  298.   
  299.             this.target.appendChild( span );  
  300.   
  301.         }  
  302.   
  303.     },  
  304.   
  305.     getBlock : function(x, y){  
  306.   
  307.         return document.getElementById('span_' + (y ? ((y-1) * this.width + x) : (x+1)));  
  308.   
  309.     },  
  310.   
  311.     activateBlock : function(block){  
  312.   
  313.         block.setAttribute('act', 'true');  
  314.   
  315.         addClass(block, 'snake-body');  
  316.   
  317.     },  
  318.   
  319.     inActivateBlock: function(block){  
  320.   
  321.         block.setAttribute('act', '');  
  322.   
  323.         removeClass(block, 'snake-body');  
  324.   
  325.     },  
  326.   
  327.     switchBlock: function(block){  
  328.   
  329.         var active = block.getAttribute('act');  
  330.   
  331.         if(active){  
  332.   
  333.             this.inActivateBlock(block);  
  334.   
  335.         }else{  
  336.   
  337.             this.activateBlock(block);  
  338.   
  339.         }  
  340.   
  341.     },  
  342.   
  343.     isFoodBlock: function(block){  
  344.   
  345.         return !!(block.getAttribute('food'));  
  346.   
  347.     },  
  348.   
  349.     createFood : function(){  
  350.   
  351.         var posX = 0, posY = 0, done = false, block;  
  352.   
  353.         while( !done){  
  354.   
  355.             posX = Math.floor(Math.random() * (this.width + 1));  
  356.   
  357.             posY = Math.floor(Math.random() * (this.height + 1));  
  358.   
  359.             if(posX == 0){ posX = 1;} if(posY == 0){ posY = 1;}  
  360.   
  361.             block = this.getBlock(posX, posY);  
  362.   
  363.             if(!this.currentSnake || (!this.currentSnake.contains(posX, posY))){  
  364.   
  365.                 block.setAttribute('food', 'true');  
  366.   
  367.                 this.switchBlock(block);  
  368.   
  369.                 done = true;  
  370.   
  371.             }  
  372.   
  373.         }  
  374.   
  375.     },  
  376.   
  377.     clsCanvas : function(snake){  
  378.   
  379.         var snakeBlock, i = 0;  
  380.   
  381.         if(snake){  
  382.   
  383.             for(;i<snake.length;i++){  
  384.   
  385.                 snakeBlock = snake.body[i];  
  386.   
  387.                 this.inActivateBlock(this.getBlock(snakeBlock.x, snakeBlock.y));  
  388.   
  389.             }  
  390.   
  391.         }else{  
  392.   
  393.             while(ithis.width * this.height){  
  394.   
  395.                 this.inActivateBlock(this.getBlock(i));  
  396.   
  397.             }  
  398.   
  399.         }  
  400.   
  401.     },  
  402.   
  403.     drawSnake : function(snake){  
  404.   
  405.         var snakeBlock;  
  406.   
  407.         for(var i=0;i<snake.length;i++){  
  408.   
  409.             snakeBlock = snake.body[i];  
  410.   
  411.             this.activateBlock(this.getBlock(snakeBlock.x, snakeBlock.y));  
  412.   
  413.         }  
  414.   
  415.         this.currentSnake = snake;  
  416.   
  417.     }  
  418.   
  419. };  
  420.   
  421. //---------------------------//  
  422.   
  423.   
  424.   
  425. function trim(text){  
  426.   
  427.     var rnotwhite = /\S/,  
  428.   
  429.     // Used for trimming whitespace  
  430.   
  431.     trimLeft = /^\s+/,  
  432.   
  433.     trimRight = /\s+$/;   
  434.   
  435.   
  436.   
  437.     // IE doesn't match non-breaking spaces with \s  
  438.   
  439.     if ( rnotwhite.test( "\xA0" ) ) {  
  440.   
  441.         trimLeft = /^[\s\xA0]+/;  
  442.   
  443.         trimRight = /[\s\xA0]+$/;  
  444.   
  445.     }  
  446.   
  447.       
  448.   
  449.     return text.toString().replace( trimLeft, "" ).replace( trimRight, "" );  
  450.   
  451. }  
  452.   
  453.   
  454.   
  455. function addClass(elem, className){  
  456.   
  457.     var setClass;  
  458.   
  459.     if ( elem.nodeType === 1 ) {  
  460.   
  461.         if ( !elem.className ) {  
  462.   
  463.             elem.className = className;  
  464.   
  465.   
  466.   
  467.         } else {  
  468.   
  469.             setClass = " " + elem.className + " ";  
  470.   
  471.             if ( !~setClass.indexOf( " " + className + " " ) ) {  
  472.   
  473.                 setClass += className + " ";  
  474.   
  475.             }  
  476.   
  477.             elem.className = trim(setClass);  
  478.   
  479.         }  
  480.   
  481.     }  
  482.   
  483. }  
  484.   
  485.   
  486.   
  487. function removeClass(elem, value){  
  488.   
  489.     var className;  
  490.   
  491.     if ( elem.nodeType === 1 && elem.className ) {  
  492.   
  493.         if ( value ) {  
  494.   
  495.             className = (" " + elem.className + " ").replace( /[\n\t\r]/g, " " );  
  496.   
  497.             className = className.replace(" " + value + " ", " ");  
  498.   
  499.             elem.className = trim( className );  
  500.   
  501.         } else {  
  502.   
  503.             elem.className = "";  
  504.   
  505.         }  
  506.   
  507.     }  
  508.   
  509. }  
  510.   
  511.  function keyDown(e){  
  512.   
  513.     if(!snake || !snake.isAlive) {  
  514.   
  515.         return;  
  516.   
  517.     }  
  518.   
  519.     e=e||window.event;  
  520.   
  521.     var keyCode = e.keyCode||e.which||e.charCode;  
  522.   
  523.     switch(keyCode){  
  524.   
  525.         case 37://左  
  526.   
  527.             snake.turnLeft();  
  528.   
  529.             break;  
  530.   
  531.         case 38://上  
  532.   
  533.             snake.turnUp();  
  534.   
  535.             break;  
  536.   
  537.         case 39://右  
  538.   
  539.             snake.turnRight();  
  540.   
  541.             break;  
  542.   
  543.         case 40://下  
  544.   
  545.             snake.turnDown();  
  546.   
  547.             break;  
  548.   
  549.         case 80://p 暂停or开始  
  550.   
  551.         case 229:  
  552.   
  553.             if(snake.auto){  
  554.   
  555.                 snake.pause();  
  556.   
  557.             }else{  
  558.   
  559.                 snake.autoWalk();  
  560.   
  561.             }  
  562.   
  563.             break;  
  564.   
  565.     }  
  566.   
  567. }  
  568.   
  569. if(document.attachEvent){  
  570.   
  571.     document.attachEvent('onkeydown', keyDown);  
  572.   
  573. }else if(document.addEventListener){  
  574.   
  575.     document.addEventListener('keydown', keyDown, false);  
  576.   
  577. }  
  578.   
  579. </script>  
  580.   
  581. <style>  
  582.   
  583. div{  
  584.   
  585.     margin: 20px auto;  
  586.   
  587. }  
  588.   
  589. .target{  
  590.   
  591.     display:block;  
  592.   
  593.     width: 400px;  
  594.   
  595.     height: 320px;  
  596.   
  597.     border: 1px solid black;  
  598.   
  599.     overflow: hidden;  
  600.   
  601. }  
  602.   
  603. .blocks{  
  604.   
  605.     display:block;  
  606.   
  607.     width: 18px;  
  608.   
  609.     height: 18px;  
  610.   
  611.     border: 1px dotted #ddd;  
  612.   
  613.     float:left;  
  614.   
  615. }  
  616.   
  617. .snake-body{  
  618.   
  619.     background-color: #111;  
  620.   
  621.     border-style: solid;  
  622.   
  623. }  
  624.   
  625. </style>  
  626.   
  627. </head>  
  628.   
  629. <body>  
  630.   
  631. <h1>Snake</h1>  
  632.   
  633. <div id='t'></div>  
  634.   
  635. <div>  
  636.   
  637. 操作提示:按上下左右键操作,按 P 键暂停或继续  
  638.   
  639. </div>  
  640.   
  641. <script>  
  642.   
  643. var canvas = new SnakeCanvas( document.getElementById('t') );  
  644.   
  645. var snake = new Snake( canvas );  
  646.   
  647. snake.onDie = function(){  
  648.   
  649.     alert('game over');  
  650.   
  651. };  
  652.   
  653. snake.onEat = function(){  
  654.   
  655.     snake.canvas.createFood();  
  656.   
  657. };  
  658.   
  659. snake.init(3);  
  660.   
  661. snake.autoWalk();  
  662.   
  663. // snake.pause();  
  664.   
  665. </script>  
  666.   
  667.   
  668.   
  669. </html>