教你用PixiJs實現複雜動畫

2021-02-21 大轉轉FE
前言

此篇文章源於前段時間商業有個項目需求,要實現一個比較複雜的H5交互動畫。那說到動畫常用的技術方案無非是下面幾種:

gif圖和css3動畫屬性顯然只能實現展示型動畫,而通過原生代碼實現交互動畫又是很複雜的,同時還得考慮動畫的兼容性和性能問題。WebGL因為可提供硬體加速渲染,其渲染性能肯定是高於canvas的,但考慮到canvas與WebGL兼容性對比(如下圖所示)及綜合我們的項目要求,最初方案選定了用canvas實現。

canvas兼容性WebGL兼容性

但交互動畫的核心在於用戶交互,用戶交互都是基於事件的。在canvas上繪製的圖形自身不支持DOM事件,只有canvas標籤支持DOM事件監聽,因此還需要對canvas事件進行封裝,實現相對應事件的監聽及處理,還挺複雜的,這時候想要是有個canvas框架就好了,網上去搜索並對比了常用的三款canvas框架fabric.js、pixi.js及Phaser.js如下:

框架canvas功能支持渲染量級事件端fabric.js全svg、canvas輕封裝了canvas標籤監聽事件pcpixi.js全webGL、canvas輕繪製元素上直接支持事件pc、移動、桌面phaser.js全webGL、canvas重繪製元素上直接支持事件pc、移動、桌面

對比發現pixi在框架量級上及渲染上都特別優秀,而且它的api簡單易用,事件操作也很簡單在繪製的對象上可直接操作事件,同時提供有滑鼠和移動端touch事件;而fabric在渲染、事件的靈活性及端的支持上不如pixi;phaser是基於pixi封裝的,在pixi優秀的渲染基礎上又封裝了很多遊戲功能如遊戲鍵盤手柄輸入、聲音支持等,所以phaser更適合做遊戲,它是一款遊戲引擎。

綜合上面的選型分析,PixiJs很適合我們用來做交互動畫及小遊戲。

PixiJs

那PixiJs具體是什麼樣的呢?

官網的介紹總結一下是這樣的:它是一款基於canvas的2D WebGL渲染引擎,可以創建豐富的交互式圖形、動畫和遊戲。pixi的目標是提供一個快速的、輕量級且是兼容所有設備的2D庫,無需了解WebGL就可以讓開發者享受到硬體加速,它默認使用WebGL渲染,但在瀏覽器不支持的情況下可優雅降級成Canvas渲染。同時對繪製內容支持完整的滑鼠和觸摸事件。

其特徵總結起來就是:

支持WebGL渲染,因為能調用GPU渲染,所以渲染性能高支持canvas渲染,當設備不支持WebGL時自動使用canvas渲染,也可以手動選擇canvas渲染豐富的交互事件,支持完整的滑鼠和移動端touch事件

了解了pixi後看它是如何使用的,Pixi的引用很方便

npm i pixi.js
import * as PIXI from "pixi.js"

引入後我們去用pixi創建一個動畫的流程大概是這樣的:

1、創建舞臺、畫布

先解釋下什麼是舞臺,什麼是畫布?

舞臺是你的創作場景中所有可見對象的根容器,我們可以將它看做一個空盒子,我們在舞臺上放的內容都會在畫布上呈現,所有要渲染的對象是只有添加到舞臺中才能被顯示出來的。畫布就是一個渲染區域,把畫布添加進DOM後,就會創建一個canvas標籤,畫布對象會默認選擇WebGL引擎渲染模式。

pixi直接提供了一個應用類PIXI.Application可以自動創建舞臺(stage)和畫布(renderer),如下圖所示:

(1)app.stage就是一個舞臺對象,添加渲染對象到舞臺上直接app.stage.addChild(XXX)就可以了。 

(2)app.renderer是畫布對象,如果你需要在創建canvas標籤之後改變它的背景色,設置app.renderer對象的backgroundColor屬性為一個任何的十六進位顏色即可

app.renderer.backgroundColor = 0xffffff;

如果你想獲取畫布的寬高,直接使用app.renderer.view.width 和app.renderer.view.height即可,同時還可以用畫布的resize方法重新設置畫布的寬高

 app.renderer.autoResize = true;
