PixiJS基础

介绍

2D Canvas框架,使用 WebGL(或可选的 Canvas)来显示图像和其他 2D 视觉内容。

提供了完整的场景图,并提供交互支持以启用处理点击和触摸事件。

轻量,以渲染功能为核心。

移植性,轻易在前端项目中引用。

目前最新版本的PixiJS为 v5.0.0+,所以本文默认使用 v5+版本。不过考虑到 v4+ 依然有很大的使用量,以及目前很多文章往往都写的是一些 v4+ 的使用方法和bug处理。我也会尽量贴出来做一个对比。

安装

  • CDN引入全局对象PIXI
    ```html

- NPM引入

npm install –save pixi.js

```js
import * as PIXI from "pixi.js";

基础概念和属性

APP

先在Html中添加对应的标签,用以存放画布内容

<div class="pixiDom" ref="pixiDom"></div>

接着创建全局app对象,附加到页面对应标签中。

Application 对象创建可视区域,自动生成 <canvas> 元素。

let app = new PIXI.Application({ width: 640, height: 360 });

// 或 document.body.appendChild(app.view);
pixiDom.appendChild(app.view);

这里创建application时,只穿入了width和height两个参数。除了宽高尺寸,PIXI.Application 还支持别的属性,比如:

let app = new PIXI.Application({
    width: 256,         // default: 800
    height: 256,        // default: 600
    // 设置抗锯齿
    antialias: true,    // default: false
    // 分辨率
    resolution: 1,      // default: 1
    // PIXI 的 renderer 对象默认使用 WebGL。如果想强行使用 Canvas 绘图 API,可以使用 forceCanvas 字段
    forceCanvas: true,  // default: false; 
    // 背景颜色和透明度
    backgroundColor: 0x000000, // default: 0x000000
    backgroundAlpha: 1,   // default: 1
    // 根据css像素resize, 且允许分辨率resolution不为1
    autoDensity: true,    // default: false
    // 设定要传给webGL的参数,对双显卡的设备而言可提高效能
    powerPreference: ''
});

Ticker

application的ticker属性,个人理解为类似RequestAnimationFrame的逐帧响应函数,每一帧将会触发一次相应函数。一般和app连用

app.ticker.add((delta) => {
    sprite.rotation += 0.1;
});

Container

Container表示容器,在Pixi中使用的最为频繁,可以理解为html中的div标签,容器(包括其它各种对象)有着它们的位置position,基点pivot等常用属性对象,且能够通过addChild来添加子对象,通过removeChild来删除子对象,类似DOM的增删。

let mask = new PIXI.Container()
let container = new PIXI.Container();
container.addChild(mask);

// 所有需要显示的物体都要放到舞台上,即 app.stage。application的stage属性是一种特殊的 Container,用作所有可视元素的根结点,类似于body标签。
app.stage.addChild(container);
// app.stage.removeChild(container);

Graphics

Graphics表示图形,可以借助它来绘制矩形Rect/圆形Circle/椭圆Ellipse/多边形Polygon

经常借助Graphics来为容器绘制Container的矩形遮罩、或者一些简单的图形:

let mask = new PIXI.Graphics();

// beginFill接受两个参数:颜色和透明度
// Graphics.beginFill(color?: number, alpha?: number)
mask.beginFill(0xff387d);

// lineStyle为设置图形的边的属性
// Graphics.lineStyle(width: number, color?: number, alpha?: number, alignment?: number, native?: boolean)
mask.lineStyle({ color: 0xffffff, width: 4, alignment: 0 });

// 调用绘制函数进行绘制。绘制多边形drawPolygon需要传入坐标的数组。
// Graphics.drawPolygon(...path: number[] | PIXI.Point[]):
// Graphics.drawCircle(x: number, y: number, radius: number)
// Graphics.drawRect(x: number, y: number, width: number, height: number)
mask.drawRect(0, 0, 640, 700);

mask.endFill();

container.addChild(mask);

所有图形绘制前需要调用beginFill来确定填充颜色及透明度,在绘制结束后需要调用endFill来应用绘制。

在确定填充颜色后,可以指定画笔样式lineStyle来确定绘制的图形的边的样式,然后就可以调用drawRect等来绘制相应的图形了。

Text

Text即表示文本节点。文字具备其相应的CSS属性,如下:

let innerText = new PIXI.Text(text, {
    fontSize: 80,
    fill: 0xffffff,
    stroke: "#4a1850",
    strokeThickness: 3,
    wordWrap: true,
    wordWrapWidth: 180
});
container.addChild(innerText);

TextStyle

  • 字体包含着文字的大小,字体族等。
  • 外观确定文字的填充颜色fill,轮廓stroke等。
  • 阴影通过dropShadow定义,包括dropShadowColor,dropShadowBlur等。
  • 布局主要影响文字的位置及间距等,通过align确定对齐方式,wordWrap和wordWrapWidth确定文字间隙等。
