PixiJS 是一个功能强大、高性能的 2D 渲染引擎,主要用于在 Web 浏览器中创建丰富的交互式图形内容。它通过抽象底层 WebGL(Web Graphics Library)和 Canvas 2D API,为开发者提供一个易于使用的 API,从而在不同浏览器和设备上实现一致且流畅的视觉体验。PixiJS 的核心优势在于其对硬件加速的利用,这使得它在处理大量图像、复杂动画和高分辨率视觉效果时表现出色,是开发游戏、互动广告、数据可视化和各种富媒体应用的首选工具。

核心思想:

  • 高性能渲染:优先利用 WebGL 进行硬件加速渲染,提供流畅的用户体验。当 WebGL 不可用时,自动回退到 Canvas 2D。
  • 易于使用:提供一套简洁直观的 API,简化了复杂的 WebGL 编程,让开发者能专注于内容创作。
  • 场景图 (Scene Graph):采用分层结构管理显示对象,便于组织和操作复杂的视觉元素。
  • 跨平台兼容性:确保在不同浏览器、操作系统和设备上提供一致的渲染效果。

一、为什么需要 PixiJS?

Web 浏览器端进行高性能的 2D 图形渲染一直是一个挑战。传统的 HTML 元素(如 <div>)在处理大量或频繁变化的元素时性能不佳,而原生的 Canvas 2D API 虽然提供了像素级别的绘制能力,但其渲染管线位于 CPU 端,对于复杂的动画和高分辨率图形,往往难以达到理想的帧率。此外,直接使用 WebGL API 虽然能利用 GPU 加速,但其学习曲线陡峭,开发复杂度高。

PixiJS 应运而生,致力于解决这些问题:

  1. 性能瓶颈:通过封装 WebGL,PixiJS 将渲染任务卸载到 GPU,大幅提高了渲染效率,特别是在处理数以千计的精灵 (Sprites) 和复杂动画时。
  2. 开发难度:PixiJS 提供了一套高级且易于理解的 API,开发者无需深入了解 WebGL 的底层细节,即可构建高性能的 2D 场景。
  3. 兼容性问题:PixiJS 内部包含了自动回退机制。如果用户的浏览器不支持 WebGL,它会平滑地切换到 Canvas 2D 模式,确保应用在不同环境下都能正常运行。
  4. 项目管理:通过其场景图系统,PixiJS 提供了结构化的方式来组织和管理显示对象,使得大型项目中的元素层级、位置和交互逻辑更加清晰。
  5. 丰富的特性:除了基础渲染,PixiJS 还内置了纹理加载、交互事件、滤镜、文本渲染等功能,满足了多数 2D 应用的开发需求。

二、核心概念

理解 PixiJS 的工作原理,需要掌握以下几个关键概念:

2.1 渲染器 (Renderer)

PIXI.Renderer 是 PixiJS 的核心组件,负责将舞台 (Stage) 上的所有显示对象渲染到 HTML <canvas> 元素上。它内部根据浏览器支持情况,自动选择使用 WebGLRenderer(硬件加速)或 CanvasRenderer(软件渲染)进行渲染。

  • WebGL (Web Graphics Library): 一种 JavaScript API,用于在任何兼容的 Web 浏览器中渲染交互式 2D 和 3D 图形,无需插件。它通过将图形处理任务直接交给计算机的图形处理单元 (GPU) 来实现硬件加速。
  • Canvas 2D API: HTML5 提供的一种通过 JavaScript 在 <canvas> 元素上绘制图形的 API。它是一个即时模式 (immediate mode) 的绘图系统,所有渲染操作都在 CPU 上进行。

2.2 舞台 (Stage)

PIXI.Container 的一个实例,通常是一个应用程序的根容器,所有其他显示对象(如精灵、文本等)都需要添加到舞台上才能被渲染。它代表了整个渲染场景的顶层。

2.3 容器 (Container)

PIXI.Container 是 PixiJS 场景图的基本构建块。它是一个抽象的显示对象,可以包含其他显示对象作为其子级。容器本身不可见,但可以管理其子级的位置、旋转、缩放等属性,并提供方便的场景图遍历和操作方法。这种分层结构是 PixiJS 组织复杂场景的关键。

