PixiJS基礎教程

PixiJS是一個輕量級的2D渲染引擎,它能自動偵測使用WebGL仍是Canvas來建立圖形。這個庫常常被用來製做HTML5遊戲以及有複雜交互的H5活動頁。javascript

搭建環境

注意:本文使用pixi最新的v5版本,同時使用Parcel進行模塊化打包html

項目初始化前端

mkdir learn-pixi
cd learn-pixi
npm init -y
複製代碼

安裝依賴java

npm i pixi.js -save
npm i parcel-bundler -save-dev
複製代碼

根目錄建立index.htmlgit

<!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.jsgithub

alert('pixi');
複製代碼

修改package.jsonweb

"scripts": {
  "dev": "parcel index.html -p 8080",
  "build": "parcel build index.html"
}
複製代碼

運行npm run dev,訪問 http://localhost:8080/ 便可看到效果npm

快速開始

index.jsjson

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

咱們能夠繼續建立新的圖形,而後渲染到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:

  • Container (舞臺,場景)
  • Renderer (渲染器)
  • Ticker (計時器)
  • Loader (資源加載器)
  • Sprite (精靈)
const app = new Application({
  width: 300,
  height: 300
});
複製代碼

Application是pixi提供的一個工具方法,它能自動建立renderer,ticker 和container,咱們一般使用該方法快速建立應用。

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的屬性,位於其中的子節點,都會受到影響。好比上面的例子,咱們把rectanglerectangle2分到了同一個組裏,若是但願同時隱藏這兩個元素,只需修改它們父級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佈局

Renderer

app.renderer是一個Renderer的實例,若是你但願從新渲染頁面,就須要使用它

// 把畫布從新渲染爲500*500大小
app.renderer.resize(500, 500);

// 渲染一個容器
const container = new Container();
app.renderer.render(container);
複製代碼

Sprite

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來預加載圖片,當圖片所有加載成功後,才渲染出來。

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

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.jsTweenMax,這裏咱們使用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 } });

}

複製代碼

自定義的Application

咱們一般使用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的底層就是幫咱們簡化了上述的操做。

參考

Pixi教程中文版

Pixi wiki

學習 PixiJS — 補間動畫

相關文章
相關標籤/搜索