PixiJS是一個輕量級的2D渲染引擎,它能自動偵測使用WebGL仍是Canvas來建立圖形。這個庫常常被用來製做HTML5遊戲以及有複雜交互的H5活動頁。javascript
注意:本文使用pixi最新的v5版本,同時使用Parcel進行模塊化打包html
pixi.js
v5版本默認使用webgl渲染,若是但願能夠回退到canvas,須要使用pixi.js-legacy
,詳情見issue前端
項目初始化java
mkdir learn-pixi cd learn-pixi npm init -y 複製代碼
安裝依賴git
npm i pixi.js -save
npm i parcel-bundler -save-dev
複製代碼
根目錄建立index.html
github
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>learn-pixi</title> </head> <body> <script src="./src/index.js"></script> </body> </html> 複製代碼
根目錄建立src
目錄,新建src/index.js
web
alert('pixi'); 複製代碼
修改package.json
npm
"scripts": { "dev": "parcel index.html -p 8080", "build": "parcel build index.html" } 複製代碼
運行npm run dev
,訪問 http://localhost:8080/ 便可看到效果json
index.js
canvas
import { Application } from 'pixi.js'; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); // app.view就是個canvas元素,掛載到頁面上 document.body.appendChild(app.view); 複製代碼
頁面上就出現了一個300*300的藍色矩形,矩形是由pixi.js建立的canvas渲染的。
咱們能夠繼續建立新的圖形,而後渲染到canvas裏
import { Application, Graphics } from 'pixi.js'; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); document.body.appendChild(app.view); // 建立一個半徑爲32px的圓 const circle = new Graphics(); circle.beginFill(0xfb6a8f); circle.drawCircle(0, 0, 32); circle.endFill(); circle.x = 130; circle.y = 130; // 添加到app.stage裏,從而能夠渲染出來 app.stage.addChild(circle); 複製代碼
咱們還能夠渲染圖片
import { Application, Sprite } from 'pixi.js'; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); document.body.appendChild(app.view); // 建立一個圖片精靈 const avatar = new Sprite.from('http://anata.me/img/avatar.jpg'); // 圖片寬高縮放0.5 avatar.scale.set(0.5, 0.5); app.stage.addChild(avatar); 複製代碼
咱們讓這個圖片精靈變得能夠交互:點擊圖片後,圖片透明度變成0.5
const avatar = new Sprite.from('http://anata.me/img/avatar.jpg'); avatar.scale.set(0.5, 0.5); // 居中展現 avatar.x = 100; avatar.y = 100; // 可交互 avatar.interactive = true; // 監聽事件 avatar.on('click', () => { // 透明度 avatar.alpha= 0.5; }) app.stage.addChild(avatar); 複製代碼
咱們還能讓圖片一直旋轉
const avatar = new Sprite.from('http://anata.me/img/avatar.jpg'); avatar.scale.set(0.5, 0.5); avatar.x = 150; avatar.y = 150; // 修改旋轉中心爲圖片中心 avatar.anchor.set(0.5, 0.5) app.stage.addChild(avatar); app.ticker.add(() => { // 每秒調用該方法60次(60幀動畫) avatar.rotation += 0.01; }) 複製代碼
pixi
有幾個重要的Class:
const app = new Application({ width: 300, height: 300 }); 複製代碼
Application
是pixi提供的一個工具方法,它能自動建立renderer,ticker 和container,咱們一般使用該方法快速建立應用。
app.stage
是一個Container
的實例,做爲最底層的舞臺(stage),全部要渲染的圖形都應放在它的內部
const app = new Application({ width: 300, height: 300 }); // 添加不一樣的圖形 app.stage.addChild(circle1); app.stage.addChild(circle2); 複製代碼
咱們也能夠建立本身的Container
,自定義的Container一般用來分組
import { Application, Container, Graphics } from 'pixi.js'; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); // 自定義Container const myContainer = new Container(); // 相對於根節點偏移 myContainer.position.set(40, 40); let rectangle = new Graphics(); rectangle.beginFill(0x000000); rectangle.drawRect(0, 0, 64, 64); rectangle.endFill(); let rectangle2 = new Graphics(); rectangle2.beginFill(0xFFFFFF); rectangle2.drawRect(0, 0, 64, 64); rectangle2.endFill(); // 相對於自定義Container偏移 rectangle2.position.set(20, 20); // 兩個圖形加到自定義Container裏 myContainer.addChild(rectangle); myContainer.addChild(rectangle2); // 自定義Container最後須要添加到app.stage app.stage.addChild(myContainer); document.body.appendChild(app.view); 複製代碼
分組的好處在於,修改container的屬性,位於其中的子節點,都會受到影響。好比上面的例子,咱們把rectangle
和rectangle2
分到了同一個組裏,若是但願同時隱藏這兩個元素,只需修改它們父級container的透明度便可。
// 父級透明,則子級也透明 myContainer.alpha = 0; 複製代碼
一種常見的作法是,咱們建立一個最頂層的rootContainer
,以後全部的內容,都添加到rootContainer
裏。而rootContainer
做爲頂級元素,能夠進行一些縮放來適配不一樣的分辨率:
const rootContainer = new Container(); app.stage.addChild(rootContainer); // 相對於設計稿750px進行縮放(豎屏狀態) const screenScaleRito = window.innerWidth / 750; // 橫屏則用innerHeight rootContainer.scale.set(screenScaleRito, screenScaleRito); 複製代碼
這種方法相似咱們前端的rem佈局
app.renderer
是一個Renderer
的實例,若是你但願從新渲染頁面,就須要使用它
// 把畫布從新渲染爲500*500大小 app.renderer.resize(500, 500); // 渲染一個容器 const container = new Container(); app.renderer.render(container); 複製代碼
Sprite精靈,你能夠把它當作普通的矢量圖形,只不過它是根據圖片渲染出來的。
const avatar = new Sprite.from('http://anata.me/img/avatar.jpg'); // 和普通的圖形同樣能夠設置各類屬性 avatar.width = 100; avatar.height = 200; avatar.position.set(20, 30); avatar.scale.set(2, 2); 複製代碼
加載圖片一般須要耗費必定的時間,所以咱們經常使用Loader
來預加載圖片,當圖片所有加載成功後,才渲染出來。
import { Application, Sprite, Loader } from 'pixi.js'; // Loader.shared內置的單例loader const loader = Loader.shared; // 也可使用自定義的loader const loader = new Loader(); const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); document.body.appendChild(app.view); loader .add('bili', 'http://pic.deepred5.com/bilibili.jpg') .add('avatar', 'http://anata.me/img/avatar.jpg') .load(setup) // 監聽加載事件 loader.onProgress.add((loader) => { console.log(loader.progress); }); function setup() { const bili = new Sprite( loader.resources["bili"].texture ); bili.width = 50; bili.height = 50; const avatar = new Sprite( loader.resources["avatar"].texture ); avatar.width = 50; avatar.height = 50; avatar.position.set(50, 50); app.stage.addChild(bili); app.stage.addChild(avatar); } 複製代碼
經過add
方法添加須要加載的圖片,全部圖片加載完成後,load
方法會調用傳入的setup
回調函數,這時就能夠把圖片精靈加入到app.stage
裏。onProgress
事件能夠監聽加載的進度,經過這個方法,能夠很方便的製做進度條動畫。
前端有時會把多張圖片合併成一張圖片,經過設置background-position
來顯示不一樣的圖片。pixi.js
也有相似的技術,咱們能夠利用Texture Packer軟件,把多張圖片合併成一張圖片,合併的同時,軟件會生成一份json
配置文件,記錄了每張圖片的相對位置。
具體教程見這裏
import { Application, Container, Sprite, Graphics, Loader, Spritesheet } from 'pixi.js'; // myjson記錄了每張圖片的相對位置 import myjosn from './assets/treasureHunter.json'; // mypng裏面有多張圖片 import mypng from './assets/treasureHunter.png'; const loader = Loader.shared; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); document.body.appendChild(app.view); loader .add('mypng', mypng) .load(setup) function setup() { const texture = loader.resources["mypng"].texture.baseTexture; const sheet = new Spritesheet(texture, myjosn); sheet.parse((textures) => { // mypng裏面的一張叫treasure.png的圖片 const treasure = new Sprite(textures["treasure.png"]); treasure.position.set(0, 0); // mypng裏面的一張叫blob.png的圖片 const blob = new Sprite(textures["blob.png"]); blob.position.set(100, 100); app.stage.addChild(treasure); app.stage.addChild(blob); }); } 複製代碼
Ticker
有點相似前端的requestAnimationFrame
,當瀏覽器的顯示頻率刷新的時候,此函數會被執行,所以經常用來製做動畫。
app.ticker
就是一個Ticker
實例。
import { Application, Sprite, Loader } from 'pixi.js'; const loader = Loader.shared; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); document.body.appendChild(app.view); loader .add('bili', 'http://pic.deepred5.com/bilibili.jpg') .load(setup) function setup() { const bili = new Sprite( loader.resources["bili"].texture ); bili.width = 50; bili.height = 50; app.stage.addChild(bili); app.ticker.add(() => { if (bili.x <= 200) { bili.x += 1; } }) } 複製代碼
咱們也可使用requestAnimationFrame
實現這個效果
function setup() { const bili = new Sprite( loader.resources["bili"].texture ); bili.width = 50; bili.height = 50; app.stage.addChild(bili); function move() { if (bili.x <= 200) { bili.x += 1; requestAnimationFrame(move) } } requestAnimationFrame(move) } 複製代碼
Ticker
能夠實現簡單的動畫,但若是咱們但願實現一些複雜效果,則須要本身編寫不少代碼,這時就能夠選擇一個兼容pixi
的動畫庫。市面上比較常見的動畫庫有:Tween.js,TweenMax,這裏咱們使用TweenMax
來演示效果。
安裝動畫庫
npm i gsap
複製代碼
import { Application, Sprite, Loader } from 'pixi.js'; import { TweenMax } from 'gsap/all'; const loader = Loader.shared; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); document.body.appendChild(app.view); loader .add('bili', 'http://pic.deepred5.com/bilibili.jpg') .load(setup) function setup() { const bili = new Sprite( loader.resources["bili"].texture ); bili.width = 50; bili.height = 50; app.stage.addChild(bili); // 1s內x和y軸移動100 TweenMax.to(bili, 1, { x: 100, y: 100 }); } 複製代碼
TweenMax
還提供了一個PixiPlugin,能夠一次修改多個pixi屬性
import { Application, Sprite, Loader } from 'pixi.js'; import * as PIXI from 'pixi.js'; import gsap, { TweenMax, PixiPlugin } from 'gsap/all'; // 註冊插件 gsap.registerPlugin(PixiPlugin); PixiPlugin.registerPIXI(PIXI); const loader = Loader.shared; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); document.body.appendChild(app.view); loader .add('bili', 'http://pic.deepred5.com/bilibili.jpg') .load(setup) function setup() { const bili = new Sprite( loader.resources["bili"].texture ); bili.width = 50; bili.height = 50; app.stage.addChild(bili); // 一次修改多個屬性 TweenMax.to(bili, 1, { pixi: { scaleX: 1.2, scaleY: 1.2, skewX: 10, rotation: 20 } }); } 複製代碼
咱們一般使用Pixi提供的Application
方法來建立一個應用,它能自動建立renderer,ticker 和container。但其實,咱們能夠本身來建立這些對象。
import { Container, Renderer, Sprite, Loader, Ticker } from 'pixi.js'; import { TweenMax } from 'gsap/all'; // 自定義render const renderer = new Renderer({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); // 自定義container const stage = new Container(); // 自定義loader const loader = new Loader(); // 自定義ticker const ticker = new Ticker(); // 每次屏幕刷新從新渲染,不然只會渲染第一幀 ticker.add(() => { renderer.render(stage); }); // 開始執行ticker,必定要調用這個方法,註冊的回調函數纔會被執行!!! ticker.start(); document.body.appendChild(renderer.view); loader .add('bili', 'http://pic.deepred5.com/bilibili.jpg') .load(setup) function setup() { const bili = new Sprite( loader.resources["bili"].texture ); bili.width = 50; bili.height = 50; stage.addChild(bili); // 動畫效果 ticker.add(() => { if (bili.x <= 200) { bili.x += 2; } }); TweenMax.to(bili, 1, { y: 100, delay: 3 }); } 複製代碼
其實PIXI.Application的底層就是幫咱們簡化了上述的操做。