2.4 精灵 (Sprite)

PIXI.Sprite 是最常用的显示对象之一,用于在屏幕上显示纹理(图像)。它继承自 PIXI.Container,因此也具有位置、旋转、缩放等属性。精灵需要一个 PIXI.Texture 实例来定义其外观。

2.5 纹理 (Texture)

PIXI.Texture 封装了单个图像数据,通常是从图像文件加载而来。它是 GPU 可以理解的图像数据格式。为了高效渲染,PixiJS 会将图像上传到 GPU 作为纹理。

2.6 图形 (Graphics)

PIXI.Graphics 允许开发者绘制基本的几何形状,如矩形、圆形、线条、多边形等,并填充颜色或描边。它提供了一个矢量绘图接口,而无需使用位图图像。

2.7 加载器 (Loader)

PIXI.Loader 用于异步加载图像、字体、JSON 数据、音频等各种资源。它提供了加载进度、缓存和错误处理机制,确保在渲染前所有必需资源都已就绪。

2.8 计时器 (Ticker)

PIXI.Ticker 提供了一个可靠的帧管理器,用于驱动动画和游戏循环。它会自动处理浏览器 requestAnimationFrame 调用,确保动画在最佳时机更新,并提供当前帧率和 delta time 等信息,方便进行平滑动画和物理模拟。

三、PixiJS 的工作原理

PixiJS 的核心在于其渲染管线和场景图管理。

  1. 初始化: 开发者创建一个 PIXI.Application 实例,它会初始化 PIXI.RendererPIXI.Container (作为根舞台) 和 PIXI.Ticker
  2. 资源加载: 使用 PIXI.Loader 加载所有图像、字体等资源,将其转换为 GPU 可识别的 PIXI.Texture
  3. 构建场景图: 开发者通过创建 PIXI.SpritePIXI.GraphicsPIXI.Text 等显示对象,并将它们添加到 PIXI.Container 实例中,最终构建一个层级化的场景图(一个树形结构)。
  4. 渲染循环: PIXI.Ticker 会在每个动画帧(通常是每秒 60 次)触发一个更新事件。
  5. 更新逻辑: 在每个更新事件中,开发者可以修改场景图中显示对象的状态(位置、旋转、缩放、颜色等)。
  6. 渲染过程: PIXI.Renderer 遍历整个场景图,将所有需要渲染的显示对象(主要是继承自 PIXI.DisplayObject 的实例)扁平化,并收集它们的顶点数据、纹理数据等信息。
  7. GPU 绘制: PIXI.Renderer 利用 WebGL API 将这些数据发送给 GPU,并通过一系列的绘图调用(Draw Call),在 <canvas> 元素上高效地渲染出最终的图像。如果 WebGL 不可用,则回退到 Canvas 2D API 进行绘制。

四、安装与配置

PixiJS 可以通过 npm、yarn 进行安装,也可以直接通过 CDN 引入。

4.1 使用包管理器安装 (推荐)

对于现代前端项目,推荐使用 npm 或 yarn 进行安装:

1
2
3
4
5
# 使用 npm
npm install pixi.js

# 或者使用 yarn
yarn add pixi.js

安装后,你可以在你的 JavaScript/TypeScript 文件中导入 PixiJS 模块:

1
2
3
import * as PIXI from 'pixi.js';
// 或者按需导入,提高效率和减小打包体积
// import { Application, Sprite, Graphics, Loader } from 'pixi.js';

4.2 使用 CDN 引入

对于简单的项目或快速原型开发,可以通过 CDN 直接引入 PixiJS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html>
<head>
<title>My PixiJS App</title>
<style>
body { margin: 0; padding: 0; overflow: hidden; }
</style>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/pixi.js@7.x/dist/pixi.min.js"></script>
<script>
// PixiJS 代码将在此处编写
const app = new PIXI.Application();
document.body.appendChild(app.view);
// ...
</script>
</body>
</html>

