iT邦幫忙

2021 iThome 鐵人賽

DAY 23
0
Modern Web

這個網站也太嗨!30 個網頁動態提案系列 第 25

#22-掰惹Gif!用Sprite雪碧圖做動畫! (CSS & Canvas)

  • 分享至 

  • xImage
  •  

有時候會碰到網站要放GIF動畫,但GIF大小動輒幾M起跳,
造成網頁Loading慢、圖片邊緣鋸齒,支援顏色也不多,不太完美。

這時候 sprite 雪碧圖就登場啦~
其實雪碧圖就是將動畫拆解成一張一張圖片,
再用CSS animation steps的做法(就跟之前換字特效是一樣的!)
讓他可以一張一張播放。

當然雪碧圖也可以用在組合多張圖片,讓網路只要載入一次,
不過這個應用就不會在這邊贅述囉~(我也還不太會

今天就來用

1.CSS Animation
2.Canvas + JS

兩種方法來做sprite動畫!
當然這邊就要 設計師請支援動畫
但我一個人兼撞鐘,眼睛就忍耐一下!


1. CSS Animation

很粗糙地先做了五個連續圖片~讓雲和燈光可以動起來。

直覺可能會想到要一張圖片一張圖片換,
但這樣做會造成缺點:多個HTTPS的請求、會造成檔案閃爍不利於管理等等。

雪碧圖搭配移動圖片位置的方法換圖片,
只要一張圖片搞定啦!

來看成品:

直接上code:

//css
.hero {
            width: 648px;
            height: 572px;
            background: url(./city-sprite.png);
            background-size: auto 100%;
            animation: bg steps(4) 5s infinite;//移動4次
        }

        @keyframes bg {
            to {
                background-position: -2592px 0; //算好移動到最後一張的寬度
            }

        }

動態成果這邊請


2.Canvas + JS

Canvas的話,就是不斷擦掉畫面,
requestAnimationFrame(animate);
不斷呼叫自己重繪圖片到Canvas上~

上圖片~

我們一樣要算出每格的距離,然後讓Canvs去吃那格的座標~
來看看成果~

直接看code說明吧~

//JS
//canvas 起手式
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 600;
canvas.height = 600;

//canvas 放圖片起手式
const spriteSheet = new Image();
spriteSheet.src="./test.png";

//異步操作,讓圖片載入後才執行
spriteSheet.onload = loadImage;

//spriteSheet的寬高除以圖片有幾格,就是一格的寬度和高度
//這裡有五格,但只有一行
let cols = 5;
let rows = 1;
let spriteWidth = 1147 / cols; //圖片寬度除格數
let spriteHeight = 557 / rows; //圖片高度除格數

//圖片切割的起始點
let srcX =0;
let srcY =0;

//這邊是控制速度用的~
let totalFrames = 5;
let currentFrame = 0;
let frameDrawn =0;

function animate(){
  //先清掉畫布
  ctx.clearRect(0,0,canvas.width, canvas.height);
  
  
  //這邊用於數的概念來看現在是第幾格了~等到第五格上限時,currentFrame又回從一開始~
  currentFrame = currentFrame % totalFrames;
  
  //現在這個是第幾格 
  srcX = currentFrame * spriteWidth;
  
	//畫畫囉參數分別是:1. 讀取圖片 2.圖片要切割的x位置 3.切割的y位置
	//4.切割多寬 5.切割多長 6.要放在canvas的x位置 7.要放在canvas的y位置
	//8.canvas貼上的地方要放多寬 9.canvas貼上的地方要要放多長
  ctx.drawImage(spriteSheet, srcX, srcY,spriteWidth, spriteHeight,
 0,0 ,spriteWidth, spriteHeight);
  
  //就是這邊控制速度
  //等於是這個animate被呼叫10次以後,currentFrame才會前進一格,以控制速度
  frameDrawn++;
  if(frameDrawn>=10){
    currentFrame++;
    frameDrawn=0;
  }

  //重複呼叫自己
  requestAnimationFrame(animate);
}

function loadImage(){
  animate();
}

// ref: https://www.youtube.com/watch?v=MHGgVlrlkYc&t=907s

成果看這邊


以上!

完成了我們的小人物動畫囉!
明天就來利用這個小人物來做互動小遊戲~(命名:都市老妹生存記
敬請期待 XD
Canvas的sprite我主要是參考這個影片

有錯或是有任何建議歡迎批評指教!


參考文章
幀動畫的多種實現方式與效能對比(推薦閱讀!)
https://www.gushiciku.cn/pl/2RQ8/zh-tw

CSS3动画之逐帧动画
https://jelly.jd.com/article/6006b1035b6c6a01506c87a7


上一篇
#21-用Canvas做科技感的動態球!(+什麼時候該用CSS/SVG/Canvas?)
下一篇
#23-用Canvas做Google恐龍遊戲(都市老妹生存記!能擊退經痛加班和渣男嗎?)
系列文
這個網站也太嗨!30 個網頁動態提案33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言