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) 进行许可。