这里 7.x 可以替换为 PixiJS 的具体版本号,例如 7.4.2

五、常用接口 (API) 解析

PixiJS 提供了丰富且直观的 API 接口,以下是一些最常用和核心的类及其关键属性/方法。

5.1 PIXI.Application

PIXI.Application 是 PixiJS 应用的入口点,它集成了渲染器、舞台、加载器和计时器等核心组件,简化了开发流程。

实例化:

1
2
3
4
5
6
7
8
9
const app = new PIXI.Application({
width: 800, // canvas 宽度
height: 600, // canvas 高度
backgroundColor: 0x1099bb, // 背景颜色,十六进制
resolution: window.devicePixelRatio || 1, // 分辨率
antialias: true, // 启用抗锯齿
autoDensity: true, // 自动适配设备像素比
});
document.body.appendChild(app.view); // 将 canvas 添加到 DOM

常用属性:

  • app.view: HTML <canvas> 元素。
  • app.renderer: PIXI.Renderer 实例,负责渲染。
  • app.stage: PIXI.Container 实例,应用的根容器。
  • app.loader: PIXI.Loader 实例,用于资源加载。
  • app.ticker: PIXI.Ticker 实例,用于管理动画循环。
  • app.screen: PIXI.Rectangle,表示渲染器当前的尺寸 (width, height)。

常用方法:

  • app.resize(): 调整渲染器视图大小,通常在窗口大小变化时调用。
  • app.destroy(): 销毁应用实例,释放资源。

5.2 PIXI.DisplayObject (基类)

所有能显示在 PixiJS 舞台上的对象(如 Container, Sprite, Graphics, Text)都继承自 PIXI.DisplayObject。它定义了所有显示对象共有的基本属性。

常用属性:

  • x, y: 显示对象在父容器坐标系中的位置。
  • width, height: 显示对象的当前宽度和高度(受scale影响)。
  • scale.x, scale.y: 沿 X 和 Y 轴的缩放比例。obj.scale.set(0.5) 会同时设置 xy
  • rotation: 旋转角度,单位为弧度(Math.PI 代表 180 度)。
  • angle: 旋转角度,单位为度(更易读)。
  • alpha: 透明度,范围 0 (完全透明) 到 1 (完全不透明)。
  • visible: 布尔值,是否可见。
  • anchor.x, anchor.y: 纹理的锚点或枢轴点(范围 01)。sprite.anchor.set(0.5) 会使精灵的中心作为旋转和定位的基准点。
  • pivot.x, pivot.y: 旋转的枢轴点在对象局部坐标系中的位置。
  • parent: 当前显示对象的父容器。
  • children: 当前显示对象的子级数组。
  • interactive: 布尔值,是否可以接收用户交互事件(鼠标/触摸)。必须设置为 true 才能响应事件。
  • hitArea: PIXI.RectanglePIXI.Circle 等对象,定义可交互的区域,用于更精确的点击检测。
  • cursor: 鼠标悬停在可交互对象上时显示的 CSS 样式,例如 'pointer'

常用方法:

  • on(event, listener) / off(event, listener): 注册/取消事件监听器,例如 'pointertap', 'pointerdown', 'pointerup', 'pointermove'
  • addListener(event, listener): 与 on 相同。
  • removeListener(event, listener): 与 off 相同。
  • getGlobalPosition(): 返回对象在舞台坐标系中的位置。
  • toGlobal(position, point): 将局部坐标转换为全局坐标。
  • toLocal(position, from, point): 将全局坐标或另一个显示对象的局部坐标转换为当前对象的局部坐标。

5.3 PIXI.Container

用于组织和管理其他显示对象的容器,本身不渲染任何视觉内容。

实例化:

1
2
const container = new PIXI.Container();
app.stage.addChild(container); // 将容器添加到舞台

