canvas實現 行人 走路的動畫(完整實現)

先看下效果,然後再說如何實現,最終效果如下:



我們知道動畫其實是不同的圖片循環替換,造成視覺上圖片在動。

我們製作這個動畫的素材如下:



從右至左,就是一個人的行走的所有動作,擡腿,邁步,腳落下,另一隻腳邁步,然後循環如此。

我們將圖中的五個動作圖截出來,循環播放,效果就如下:



可以看出,這是一個原地踏步的動作,如果給圖片加上位移,就是行走的效果。

這裏講一個知識點:Css spirit

我們剛剛已經講了,動畫是5個動作的合成,應該有5張圖片,現在我們將5張圖片放在一張圖片裏,需要時截取圖片的部分,就可以獲取所需實際圖片了。

這麼做的原因是:

在實際的web應用中,頁面上可能有上百張甚至好幾百張圖片,如果每張圖片都是單獨的,就需要建立幾百個http連接,每個連接的建立都需要耗費一定時間,幾個個連接的時間浪費是非常大的。我們可以把多張圖片合成到一張大的圖片中,然後通過CSS中的背景定位等技術,把背景定位到實際的圖片位置,就可以得到所需圖片了(canvas也可以利用這種思想)。這樣可以節省大量的連接建立時間。是前端優化的一部分。

當然,現在我們使用各種工具構建前端工程,打包時會將很多小圖標直接轉成BASE64編碼。
(例如,webpack, 使用url-loader插件,設置limit,打包時,將所有小於limit的圖片進行BASE64編碼)。

源碼如下:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>walk</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
  <canvas width="500" height="400" id="canvas" style="margin-top: 200px;"></canvas>
  <img src="../asserts/walk.jpg" style="display: none;" id="walk">
  <script>
    //獲取圖片
    let walkImg = document.getElementById('walk'); 
    //獲取繪圖上下文
    let ctx = document.getElementById('canvas').getContext('2d');
    
    //這個參數是用來標識,現在改用哪個用作,初始值是4,圖片最有邊的動作,開始行走的動作。取值是4~0,循環
    let index = 4;

    //行走位置
    let position = 0;
    
    //行走的方向,true代表從左至右, false代表從右至左
    let direct = true;

    //定時器,確保圖片加載完成再繪製動畫
    let timer = null;
    //確保圖片加載完成再繪製到
    if (!walkImg.complete) {
      timer = setInterval(() => {
        //兩張圖片加載完成
        if (walkImg.complete) {
          //清除定時器
          clearInterval(timer);
          timer = null;
          //繪製
          drawAll();
        }
      }, 200);
    } else {
      drawAll();
    }

    function drawAll() {
      //清除原來的圖層
      ctx.clearRect(0, 0, 500, 400);
      //畫腳下的線,當做地面
      addLawn();
      //添加初始動作
      addWalk();
      //使用定時器,不斷重繪畫面,形成動畫
      setInterval(() => {
        ctx.clearRect(0, 0, 500, 400);
        addLawn();
        addWalk();
      }, 150);
    }

    //繪製線段,當做地面
     function addLawn() {
      ctx.save();
      ctx.beginPath();
      ctx.strokeStyle = 'green';
      ctx.lineWidth = 3;
      ctx.moveTo(0, 112);
      ctx.lineTo(500, 112);
      ctx.stroke();
      ctx.closePath();
      ctx.restore();
     }

     //添加不同位置圖片
     function addWalk() {
      ctx.save();
      /**
       * 行走分爲兩個方向,從左至右和從右至左,我們分別說明
       * 1、從右至左:圖片資源的5個動作就是從右至左方向走的,所以從右至左行走時,無需
       * 額外處理圖片,只需將對應動作放在規定位置即可。
       * 
       * 2、從左至右:這與圖片資源的工作方向相反,所以,提取動作後,需要翻轉(利用scale進行翻轉)。
       * */

      if (direct) {
        //從左至右方向,scale(-1, 1)先翻轉畫布,然後利用translate修改座標系原點
        ctx.scale(-1, 1);
        ctx.translate(-position-55,0);
        position += 6;
      } else {
        //從右至左方向,無需翻轉,只需修改座標系原點,然後將圖片直接從原點處放置即可
        ctx.translate(position,0);
        position -= 6;
      }
      //根據index不同,從圖片資源中提取不同的行走動作
      switch(index) {
        case 0:
          ctx.drawImage(walkImg, 0, 0, 55, 110, 0, 0, 55, 110);
          break;
        case 1:
          ctx.drawImage(walkImg, 75, 0, 55, 110, 0, 0, 55, 110);
          break;
        case 2:
          ctx.drawImage(walkImg, 145, 0, 55, 110, 0, 0, 55, 110);
          break;
        case 3:
          ctx.drawImage(walkImg, 220, 0, 55, 110, 0, 0, 55, 110);
          break;
        case 4:
          ctx.drawImage(walkImg, 270, 0, 55, 110, 0, 0, 55, 110);
          break;
      }
      
      //圖片位置,走到這返回
      if (position > 440) {
        direct = false;
      } 
      if (position < 10) {
        direct = true;
      }

      index -=1 ;
      if (index < 0) {
        index = 4;
      }
      ctx.restore();
    }
  </script>
</body>
</html>

有疑問歡迎留言給我,或發送郵件至[email protected],歡迎大家討論交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章