此篇文章源於前段時間商業有個項目需求,要實現一個比較複雜的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;
2、把畫布掛載到DOM上
app.renderer.resize(512, 512);舞臺和畫布已經創建好,把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