PixiJS 高级主题 #
性能优化概述 #
性能优化是 PixiJS 开发中的重要环节,良好的优化可以让应用在各种设备上流畅运行。
text
┌─────────────────────────────────────────────────────────────┐
│ 性能优化方向 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 渲染优化 │
│ ├── 减少绘制调用 │
│ ├── 使用批处理 │
│ ├── 合理使用缓存 │
│ └── 优化滤镜 │
│ │
│ 内存优化 │
│ ├── 纹理管理 │
│ ├── 对象池 │
│ ├── 及时销毁 │
│ └── 避免内存泄漏 │
│ │
│ 更新优化 │
│ ├── 减少更新频率 │
│ ├── 空间分区 │
│ ├── 视口裁剪 │
│ └── LOD(细节层次) │
│ │
└─────────────────────────────────────────────────────────────┘
渲染优化 #
批处理渲染 #
PixiJS 会自动批处理相同纹理的精灵:
javascript
// 好:相同纹理,自动批处理
const texture = PIXI.Texture.from('particle.png');
for (let i = 0; i < 1000; i++) {
const sprite = new PIXI.Sprite(texture);
app.stage.addChild(sprite);
}
// 差:不同纹理,无法批处理
for (let i = 0; i < 1000; i++) {
const sprite = PIXI.Sprite.from(`particle_${i % 10}.png`);
app.stage.addChild(sprite);
}
使用精灵表 #
javascript
// 使用精灵表可以让多个精灵共享同一纹理
const spritesheet = await Assets.load('sprites.json');
// 这些精灵可以批处理
const sprites = [];
for (let i = 0; i < 100; i++) {
const sprite = new PIXI.Sprite(spritesheet.textures['particle.png']);
sprites.push(sprite);
app.stage.addChild(sprite);
}
ParticleContainer #
对于大量粒子,使用 ParticleContainer:
javascript
import { ParticleContainer } from 'pixi.js';
const particleContainer = new ParticleContainer(10000, {
scale: true,
position: true,
rotation: true,
uvs: true,
alpha: true
});
app.stage.addChild(particleContainer);
// 添加粒子
for (let i = 0; i < 10000; i++) {
const particle = PIXI.Sprite.from('particle.png');
particleContainer.addChild(particle);
}
缓存位图 #
javascript
// 对于复杂的静态内容,启用缓存
const complexContainer = new Container();
// 添加多个子对象...
complexContainer.addChild(/* ... */);
// 缓存为位图
complexContainer.cacheAsBitmap = true;
// 更新时需要重新缓存
complexContainer.cacheAsBitmap = false;
// 更新内容...
complexContainer.cacheAsBitmap = true;
渲染纹理 #
javascript
import { RenderTexture } from 'pixi.js';
// 创建渲染纹理
const renderTexture = RenderTexture.create({
width: 512,
height: 512
});
// 渲染到纹理
app.renderer.render({
container: complexGraphics,
target: renderTexture
});
// 使用渲染结果
const sprite = new PIXI.Sprite(renderTexture);
内存管理 #
纹理管理 #
javascript
// 销毁纹理
texture.destroy(true);
// 从缓存移除
PIXI.Texture.removeFromCache('texture-id');
// 清理纹理缓存
PIXI.utils.clearTextureCache();
销毁显示对象 #
javascript
// 销毁精灵
sprite.destroy();
// 销毁并清理纹理
sprite.destroy({
children: true, // 销毁子对象
texture: true, // 销毁纹理
textureSource: true, // 销毁纹理源
context: true // 销毁 WebGL 上下文
});
// 销毁容器
container.destroy({
children: true
});
销毁应用 #
javascript
// 完整销毁应用
app.destroy(true, {
children: true,
texture: true,
textureSource: true,
context: true
});
对象池 #
javascript
class ObjectPool {
constructor(createFn, resetFn, initialSize = 10) {
this.createFn = createFn;
this.resetFn = resetFn;
this.pool = [];
for (let i = 0; i < initialSize; i++) {
this.pool.push(this.create());
}
}
create() {
const obj = this.createFn();
obj._pooled = true;
return obj;
}
get() {
if (this.pool.length > 0) {
const obj = this.pool.pop();
this.resetFn(obj);
return obj;
}
return this.create();
}
release(obj) {
if (obj._pooled) {
this.pool.push(obj);
}
}
}
// 使用对象池
const bulletPool = new ObjectPool(
() => {
const bullet = PIXI.Sprite.from('bullet.png');
bullet.visible = false;
app.stage.addChild(bullet);
return bullet;
},
(bullet) => {
bullet.visible = false;
bullet.x = 0;
bullet.y = 0;
},
50
);
// 获取子弹
const bullet = bulletPool.get();
bullet.visible = true;
bullet.x = player.x;
bullet.y = player.y;
// 释放子弹
bulletPool.release(bullet);
内存泄漏检测 #
javascript
// 检测显示对象数量
function countDisplayObjects(container) {
let count = 0;
const traverse = (obj) => {
count++;
if (obj.children) {
obj.children.forEach(traverse);
}
};
traverse(container);
return count;
}
// 定期检查
setInterval(() => {
console.log('显示对象数量:', countDisplayObjects(app.stage));
}, 5000);
更新优化 #
视口裁剪 #
javascript
class ViewportCulling {
constructor(app) {
this.app = app;
this.visibleObjects = new Set();
}
update(objects) {
const screen = this.app.screen;
objects.forEach(obj => {
const bounds = obj.getBounds();
const isVisible =
bounds.x < screen.width &&
bounds.x + bounds.width > 0 &&
bounds.y < screen.height &&
bounds.y + bounds.height > 0;
obj.visible = isVisible;
});
}
}
空间分区 #
javascript
class SpatialHash {
constructor(cellSize) {
this.cellSize = cellSize;
this.grid = new Map();
}
getKey(x, y) {
const cellX = Math.floor(x / this.cellSize);
const cellY = Math.floor(y / this.cellSize);
return `${cellX},${cellY}`;
}
insert(obj) {
const key = this.getKey(obj.x, obj.y);
if (!this.grid.has(key)) {
this.grid.set(key, []);
}
this.grid.get(key).push(obj);
}
query(x, y, radius) {
const results = [];
const minCellX = Math.floor((x - radius) / this.cellSize);
const maxCellX = Math.floor((x + radius) / this.cellSize);
const minCellY = Math.floor((y - radius) / this.cellSize);
const maxCellY = Math.floor((y + radius) / this.cellSize);
for (let cx = minCellX; cx <= maxCellX; cx++) {
for (let cy = minCellY; cy <= maxCellY; cy++) {
const key = `${cx},${cy}`;
const cell = this.grid.get(key);
if (cell) {
results.push(...cell);
}
}
}
return results;
}
clear() {
this.grid.clear();
}
}
LOD(细节层次) #
javascript
class LODSystem {
constructor() {
this.levels = [];
}
addLevel(distance, createFn) {
this.levels.push({ distance, createFn });
this.levels.sort((a, b) => a.distance - b.distance);
}
update(camera, objects) {
objects.forEach(obj => {
const dist = this.getDistance(camera, obj);
for (let i = this.levels.length - 1; i >= 0; i--) {
if (dist >= this.levels[i].distance) {
this.setLevel(obj, i);
break;
}
}
});
}
getDistance(camera, obj) {
return Math.hypot(camera.x - obj.x, camera.y - obj.y);
}
setLevel(obj, level) {
if (obj.currentLOD !== level) {
obj.currentLOD = level;
// 更新显示对象
}
}
}
调试技巧 #
FPS 显示 #
javascript
class FPSCounter {
constructor() {
this.fps = 0;
this.frames = 0;
this.lastTime = performance.now();
this.text = new Text({
text: 'FPS: 0',
style: {
fontFamily: 'monospace',
fontSize: 16,
fill: 0x00ff00
}
});
}
update() {
this.frames++;
const now = performance.now();
if (now - this.lastTime >= 1000) {
this.fps = this.frames;
this.frames = 0;
this.lastTime = now;
this.text.text = `FPS: ${this.fps}`;
}
}
}
const fpsCounter = new FPSCounter();
app.stage.addChild(fpsCounter.text);
app.ticker.add(() => {
fpsCounter.update();
});
渲染统计 #
javascript
class RenderStats {
constructor(app) {
this.app = app;
this.stats = {
drawCalls: 0,
objectsRendered: 0
};
this.text = new Text({
text: '',
style: {
fontFamily: 'monospace',
fontSize: 14,
fill: 0xffffff
}
});
this.setupHooks();
}
setupHooks() {
this.app.renderer.on('prerender', () => {
this.stats.drawCalls = 0;
this.stats.objectsRendered = 0;
});
this.app.renderer.on('postrender', () => {
this.updateText();
});
}
updateText() {
this.text.text = [
`Draw Calls: ${this.stats.drawCalls}`,
`Objects: ${this.stats.objectsRendered}`
].join('\n');
}
}
性能分析 #
javascript
class PerformanceProfiler {
constructor() {
this.profiles = new Map();
}
start(name) {
this.profiles.set(name, {
start: performance.now(),
calls: 0,
total: 0
});
}
end(name) {
const profile = this.profiles.get(name);
if (profile) {
profile.calls++;
profile.total += performance.now() - profile.start;
}
}
getReport() {
const report = [];
this.profiles.forEach((profile, name) => {
report.push({
name,
calls: profile.calls,
total: profile.total.toFixed(2),
average: (profile.total / profile.calls).toFixed(2)
});
});
return report;
}
}
const profiler = new PerformanceProfiler();
// 使用
app.ticker.add(() => {
profiler.start('update');
update();
profiler.end('update');
profiler.start('render');
// 渲染逻辑
profiler.end('render');
});
调试工具 #
javascript
// 启用 PixiJS DevTools
if (import.meta.env.DEV) {
globalThis.__PIXI_APP__ = app;
globalThis.__PIXI_STAGE__ = app.stage;
globalThis.__PIXI_RENDERER__ = app.renderer;
}
// 显示边界框
function showBounds(displayObject, color = 0xff0000) {
const bounds = displayObject.getBounds();
const graphics = new Graphics();
graphics.rect(bounds.x, bounds.y, bounds.width, bounds.height);
graphics.stroke({ width: 1, color });
app.stage.addChild(graphics);
return graphics;
}
// 显示锚点
function showAnchor(sprite, color = 0x00ff00) {
const graphics = new Graphics();
graphics.circle(sprite.x, sprite.y, 5);
graphics.fill({ color });
app.stage.addChild(graphics);
return graphics;
}
架构设计 #
场景管理 #
javascript
class SceneManager {
constructor(app) {
this.app = app;
this.scenes = new Map();
this.currentScene = null;
}
add(name, scene) {
this.scenes.set(name, scene);
}
async switchTo(name) {
if (this.currentScene) {
await this.currentScene.onExit();
this.app.stage.removeChild(this.currentScene);
}
const scene = this.scenes.get(name);
if (scene) {
this.currentScene = scene;
this.app.stage.addChild(scene);
await scene.onEnter();
}
}
update(delta) {
if (this.currentScene) {
this.currentScene.update(delta);
}
}
}
class Scene extends Container {
async onEnter() {
// 进入场景
}
async onExit() {
// 离开场景
}
update(delta) {
// 更新逻辑
}
}
实体组件系统 #
javascript
class Entity {
constructor() {
this.components = new Map();
}
addComponent(component) {
this.components.set(component.constructor, component);
component.entity = this;
component.init();
return this;
}
getComponent(ComponentClass) {
return this.components.get(ComponentClass);
}
removeComponent(ComponentClass) {
const component = this.components.get(ComponentClass);
if (component) {
component.destroy();
this.components.delete(ComponentClass);
}
return this;
}
update(delta) {
this.components.forEach(component => {
component.update(delta);
});
}
}
class Component {
constructor() {
this.entity = null;
}
init() {}
update(delta) {}
destroy() {}
}
// 示例组件
class TransformComponent extends Component {
constructor(x = 0, y = 0) {
super();
this.x = x;
this.y = y;
this.rotation = 0;
this.scale = { x: 1, y: 1 };
}
}
class SpriteComponent extends Component {
constructor(texture) {
super();
this.sprite = new PIXI.Sprite(texture);
}
init() {
const transform = this.entity.getComponent(TransformComponent);
if (transform) {
this.sprite.x = transform.x;
this.sprite.y = transform.y;
}
}
update(delta) {
const transform = this.entity.getComponent(TransformComponent);
if (transform) {
this.sprite.x = transform.x;
this.sprite.y = transform.y;
this.sprite.rotation = transform.rotation;
}
}
}
// 使用
const player = new Entity()
.addComponent(new TransformComponent(100, 100))
.addComponent(new SpriteComponent(texture));
状态机 #
javascript
class StateMachine {
constructor() {
this.states = new Map();
this.currentState = null;
}
addState(name, state) {
this.states.set(name, state);
state.machine = this;
}
setState(name) {
const newState = this.states.get(name);
if (newState && newState !== this.currentState) {
if (this.currentState) {
this.currentState.onExit();
}
this.currentState = newState;
this.currentState.onEnter();
}
}
update(delta) {
if (this.currentState) {
this.currentState.update(delta);
}
}
}
class State {
constructor() {
this.machine = null;
}
onEnter() {}
onExit() {}
update(delta) {}
}
// 示例:角色状态
class IdleState extends State {
onEnter() {
console.log('进入空闲状态');
}
update(delta) {
// 检查是否应该切换到其他状态
if (this.isMoving) {
this.machine.setState('walk');
}
}
onExit() {
console.log('离开空闲状态');
}
}
class WalkState extends State {
onEnter() {
console.log('进入行走状态');
}
update(delta) {
if (!this.isMoving) {
this.machine.setState('idle');
}
}
}
最佳实践 #
代码组织 #
text
项目结构建议:
├── src/
│ ├── main.js # 入口文件
│ ├── config.js # 配置文件
│ ├── scenes/ # 场景
│ │ ├── MenuScene.js
│ │ └── GameScene.js
│ ├── entities/ # 实体
│ │ ├── Player.js
│ │ └── Enemy.js
│ ├── components/ # 组件
│ │ ├── Sprite.js
│ │ └── Physics.js
│ ├── systems/ # 系统
│ │ ├── Input.js
│ │ └── Collision.js
│ ├── utils/ # 工具
│ │ ├── math.js
│ │ └── pool.js
│ └── assets/ # 资源配置
│ └── manifest.js
资源管理 #
javascript
// 资源清单
const assetManifest = {
bundles: [
{
name: 'preload',
assets: [
{ alias: 'loading', src: 'images/loading.png' }
]
},
{
name: 'game',
assets: [
{ alias: 'player', src: 'images/player.png' },
{ alias: 'enemy', src: 'images/enemy.png' },
{ alias: 'spritesheet', src: 'sprites/game.json' }
]
}
]
};
// 加载资源
async function loadAssets() {
await Assets.init({ manifest: assetManifest });
const preload = await Assets.loadBundle('preload');
showLoadingScreen(preload);
await Assets.loadBundle('game', onProgress);
}
响应式设计 #
javascript
function setupResponsive(app) {
const resize = () => {
const width = window.innerWidth;
const height = window.innerHeight;
app.renderer.resize(width, height);
// 更新游戏内容
updateGameLayout(width, height);
};
window.addEventListener('resize', resize);
resize();
}
错误处理 #
javascript
// 全局错误处理
window.onerror = (message, source, lineno, colno, error) => {
console.error('全局错误:', message);
// 上报错误
};
// Promise 错误
window.onunhandledrejection = (event) => {
console.error('未处理的 Promise 错误:', event.reason);
};
// 资源加载错误
try {
const texture = await Assets.load('image.png');
} catch (error) {
console.error('资源加载失败:', error);
// 使用默认资源
}
无障碍访问 #
javascript
// 添加 ARIA 标签
const button = new Container();
button.accessible = true;
button.accessibleTitle = '开始游戏';
button.accessibleHint = '点击开始新游戏';
// 键盘导航
button.eventMode = 'static';
button.on('keydown', (event) => {
if (event.key === 'Enter' || event.key === ' ') {
button.emit('click');
}
});
总结 #
恭喜你完成了 PixiJS 完全指南的学习!你已经掌握了:
- 基础概念:Application、Container、DisplayObject
- 图形绘制:Graphics API 绘制各种形状
- 文本处理:Text 和 BitmapText 的使用
- 交互事件:鼠标、触摸、键盘事件处理
- 动画系统:Ticker 和 Tween 动画
- 资源加载:Assets 加载器的使用
- 滤镜效果:内置和扩展滤镜
- 高级主题:性能优化、架构设计
继续实践,探索更多 PixiJS 的可能性!
最后更新:2026-03-29