app.renderer.resize(512, 512);

2、把畫布掛載到DOM上

舞臺和畫布已經創建好,把Pixi應用對象創建出來的HTMLCanvasElement(即app.view)添加到dom上,就可以在瀏覽器上看到一個白色背景的canvas渲染區了,如下圖所示:

 document.getElementById('draw').appendChild(app.view)

3、創建精靈

現在我們已經有了舞臺和畫布,就可以往舞臺上添加圖片,然後在畫布上顯示了。

我們把能放到舞臺上的特殊圖像對象稱為精靈,精靈就是我們能用代碼控制的圖片,你能夠控制他們的位置、大小、層次,用它來產生交互和動畫,是pixi製作動畫的關鍵因子。

pixi有一個精靈類PIXI.Sprite,直接在創建精靈方法中傳入單個圖片、或者雪碧圖、或者一個包含圖像信息的JSON對象都可以創建一個或多個精靈。

但pixi因為用WebGL和GPU去渲染圖像,所以圖像需要轉化成GPU可以處理的形式才行,我們把可以被GPU處理的圖像稱作紋理。一般不能直接在PIXI.Sprite裡直接傳圖片,要傳紋理才行。而怎麼加載圖像並將它轉化成紋理呢?pixi提供了強大的loader對象可以通過loader把上面三種類型(單張、雪碧圖、JSON)圖像資源轉化成紋理資源,如下面代碼所示:

PIXI.loader
  .add(['image1.png']) // 加載圖片
  .load(setup);
// 圖片加載完成時用setup的方法來使用它
function setup() {
  // 生成精靈
  let sprite = new PIXI.Sprite(
    // 圖片轉換成紋理
    PIXI.loader.resources['image1.png'].texture
  );
}

4、將精靈添加到舞臺

已經製作好了精靈,按照上面介紹的舞臺對象操作方法把精靈添加到舞臺上就可以在畫布上顯示圖片了。

app.stage.addChild(sprite)

單個精靈已經創建好了,如果你的動畫場景比較複雜想管理一組圖片,那麼可以用PIXI.Container對象,把一組精靈聚合起來,如果要同時操控這一組精靈,直接操作container對象就可以了,如下圖所示就是創建了2行2列的小鳥精靈,這些精靈都添加到了容器container中且容器在畫布居中旋轉:

代碼如下:

const container = new PIXI.Container();
app.stage.addChild(container);
const birdTexture = PIXI.Texture.fromImage('bird.png');
for (let i = 0; i < 4; i++) {
  const bird = new PIXI.Sprite(birdTexture);
  bird.width = 40
  bird.height = 40
  bird.anchor.set(0.5);
  bird.x = (i % 2) * 40;
  bird.y = Math.floor(i / 2) * 40;
  container.addChild(bird);
}
// 設置container位置
container.x = 300;
container.y = 300;
// 設置container容器原點
container.pivot.x = container.width / 2;
container.pivot.y = container.height / 2;
// 循環旋轉
app.ticker.add((delta) => {
  container.rotation -= 0.01 * delta;
});

一個pixi實例實際上就是一個樹狀結構,由一個root container(app.stage)包含所有的renderable元素,而Container也可以包含其他Container,下圖是pixi實例的樹狀結構:

5、操作精靈

單個精靈或者一組精靈創建完後,就可以控制精靈的位置、大小、層次等進行動畫交互了,Pixi常用的交互事件有:

事件的運用在下面的例子中會有詳細介紹。這五步大概涵蓋了完整動畫的創建流程,下面會用一個有天空背景,滑鼠拖動小鳥在天空舞動的例子介紹下pixi動畫的具體實現。

PixiJs實踐1、搭建舞臺、畫布
  const app = new PIXI.Application({
    width: 600,
    height: 600,
    antialias: true,
    transparent: false,
    resolution: 2,
    autoResize: true,
    backgroundColor: 0xffffff
  })
  const drawing: any = document.getElementById('draw')
  drawing.appendChild(this.app.view)

2、設置藍天背景
PIXI.loader
  .add('sky.png')
  .load(setup)