常用方法:

  • addChild(...displayObjects): 添加一个或多个子级显示对象。
  • removeChild(...displayObjects): 移除一个或多个子级显示对象。
  • addChildAt(child, index): 在指定索引处添加子级。
  • removeChildAt(index): 移除指定索引处的子级。
  • removeChildren(beginIndex, endIndex): 移除指定范围内的子级。
  • getChildAt(index): 获取指定索引处的子级。
  • getChildByName(name): 通过 name 属性(需提前设置)获取子级。
  • sortChildren(): 强制对子级进行排序,通常与 sortableChildren = truesortDirty = true 配合使用。

5.4 PIXI.Sprite

用于显示图片的显示对象。

实例化:

  • 从纹理创建:new PIXI.Sprite(texture)
  • 从图片URL创建:PIXI.Sprite.from('path/to/image.png')
  • 从纹理帧创建(用于图集):PIXI.Sprite.fromFrame('frame_name')
  • 从画布或视频创建:PIXI.Sprite.from(HTMLElement)
1
2
3
4
5
6
7
8
9
10
11
// 示例:从纹理创建精灵
const texture = PIXI.Texture.from('assets/image.png');
const sprite = new PIXI.Sprite(texture);
sprite.x = 100;
sprite.y = 100;
sprite.anchor.set(0.5); // 设置中心锚点

// 示例:直接从URL创建精灵 (会异步加载)
const spriteFromURL = PIXI.Sprite.from('assets/another_image.png');
spriteFromURL.position.set(200, 200);
app.stage.addChild(spriteFromURL);

常用属性:

  • texture: 当前精灵使用的 PIXI.Texture 实例。
  • 继承自 PIXI.DisplayObject 的所有属性。

5.5 PIXI.Graphics

用于绘制矢量图形。

实例化:

1
2
const graphics = new PIXI.Graphics();
app.stage.addChild(graphics);

常用方法 (链式调用):

  • lineStyle(width, color, alpha): 设置线条样式。
  • beginFill(color, alpha): 开始填充形状。
  • endFill(): 结束填充。
  • drawRect(x, y, width, height): 绘制矩形。
  • drawRoundedRect(x, y, width, height, radius): 绘制圆角矩形。
  • drawCircle(x, y, radius): 绘制圆形。
  • drawEllipse(x, y, width, height): 绘制椭圆。
  • drawPolygon(...points): 绘制多边形。
  • moveTo(x, y): 移动画笔到指定点。
  • lineTo(x, y): 从当前点画线到指定点。
  • clear(): 清除所有绘制内容。
1
2
3
4
5
6
7
8
9
10
// 示例:绘制一个红色的正方形和一个蓝色的圆
graphics.lineStyle(2, 0xFF00FF, 1) // 紫色边框
.beginFill(0xFF0000) // 红色填充
.drawRect(50, 50, 100, 100) // 绘制一个矩形
.endFill();

graphics.lineStyle(4, 0x00FF00, 1) // 绿色边框
.beginFill(0x0000FF, 0.8) // 蓝色填充,半透明
.drawCircle(250, 100, 50) // 绘制一个圆形
.endFill();

5.6 PIXI.Text

用于在舞台上显示文本。

实例化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const text = new PIXI.Text('Hello PixiJS!', {
fontFamily: 'Arial',
fontSize: 36,
fill: 0xffffff, // 白色
align: 'center',
dropShadow: true,
dropShadowColor: '#000000',
dropShadowAngle: Math.PI / 6,
dropShadowDistance: 5,
});
text.x = app.screen.width / 2;
text.y = app.screen.height / 2;
text.anchor.set(0.5); // 设置文本中心为锚点
app.stage.addChild(text);

常用属性:

  • text: 字符串,文本内容。
  • style: PIXI.TextStyle 对象,用于设置字体、颜色、大小等样式。
  • 继承自 PIXI.DisplayObject 的所有属性。

5.7 PIXI.Loader

用于异步加载资源。可以通过 app.loader 访问。

常用方法:

  • add(name, url)add({ name, url, ...}): 添加一个或多个资源到加载队列。
  • load(callback): 开始加载队列中的资源,完成后调用回调函数。回调函数接收 (loader, resources) 两个参数。
  • reset(): 重置加载器。
  • onProgress.add(callback): 监听加载进度。
  • onComplete.add(callback): 监听加载完成事件。
  • onError.add(callback): 监听加载错误事件。