// from Pixi examples
const style = new PIXI.TextStyle({
    fontFamily: 'Arial',
    fontSize: 36,
    fontStyle: 'italic',
    fontWeight: 'bold',
    fill: ['#ffffff', '#00ff99'], // gradient
    stroke: '#4a1850',
    strokeThickness: 5,
    dropShadow: true,
    dropShadowColor: '#000000',
    dropShadowBlur: 4,
    dropShadowAngle: Math.PI / 6,
    dropShadowDistance: 6,
    wordWrap: true,
    wordWrapWidth: 440,
    lineJoin: 'round',
});

const richText = new PIXI.Text('Rich text', style);

Sprite

Sprite称精灵,在各种动画框架中均可见到它的身影,可以通过图片来创建。

const imgPath = 'assets/image.png'
let sprite = new PIXI.Sprite(PIXI.Texture.from(imgPath))
// 等价于
let sprite = PIXI.Sprite.from(imgPath)

纹理(texture)

由于 Pixi 使用 WebGL 在显卡上渲染图像,因此图像的格式必须能够被显卡处理。这种图像称作纹理(texture)。使用精灵显示图像前,需要把普通图片文件转换为 WebGL 纹理。为了提升效率,Pixi 使用纹理缓存(texture cache)存储引用所有精灵需要的纹理。纹理名称与文件路径匹配。

let sprite = PIXI.Sprite.from('assets/image.png');

// 等价于

let texture = PIXI.Texture.from('assets/image.png'); // 当需要同一份图片生成不同精灵时,可以采用创建纹理来重复使用
let sprite1 = new PIXI.Sprite(texture);              // PIXI.Sprite(item:PIXI.Texture), PIXI.Sprite.from('assets/image.png')算是一种简写形式
let sprite2 = new PIXI.Sprite(texture);

更高效的做法,使用loader来批量添加纹理

import { Loader, LoaderResource, Sprite } from 'pixi.js';

const arr = [
  {
    key: 'image1',
    url: 'assets/image1.png'
  },
  {
    key: 'image2',
    url: 'assets/image2.png'
  },
  ...
]

Loader.shared.add(arr).load(setup);

function setup() {
    let sprite = new PIXI.Sprite(
    loader.shared.resources['image1'].texture
);
}

position && pivot

一个容器的位置position是相对于其父容器的(0,0)来进行相对于本容器基点的位置(一般为(0,0))来定位。

容器的一些变化操作,例如放大,旋转,移动等,都是以基点为中心进行。

例如我们可以封装一个PIXI元素的居中函数:

// 传入的son、parent为PIXI元素,如Container、Sprites、Graphics等
const setCenter = (son, parent) => {
  // 设置position的x、y属性
  son.position.x = parent.width / 2 - son.width / 2;
  son.position.y = parent.height / 2 - son.height / 2;
};

一般来说,当元素涉及到有放大、旋转等属性改变的操作,建议都将基点设置为中心点,这样放大等效果会更加自然。我们来升级一下setCenter函数,改变一下基点:

const setCenter = (son, parent) => {
  // 此时x、y的坐标点为基点的坐标。目前还是(0,0)。后续设置为中心。
  son.position.x = parent.width / 2;
  son.position.y = parent.height / 2;

  // 设置son的基点为中心点
  son.pivot.x = son.width / 2;
  son.pivot.y = son.height / 2;
};

基点一经设置不会在变。若后续手动改变了基点,则在该基点下的设置也会改变。

交互事件处理

任何DisplayObject派生的对象(精灵、容器等。)只需将其interactive属性设置为true,就可以成为交互式的。这样做将导致对象发出交互事件,可以响应这些事件来驱动项目的行为。

let sprite = PIXI.Sprite.from('/some/texture.png');
sprite.interactive = true
// 响应点击事件
sprite.on('pointerdown', (event) => { alert('clicked!'); });

PIXI支持三种交互事件:mouse、touch、pointer(鼠标事件、触摸事件、指针事件)。

鼠标事件由鼠标触发,例如click事件。触摸事件由可触摸设备触发。这两者都可以出发指针事件。为了兼容不同输入设备(手机&&PC),建议首选pointer事件,兼容两者。

有时为了兼容比较特殊的输入设备,可能需要使用mouse和touch事件。

PixiJS的交互系统被设计成看起来类似于web开发中DOM所支持的交互事件,但是有一些重要的不同之处会使不熟悉PixiJS的用户出错。

首先,PixiJS中的事件不会“冒泡”,这意味着您不能在父对象上设置事件触发器,并在单击子对象时让它触发。如果您想支持冒泡,您需要在子对象的事件处理代码中显式地重新触发父对象的事件。

第二,没有事件捕获支持——例如,你不能让一个对象在拖动时捕获所有的交互事件。

当前支持交互事件的对象

  • PIXI.Container
  • PIXI.Graphics
  • PIXI.Sprite
  • PIXI.Text
  • PIXI.BitmapText
  • PIXI.TilingSprite
  • PIXI.AnimatedSprite
  • PIXI.Mesh
  • PIXI.NineSlicePlane
  • PIXI.SimpleMesh
  • PIXI.SimplePlane
  • PIXI.SimpleRope

本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 (CC BY-NC-ND 4.0) 进行许可。