function setup() {
  let bgSprite = new PIXI.Sprite(PIXI.loader.resources['sky.png'].texture)
  bgSprite.width = 600
  bgSprite.height = 600
  app.stage.addChild(bgSprite);
}

效果圖如下:

3、添加小鳥精靈
let birdSprite = new PIXI.Sprite(PIXI.loader.resources['bird.png'].texture)
birdSprite.width = 80
birdSprite.height = 80
birdSprite.position.set(20, 20) // 設置位置
app.stage.addChild(birdSprite)

效果圖如下:

4、拖拽小鳥舞動
// 給小鳥精靈添加事件
birdSprite
.on('pointerdown', this.onDragStart)
.on('pointermove', this.onDragMove)
.on('pointerup', this.onDragEnd)
.on('pointerupoutside', this.onDragEnd)
//開始拖拽
onDragStart(event) {
  this.dragging = true
  this.data = event.data
  // 滑鼠點擊位置和小鳥位置的偏移量,用於移動計算
  this.diff = { x: event.data.global.x - this.x, y: event.data.global.y - this.y }
}
//拖拽移動中
onDragMove() {
  if (this.dragging) {
    const newPosition = this.data.getLocalPosition(this.parent)
    // 拖拽中保證小鳥不超過背景區域
    this.x = Math.min(Math.max(this.boundary.left || 0, newPosition.x - this.diff.x), this.boundary.right)
    this.y = Math.min(Math.max(this.boundary.top || 0, newPosition.y - this.diff.y), this.boundary.bottom)
  }
}
//拖拽完成,鬆開滑鼠或抬起手指
onDragEnd() {
  if (this.dragging) {
    this.dragging = false
    this.data = null
  }
}

5、總體效果圖

總結

至此怎麼用pixi實現一個交互動畫就講完了,如果動畫場景再設置複雜點,然後加上音頻、加上動效等開發一個酷炫的小遊戲也不在話下呢~,當然pixi不僅僅只有介紹的這些功能,它還支持繪製文本、繪製幾何圖形、支持20多種濾鏡、設置遮罩層及提供動畫屬性等。下圖是對pixi支持功能的一個細節分類:

圖片來自網上

pixi功能很強大,是好多人製作複雜動畫和小遊戲的首選,但學習pixi的中文資料不多,更複雜些的功能需要查看官方英文文檔和研究源碼了解,歡迎大家一起研究、探討pixi的更多更好玩的功能!

參考資料

Pixi官方文檔

pixi_github