1
2
3
4
5
6
7
8
9
app.loader.add('bunny', 'assets/bunny.png')
.add('data', 'assets/data.json')
.add('spritesheet', 'assets/spritesheet.json')
.onProgress.add((loader) => console.log(`Progress: ${loader.progress}%`))
.load((loader, resources) => {
console.log('All resources loaded!');
const bunnySprite = new PIXI.Sprite(resources.bunny.texture);
app.stage.addChild(bunnySprite);
});

5.8 PIXI.Ticker

用于管理和驱动动画循环,与浏览器的 requestAnimationFrame 同步。可以通过 app.ticker 访问。

常用方法:

  • add(callback, context): 添加一个回调函数到动画循环。回调函数会接收一个 delta 参数,表示自上次更新以来的时间步长。
  • remove(callback, context): 从动画循环中移除回调函数。
  • start(): 启动计时器(默认已启动)。
  • stop(): 停止计时器。
  • update(): 手动触发一次更新(通常不需要)。
1
2
3
4
app.ticker.add((delta) => {
// 任何需要在每帧更新的逻辑,例如移动、旋转等
bunny.rotation += 0.05 * delta;
});

5.9 PIXI.TexturePIXI.BaseTexture

PIXI.Texture 代表一张图像在 GPU 中的表现形式。PIXI.BaseTexture 是其底层对象,包含实际的图像数据。

常用方法 (静态):

  • PIXI.Texture.from(source): 从 URL、HTMLImageElementHTMLCanvasElement 等创建纹理。
  • PIXI.Texture.fromImage(imageUrl, options): 遗留方法,推荐使用 from()
  • PIXI.Texture.fromLoader(resource, imageUrl): 从 PIXI.Loader 资源创建。
  • PIXI.Texture.WHITE, PIXI.Texture.BLACK: 常用的纯白和纯黑纹理。
1
2
3
4
5
6
7
// 从图片 URL 创建纹理
const texture = PIXI.Texture.from('path/to/image.png');

// 从另一个精灵的纹理创建一个纹理切片 (用于图集)
const rect = new PIXI.Rectangle(0, 0, 32, 32); // 定义一个 32x32 的矩形区域
const frameTexture = new PIXI.Texture(baseTexture, rect);
const frameSprite = new PIXI.Sprite(frameTexture);

5.10 PIXI.Rectangle

代表一个矩形区域,常用于定义纹理帧、碰撞区域或边界框。

实例化:

1
const rect = new PIXI.Rectangle(x, y, width, height); // x, y 为左上角坐标

常用属性:

  • x, y: 矩形左上角坐标。
  • width, height: 矩形宽度和高度。
  • left, right, top, bottom: 边界位置。
  • centerX, centerY: 矩形中心点坐标。

常用方法:

  • contains(x, y): 判断点是否在矩形内。
  • intersects(rect): 判断两个矩形是否相交。
  • clone(): 克隆一份矩形。

六、使用示例:结合常用接口

