井井客

搜索

canvas完成贪吃蛇小游戏

以前看过别人做过类似的小游戏代码,所以自己尝试用canvas画了一下,自我感觉良好~

canvas完成贪吃蛇小游戏

整体代码如下,代码里面有注释,仔细看应该能看懂。下面我会再做一个解释,大概每个函数是什么意思的。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>demo</title>
    <style>
      html,body,div,p,span,canvas {
        padding: 0;
        margin: 0;
        border: 0;
      }
      .warp {
        width: 600px;
        height: 400px;
        margin: 50px auto 0;
        border: 5px solid #ccc;
        background: linear-gradient(45deg,#eee 25%,transparent 0,transparent 75%,#eee 0),
                    linear-gradient(45deg,#eee 26%,transparent 0,transparent 74%,#eee 0);
          background-size: 40px 40px;
          background-position: 0 0,20px 20px;
      }
      .start-btn {
        display: block;
        width: 200px;
        height: 36px;
        margin:20px auto 0;
      }
      
    </style>
  </head>
  <body>
    <div class="warp">
      <canvas width="600" height="400" id="canvas"></canvas>
    </div>
    <button class="start-btn" id="submit">点击开始</button>
    
    <script>
      // 获取开始按钮并且点击开始执行动画
      var btn = document.getElementById('submit');
      btn.addEventListener('click',times,false)
      
      // 获取画布
      var canvas = document.getElementById('canvas');
      var ctx = canvas.getContext('2d');
      var bodyArr = [],
        randomX,
        randomY,
        path = 'right',  // 当前方向
        temp = 'right', // 暂时记录的方向
        speed = 300,   // 初始蛇移动速度
        spacing = 0.4;  // 每次吃完食物移动速度递减(值越小速度越快)
      
      // 初始化默认蛇身
      function defaultSnake(value){
        // 获取位置点
        while(value > 0){
          value--;
          bodyArr.push([value*20,0])
        }
        drawSnake();
      }
      defaultSnake(5);
      
      // canvas绘制蛇身
      function drawSnake(){
        for(var i = 0; i < bodyArr.length; i++){
          ctx.beginPath();
          // 判断头部颜色
          if(i === 0){
            ctx.fillStyle='red';
          }else{
            ctx.fillStyle='green';
          }
          ctx.fillRect(bodyArr[i][0],bodyArr[i][1],20,20)
          ctx.fill();
          ctx.closePath();
        }
      }
      
      // canvas绘制食物
      function drawFood(){
        // 获取随机位置
        function getRandom(){
          // 随机位置计算
          randomX = parseInt(29 * Math.random())*20;
          randomY = parseInt(19 * Math.random())*20;
          // 判断不与身体重复(重复时刷新随机食物位置)
          for(var i=0; i < bodyArr.length; i++){
            if(randomX === bodyArr[i][0] && randomY === bodyArr[i][1]){
              getRandom();
            }
          }
        }
        getRandom()
        // 绘制食物点
        ctx.beginPath();
        ctx.arc(randomX+10,randomY+10,10,0,2*Math.PI);
        ctx.fillStyle='red';
        ctx.fill();
        ctx.closePath();
      }
      drawFood();
      
      // 执行(定时器)
      function times(){
        setTimeout(function(){
          startForward()
        },speed)
      }
      
      // 开始前进
      function startForward(){
        // 获取当前头部位置
        var posX = bodyArr[0][0], posY = bodyArr[0][1];
        // 接下来的位置(先更新方向)
        path = temp;
        if(path === 'left'){
          posX -= 20;
        }else if(path === 'top'){
          posY -= 20;
        }else if(path === 'right'){
          posX += 20;
        }else if(path === 'bottom'){
          posY += 20;
        }
        // 判断身体是否撞到墙了
        if(posX < 0 || posX >= 600 || posY < 0 || posY >=400){
          alert('糟了,撞到墙了。(game over)')
          return false;
        }
        // 判断是否撞到自己了
        for(var i = 0; i < bodyArr.length; i++){
          if(bodyArr[i][0] === posX && bodyArr[i][1] === posY){
            alert('糟了,撞到自己了。(game over)')
            return false;
          }
        }
        // 将新头部放入蛇身数组中并绘制身体
        bodyArr.unshift([posX,posY])
        drawSnake()
        // 判断是否吃到食物(吃到食物则重新绘制一个食物并提升速度,否则减掉尾巴)
        if(posX === randomX && posY === randomY){
          drawFood();
          speed -= spacing;
        }else{
          ctx.clearRect(bodyArr[bodyArr.length-1][0],bodyArr[bodyArr.length-1][1],20,20)
          bodyArr.splice(bodyArr.length-1,1)
        }
        // 继续走起来
        times();
      }
      
      // 监听键盘事件
      window.addEventListener('keydown',function(e){
        var keyValue = e.keyCode;
        // 跟据按键判断接下来的方向(用temp暂做记录,防止一个移动的时间间隔内输入多次方向而为正在移动的方向冲突)
        if(keyValue === 37 && path !== 'right'){
          temp = 'left';
        }else if(keyValue === 38 && path !== 'bottom'){
          temp = 'top';
        }else if(keyValue === 39 && path !== 'left'){
          temp = 'right';
        }else if(keyValue === 40 && path !== 'top'){
          temp = 'bottom';
        }
      },false)
    </script>
  </body>
</html>

一百多行代码,需要稍微花点点时间了。

先说说bodyArr数组吧,这个是蛇身体的每一个方块的组成位置点,很重要的一个东西。初始时会从头(红色)到尾开始记录五组子数组,子数组中存放X轴Y轴初始位置,像这样:[[80,0],[60,0],[40,0],[20,0],[0,0]]。

接下来就是蛇运动的轨迹了,默认是向右,而我给了两个记录方向的值:path和temp。path是正在进行的方向,而temp则是监听键盘事件时,当我们按“上下左向”这四个键时记录的方向值,因为考虑到一个移动间隔内可能按了多次方向键,所以给了一个判断,并在最后当蛇身移动时将temp赋值给path。

绘制食物也是同样的,任意位置,但是会先判断一下是否与蛇身的数组坐标有重叠,如果重叠的话就另外随机一个位置。

而走“times”定时器,其实就是根据speed速度来执行startForward,主要还是分析startForward函数比较重要。

startForward里面当然注释也没有少,我的想法就是根据方向键(没有按方向键就是初始默认方向)来进行。同样用到了bodyArr数组,向数组的头部添加接下来的身体位置,然后去判断这个身体位置是否撞墙或者撞到自己,没有的话就开始绘画了,绘画完成之后去判断是否吃到食物,吃到食物就会调整下一次的速度并且重新随机食物位置,否则就正常的去掉当前蛇尾(因为新画了一个蛇头了,所以蛇尾要去一格)。最后继续执行times,完成一次次循环。这里面只有撞到了才会有return false退出,否则就会一直执行的。

上次纯粹是我自己的分析,代码有不好的地方欢迎拍砖呢~

文章TAG:JS,canvas

作者:井井客原创来源:原创
本文标题:canvas完成贪吃蛇小游戏
本文链接:/c/21286.html

上一篇:原生JS实现拖动拼图验证
下一篇:CSS3+JQ完成元素进场动画效果

文章分类

相关阅读

随便看看