2478次阅读
贪吃蛇游戏

主要有五个知识点,一一道破,首先是监听键盘事件

<!DOCTYPE html>
<head>
<meta charset=utf-8 />
<title>贪吃蛇游戏</title>
</head>
<body>
  <h1>按键事件</h1>
  <div id="keypress"></div>
  <div id="keydown"></div>
  <div id="keyup"></div>
  <script>
    document.onkeypress = function(e) {
      document.getElementById('keypress').innerText = 'press : ' + e.keyCode + ' ' + e.which + ' ' + e.charCode;
    }
    document.onkeydown = function(e) {
      document.getElementById('keydown').innerText = 'down : ' + e.keyCode + ' ' + e.which + ' ' + e.charCode;
    }
    document.onkeyup = function(e) {
      document.getElementById('keyup').innerText = 'up : ' + e.keyCode + ' ' + e.which + ' ' + e.charCode;
    }
  </script>
</body>  	
check the result

按键相关的东西就是三个:document.onkeypress、document.onkeydown、document.onkeyup,分别表示字符按键、按下和弹起,键的信息都在参数e中,onkeypress只有按到字符键才有效,onkeydown和onkeyup基本对所有键都有效,所以贪吃蛇的上下左右用onkeydown就好。

接下来是每隔一定时间就触发动作,其实专业术语叫定时器

<!DOCTYPE html>
<head>
<meta charset=utf-8 />
<title>贪吃蛇游戏</title>
</head>
<body>
  <h1>定时器</h1>
  <button id="start">开始</button>
  <button id="stop">停止</button>
  <div id="num"></div>
  <script>
    var i = 0;
    var timer = undefined;
    document.getElementById('start').onclick = function() {
      timer = setInterval(function(){
        i++;
        document.getElementById('num').innerText = i;
      }, 500);
      document.getElementById('start').disabled = true;
      document.getElementById('stop').disabled = false;
    };
    document.getElementById('stop').onclick = function() {
      if(timer) {
        clearInterval(timer);
        timer = undefined;
      }
      document.getElementById('start').disabled = false;
      document.getElementById('stop').disabled = true;
    };
    document.getElementById('stop').disabled = true;
  </script>
</body>	
check the result

这里的重点是setInterval函数,第一个参数是回调函数,第二个参数是时间间隔,单位ms,这个函数会返回一个timer,代表定时器,当我们要取消定时器的时候,就调用clearInterval,将setInterval返回的timer作为参数传进去。还有就是可以通过设置元素的disabled为true或false来控制按钮的可点击状态。

再接下来就是随机数了,这个也很简单:

<!DOCTYPE html>
<head>
<meta charset=utf-8 />
<title>贪吃蛇游戏</title>
</head>
<body>
  <h1>产生1~100的随机数</h1>
  <button id="btn">产生随机数</button>
  <div id="num"></div>
  <script>
    document.getElementById('btn').onclick = function() {
      var ran = Math.random();
      var res = Math.ceil(ran * 100);
      document.getElementById('num').innerText = res;
    };
  </script>
</body>	
check the result

Math.ramdon产生0~1之间的随机数,但是是小数,要把它变成1~100的整数,只需要乘以100,再向上去整就好了。

然后是二维地图的实现:

<!DOCTYPE html>
<head>
<meta charset=utf-8 />
<title>贪吃蛇游戏</title>
</head>
<style>
  .map {
    width : 400px;
    height : 400px;
    border : 5px solid brown;
    background-color : transparent;
    position : relative;
  }
  .snakehead, .snake, .target {
    width : 20px;
    height : 20px;
    position : absolute;
  }
  .snakehead {
    background-color : pink;
  }
  .snake {
    background-color : red;
  }
  .target {
    background-color : blue;
  }
</style>
<body>
  <h1>二维地图</h1>
  <div class="map">
    <div class="snakehead" style="top:0px;left:0px;"></div>
    <div class="snake" style="top:20px;left:0px;"></div>
    <div class="snake" style="top:40px;left:0px;"></div>
    <div class="snake" style="top:60px;left:0px;"></div>
    <div class="target" style="top:60px;left:60px;"></div>
  </div>
</body>	
check the result

这里用了一个relative的div作为map,然后里面蛇和食物都是absolute的div,移动的时候只要设置它们的left和top就行了。注意这里的样式设置,.snakehead, .snake, .target就可以设置.snakehead、.snake和.target的公共样式。

最后是动态添加蛇身:

<!DOCTYPE html>
<head>
<meta charset=utf-8 />
<title>贪吃蛇游戏</title>
</head>
<style>
  .map {
    width : 400px;
    height : 400px;
    border : 5px solid brown;
    background-color : transparent;
    position : relative;
  }
  .snake {
    width : 20px;
    height : 20px;
    position : absolute;
    background-color : red;
  }
</style>
<body>
  <h1>动态添加DOM元素</h1>
  <button id="add">添加</button>
  <div class="map" id="map"></div>
  <script>
    var myLeft=0;
    var myTop=0;
    document.getElementById('add').onclick = function() {
      if(myTop < 400) {
        var newNode = document.createElement('div');
        newNode.className = 'snake';
        newNode.style.top = myTop + 'px';
        newNode.style.left = myLeft + 'px';
        document.getElementById('map').appendChild(newNode);
        myLeft += 20;
        if(myLeft >= 400) {
          myLeft = 0;
          myTop += 20;
          if(myTop >= 400) {
            window.alert('满了');
          }
        }
      }
    };
  </script>