相關焦點

  • 【Web動畫】SVG 實現複雜線條動畫
    在上一篇文章中,我們初步實現了一些利用基本圖形就能完成的線條動畫:【Web動畫】SVG 線條動畫入門[1]當然,事物都是朝著熵增焓減的方向發展的,複雜線條也肯定比有序線條要多。所以,很多時候,我們無法人工去畫出一些十分複雜動畫的線條,這個時候,就要藉助我們前端的好幫手 PS 和 AI:好了,假定我們現在要製作下圖 GIF 這樣的一個 loading 圖:
  • 十分鐘教你用svg做出精美的動畫!
    前言經常在Codepen上看到大俠們用SVG畫出不可思議的動畫,我一直很好奇他們是怎麼運作的,總覺得這需要對SVG有足夠透徹的了解,並且自己畫出那些SVG圖案,才有辦法讓他動起來。但其實不然,今天教大家一個簡單的小技巧,讓你快速實現一個svg動畫!
  • 用css3實現背景即背景動畫(高級附源碼)
    本文轉載自【微信公眾號:趣談前端,ID:beautifulFront】經微信公眾號授權轉載,如需轉載與原文作者聯繫我們傳統的前端更多的是用javascript實現各種複雜動畫,自從有了Css3 transition和animation以來,前端開發在動畫這一塊有了更高的自由度和格局,對動畫的開發也越來越容易。
  • 十分鐘教你用 svg 做出精美的動畫!
    前言經常在Codepen上看到大俠們用 SVG 畫出不可思議的動畫,我一直很好奇他們是怎麼運作的,總覺得這需要對 SVG 有足夠透徹的了解,並且自己畫出那些 SVG 圖案,才有辦法讓他動起來。但其實不然,今天教大家一個簡單的小技巧,讓你快速實現一個 svg 動畫!
  • 《當代動畫》| 兒童動畫的「教」與「樂」——評《巧虎》系列動畫
    這正是巧虎系列動畫在寓教於樂過程中對「教」的有效呈現。在「寓教於樂」這一觀念的指引下,「教」為「道」,「樂」為「器」。有形而上的「道」為正確指引,還需有形而下的「器」去有效實現,「樂」則是巧虎實現教育之「道」的利器。面對低齡兒童,如何用他們可接受的講述方式來實現「文以載道」是創作者需要面對的另一個難題,《可愛巧虎島》也為我們提供了一個可供分析的成功案例。
  • 用pygame實現動畫效果
    養馬時覺得那個3D效果不卡頓實現好像有點厲害,看到想到那麼就來分享一期用pygame做出一個動畫效果吧,我只會二維的不是3D啦。
  • Motion 動畫基礎丨手把手教你製作電影片頭
    05遮罩功能(運用)簡單理解,你也可以認為【遮罩功能】就是平面設計中的蒙版功能。這裡仍然用慄子來說明:當然,你還可以在複製器上疊加【資源庫】中的其它功能一起使用,以及配合【關鍵幀】實現相關動畫效果。06複製器(運用)你沒有猜錯,複製器的作用就是把一個複製出多個:畫一個圓點;點擊菜單欄中的【對象】-【複製】(或用快捷鍵);調整相關參數即可。
  • 教你用一張圖片來做動畫,提高你的「視效元認知能力「吧
    所以今天我就蹭這個熱點,在教學中引入元認知能力,教大家如何就用一張圖片來做動畫!先看下一張圖片完成的最終效果。 這麼妖的舞蹈動畫,你不想學一下嗎?雖說內容涉及角色動畫,但實際操作簡單到令人髮指的地步,不需要任何外部插件,只需要AE自帶的圖釘工具即可,只要音樂和動作構想構思得當,沒有任何角色動畫經驗的同學都可以做出相當有趣的效果。但高手們也別小瞧,AE自帶的圖釘用好了也挺不錯,關鍵是要用對地方,用最小的力打出效果。(話說AE的圖釘工具你真的有研究過嗎?)
  • 直播App中Android酷炫禮物動畫實現方案(上篇)
    在當下移動直播火爆的年代,如果你曾經使用過移動端直播應用,相信會被裡面那令人驚嘆的禮物動畫效果迷住,比如像下面這樣的效果。
  • 動畫師工作中都用什麼軟體? | 動畫人說
    遊戲特效的實現相對簡單,二維和2.5D遊戲採用打包序列幀的方式,只用PS和3dMax就可以搞定,大型三維遊戲都是在引擎中完成特效解算。 二維動畫特效用的比較多的還是AE和PS,PS用來製作特效素材,AE用來編輯素材,合成沒有素材的部分,追蹤特效目標。
  • 日本動畫的角色設計,一部複雜而有趣的演化史
    上期我們分享過的內容「你名」與「國家隊」的角色設計師想跟你聊聊人設那些事 就是在討論這件事情。今天,我們帶大家來回顧一下日本動畫角色設計的發展歷程吧!大友克洋的獨特設計推動了動畫效果的展現,動畫裡難以置信的細節也增強了影片的效果。大友克洋的角色面部設計十分複雜,得以讓角色表達出豐富的情感。
  • 這10種好用的PPT動畫效果,讓小白也能做出炫酷動畫!(PPT教程)
    手把手教你製作「動態」樣機,驚豔全場!【PPT教程】》城市汽車素材在PPT製作PPT的過程中經常使用到,但很多時候,靜態的城市汽車圖片並不能將城市的變化一目了然地展示給觀眾,更不能留下深刻的印象。為了使城市汽車等景觀能給觀眾帶去更直觀的感受,我們可以選擇添加動畫。
  • lottie-web 動畫實現原理
    設計師使用 AE 製作動畫。通過 Lottie 提供的 AE 插件 Bodymovin 把動畫導出 JSON 數據文件。加載 Lottie 庫結合 JSON 文件和下面幾行代碼就可以實現一個 Lottie 動畫。<!
  • 《哆啦 A 夢》的這 29 個道具,現在已經實現了,而且你每天都在用
    沒有「知乎日報」陪伴的夜晚,有沒有覺得少了點什麼~因為想要陪伴你們度過每一個夜晚,知乎君要教你們一個快速找到「知乎日報」的方法👇設置完成後,就可以每天在「訂閱號」中快速找到知乎君啦~知友:加劉景長(7600+ 贊同,動畫話題優秀回答者)從漫畫第一話開始 短篇集「全 1-45 卷」。用的版本是吉林美術出版社的中文版。第 1 卷 古董大戰
  • 【動漫】日本動畫的角色設計,一部複雜而有趣的演化史
    大友克洋的獨特設計推動了動畫效果的展現,動畫裡難以置信的細節也增強了影片的效果。大友克洋的角色面部設計十分複雜,得以讓角色表達出豐富的情感。她的骨骼、肌肉和比例都是精確的。實現了震撼的效果。上世紀90年代的另一面則是對80年代的延續。動畫《聖天空戰記》在《超時空要塞》明亮浮華的風格上,加入一些必要的複雜性來打造得更精緻。它採用了老派的設計。人物設計也很複雜。給人一種日式角色扮演遊戲的感覺。該片從上世紀80年代的寫實主義轉變到非寫實設計:在頭髮中加入反射光,成為當時的一種潮流。
  • SVG 實現動態模糊動畫效果
    動態模糊是一種廣泛使用於動態影像和動畫的技術,它能使動作看起來更加平滑自然。 那麼,怎麼才能產生這種效果呢?記住,此模糊濾鏡只支持X或Y方向上的方向模糊,不能任意角度,因此你需要相應地規劃好動畫效果。還有,改變模糊濾鏡會影響與其相關聯的所有對象,因此我們需要為將應用此效果的每個對象添加一個新的元素。
  • 一起玩定格———9招教你拍好定格動畫
    那麼在本文裡,我將和大家分享我在創作定格動畫故事短片「Sammy's Measle」中的一些過程方法,教大家如何拍好定格動畫。     下面就是我給大家的幾點定格動畫拍攝建議:1、想的複雜,做得簡單在構建一些場景時(比如本文視頻裡面「莉莉」給「薩米」動「麻疹」手術的場景),我們可能用到一座城市,但實際上,一個小房間就足夠了;我們可能用到一間屋子,但在實際拍攝中,一個手術對象或者一把手術刀就可以了。
  • 【Unity Shader- UV動畫原理及簡易實現
    時間變量在我們寫遊戲邏輯時,涉及到隨時間移動或旋轉這種動作時,我們一般都會使用 Time.time 這個變量,同樣,在 Unity Shader 中,我們需要實現一些動畫時,也需要時間變量。下面我們使用它來實現一些效果二. 序列幀動畫序列幀動畫是一種十分常見的動畫,它就像播放電影一樣,把一連串的關鍵幀圖像以一定的速度播放出來,看起來就是一段連續的動畫。而它的優缺點也十分明顯:本文以製作一個火焰效果為例。
  • 日本中二少年教你用姿勢估計把自己變成3D人物,動作實時同步,iOS上也能實現
    source=post_pagee74d7d347c2--青柳君嘗試過多種實現方式,包括WindowsML,ML.Net,Onnx Runtime等,但最終選擇了OpenCVSharp,也就是OpenCV模型導入功能,在Unity中加載和執行Onnx,因為OpenCVSharp在Unity和.Net環境中可以用相同的方式處理,圖像也不會被轉換為Mat格式。
  • 使用jQuery的animate()+CSS樣式實現動畫效果及stop()停止動畫
    :第1個參數params必須存在,用於設置能夠形成動畫效果的CSS屬性,可見動畫效果是CSS樣式實現的。03第3節:animate()方法控制多個樣式動畫我們知道,animate()方法產生的動畫是由CSS樣式形成的,一個CSS樣式是一個動畫效果,那麼多個CSS樣式就是多個動畫效果了,此時,就可以實現更豐富的動畫效果。