这个示例将创建一个 PixiJS 应用,加载一张图片,并绘制一个形状,通过 PIXI.Ticker 驱动动画,并演示一些交互性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<!DOCTYPE html>
<html>
<head>
<title>PixiJS 常用接口示例</title>
<style>
body { margin: 0; padding: 0; overflow: hidden; background-color: #333; }
canvas { display: block; }
</style>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/pixi.js@7.x/dist/pixi.min.js"></script>
<script>
// 1. 创建 PixiJS 应用实例
const app = new PIXI.Application({
width: window.innerWidth,
height: window.innerHeight,
backgroundColor: 0x2c3e50, // 深蓝色背景
resolution: window.devicePixelRatio || 1,
antialias: true,
});
document.body.appendChild(app.view);

// 2. 响应窗口大小变化
window.addEventListener('resize', () => {
app.renderer.resize(window.innerWidth, window.innerHeight);
// 调整精灵和文本位置以保持居中
if (bunny) {
bunny.x = app.screen.width / 2;
bunny.y = app.screen.height / 2;
}
if (infoText) {
infoText.x = app.screen.width / 2;
infoText.y = app.screen.height - 50;
}
});

let bunny; // 定义全局变量以在不同作用域中使用
let infoText; // 定义全局变量以在不同作用域中使用

// 3. 使用 Loader 加载资源
app.loader.add('bunnyTexture', 'https://pixijs.com/assets/bunny.png')
.onProgress.add((loader) => console.log(`加载进度: ${loader.progress.toFixed(2)}%`))
.load(setup); // 加载完成后调用 setup 函数

function setup(loader, resources) {
// -- 绘制一个 Graphics 形状 --
const yellowSquare = new PIXI.Graphics();
yellowSquare.beginFill(0xF1C40F) // 黄色填充
.drawRect(0, 0, 80, 80) // 绘制一个 80x80 的正方形
.endFill();
yellowSquare.x = app.screen.width / 4;
yellowSquare.y = app.screen.height / 2 - 40;
yellowSquare.anchor.set(0.5); // 锚点设为中心
yellowSquare.interactive = true; // 允许交互
yellowSquare.buttonMode = true; // 鼠标悬停时显示手型光标

yellowSquare.on('pointerdown', () => {
yellowSquare.scale.set(1.2); // 点击时放大
console.log('Square clicked!');
});
yellowSquare.on('pointerupoutside', () => {
yellowSquare.scale.set(1.0); // 鼠标松开或移出时恢复
});
yellowSquare.on('pointerup', () => {
yellowSquare.scale.set(1.0);
});

app.stage.addChild(yellowSquare);

// -- 创建一个 Sprite 精灵 --
bunny = new PIXI.Sprite(resources.bunnyTexture.texture);
bunny.x = app.screen.width / 2;
bunny.y = app.screen.height / 2;
bunny.anchor.set(0.5); // 锚点设置在中心
bunny.scale.set(2); // 放大两倍
bunny.interactive = true; // 允许交互
bunny.buttonMode = true; // 鼠标悬停时显示手型光标
app.stage.addChild(bunny);

// 交互事件示例
bunny.on('pointerup', () => {
bunny.alpha = (bunny.alpha === 1) ? 0.5 : 1; // 点击切换透明度
console.log('Bunny clicked!');
});
bunny.on('pointerover', () => {
bunny.tint = 0xff0000; // 鼠标移入变红
});
bunny.on('pointerout', () => {
bunny.tint = 0xffffff; // 鼠标移出恢复原色
});

// -- 创建一个 Text 文本 --
infoText = new PIXI.Text('点击兔子改变透明度,点击方块放大', {
fontFamily: 'Arial',
fontSize: 24,
fill: 0xffffff,
align: 'center',
});
infoText.x = app.screen.width / 2;
infoText.y = app.screen.height - 50;
infoText.anchor.set(0.5);
app.stage.addChild(infoText);


// -- Ticker 动画循环 --
app.ticker.add((delta) => {
bunny.rotation += 0.02 * delta; // 兔子旋转
yellowSquare.rotation -= 0.01 * delta; // 方块反向旋转
});

console.log('PixiJS application is ready!');
}
</script>
</body>
</html>

七、总结

PixiJS 是一个高性能、易用且功能丰富的 2D WebGL 渲染引擎,它成功地在复杂的 GPU 编程和简单的 Web 开发之间架起了一座桥梁。

  • 优势:极佳的性能、友好的 API、强大的场景图管理、跨浏览器兼容性、丰富的生态系统和活跃的社区支持。
  • 适用场景
    • 2D 游戏开发:特别是桌面和移动端的休闲游戏、益智游戏、平台游戏等。
    • 互动媒体和广告:创建高性能、视觉丰富的互动广告和品牌体验。
    • 数据可视化:渲染大量动态数据点或复杂图表。
    • 教育和艺术应用:构建创意的互动工具和数字艺术作品。

通过充分理解和利用 PixiJS 提供的核心接口,开发者可以高效地构建出视觉惊艳、交互流畅的 Web 2D 应用程序,而无需深陷 WebGL 底层 API 的复杂性。