</body>	
check the result

首先我们用document.createElement来创建一个div,然后设置它的一些属性,最后用document.getElementById('map').appendChild(newNode),把它加到map中,这样就动态添加了一个div。

好了,基本的知识点都已经打通,接下来就打大BOSS了:

<!DOCTYPE html>
<head>
<meta charset=utf-8 />
<title>贪吃蛇游戏</title>
</head>
<style>
  .map {
    width : 400px;
    height : 400px;
    border : 5px solid brown;
    background-color : transparent;
    position : relative;
  }
  .snakehead, .snake, .target {
    width : 20px;
    height : 20px;
    position : absolute;
  }
  .snakehead {
    background-color : pink;
  }
  .snake {
    background-color : red;
  }
  .target {
    background-color : blue;
  }
</style>
<body>
  <h1>贪吃蛇</h1>
  <div class="map" id="map"></div>
  <script>
    // 0:up 1:left 2:down 3:right
    var dir = 3;
    var step = [{dx : 0, dy : -20}, {dx : -20, dy : 0}, {dx : 0, dy : 20}, {dx : 20, dy : 0}];
    // the snake, a array of div
    var snake = [];
    // the snake target
    var target;
    // timer
    var timer = undefined;
    // can not act two key in one interval
    var isKey = false;
    // add snake
    var add = function(left, top, className) {
      var newNode = document.createElement('div');
      newNode.className = className;
      newNode.style.left = left + 'px';
      newNode.style.top = top + 'px';
      document.getElementById('map').appendChild(newNode);
      snake.push(newNode);
    };
    // judge the target in snake
    var inSnake = function(newx, newy, type) {
      var start = 0;
      if(type == 'all') {
        start = 0;
      } else if(type == 'body') {
        start = 1;
      }
      for (var i = start; i<snake.length; i++) {
        if(parseInt(snake[i].style.left) == newx && parseInt(snake[i].style.top) == newy) {
          return true;
        }
      }
      return false;
    };
    // new target
    var newTarget = function() {
      var newx = -1;
      var newy = -1;
      while(newx == -1 || newy == -1 || inSnake(newx, newy, 'all')) {
        newx = (Math.floor(Math.random()*20) * 20);
        newy = (Math.floor(Math.random()*20) * 20);
      }
      target.style.left = newx + 'px';
      target.style.top = newy + 'px';
    };
    // snake move
    var move = function() {
      // calculate next head pos
      var nextx, nexty;
      nextx = parseInt(snake[0].style.left) + step[dir].dx;
      nexty = parseInt(snake[0].style.top) + step[dir].dy;
      // is Game Over?
      if(nextx < 0 || nextx > 380 || nexty < 0 || nexty > 380) {
        clearInterval(timer);
        window.alert('Game Over!');
        return;
      }
      // move
      var tailLeft = snake[snake.length-1].style.left;
      var tailTop = snake[snake.length-1].style.top;
      for(var i=snake.length-1; i>0; i--) {
        snake[i].style.left = snake[i-1].style.left;
        snake[i].style.top = snake[i-1].style.top;
      }
      snake[0].style.left = nextx + 'px';
      snake[0].style.top = nexty + 'px';
      // is get food?
      if(nextx == parseInt(target.style.left) && nexty == parseInt(target.style.top)) {
        add(parseInt(tailLeft), parseInt(tailTop), 'snake');
        newTarget();
      }
      // snake head meet snake body
      if(inSnake(parseInt(snake[0].style.left), parseInt(snake[0].style.top), 'body')) {
        clearInterval(timer);
        window.alert('Game Over!');
        return;
      }
      isKey = false;
    }
    add(60, 20, 'snakehead');
    add(40, 20, 'snake');
    add(20, 20, 'snake');
    target = document.createElement('div');
    target.className = 'target';
    newTarget();
    document.getElementById('map').appendChild(target);
    // key event
    document.onkeydown = function(e) {
      if(!isKey) {
        if(e.keyCode == 38) {  //up
          if(dir != 2) {dir = 0; isKey = true;}
        } else if(e.keyCode == 39) {  //right
          if(dir != 1) {dir = 3; isKey = true;}
        } else if(e.keyCode == 40) {  //down
          if(dir != 0) {dir = 2; isKey = true;}
        } else if(e.keyCode == 37) {  //left
          if(dir != 3) {dir = 1; isKey = true;}
        }
      }
    };
    // timer
    timer = setInterval(move, 100);
  </script>
</body>	
check the result

这里用了snake作为一个数组,每个元素是一个div的Element,然后就是游戏结束的条件,有两个,一个是蛇碰到墙壁,一个是蛇碰到自身,主要逻辑就是蛇吃到食物的时候,蛇身要变长,然后食物随机换一个位置,当然不能与蛇身重合。当然游戏的细节比较多的,可以结合代码理解。

这个游戏调了两天,虽然规则很简单,但是细节还是需要花费精力的

如果您觉得此教程不错,想支持一下,您可以通过支付宝扫码给我们一点,不要超过100元哦!
评论请先登录