pixijs-performance
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseProfile before optimizing. PixiJS handles a lot of content well out of the box; browser DevTools Performance + GPU profiling should be your first move. Once you've found the bottleneck, apply the targeted pattern below (destroy, pool, batch, cache, or cull).
优化前先进行性能分析。PixiJS本身就能很好地处理大量内容;浏览器开发者工具的性能分析+GPU分析应该是你的首要操作。找到性能瓶颈后,应用以下针对性方案(销毁、池化、批处理、缓存或剔除)。
Quick Start
快速开始
ts
container.cacheAsTexture(true);
container.updateCacheTexture();
container.cacheAsTexture(false);
container.destroy({ children: true });
import { CullerPlugin, extensions } from "pixi.js";
extensions.add(CullerPlugin);
offscreenContainer.cullable = true;
offscreenContainer.cullArea = new Rectangle(0, 0, 256, 256);
// Tune GC via init options (ms). The `textureGC.*` properties are
// deprecated since 8.15.0 — use these on the Application init instead.
await app.init({ gcMaxUnusedTime: 60_000, gcFrequency: 30_000 });Related skills: (destroy options), (render groups, layers, culling), (BitmapText for dynamic content), (atlasing), (custom batchers).
pixijs-scene-containerpixijs-scene-core-conceptspixijs-scene-textpixijs-assetspixijs-custom-renderingts
container.cacheAsTexture(true);
container.updateCacheTexture();
container.cacheAsTexture(false);
container.destroy({ children: true });
import { CullerPlugin, extensions } from "pixi.js";
extensions.add(CullerPlugin);
offscreenContainer.cullable = true;
offscreenContainer.cullArea = new Rectangle(0, 0, 256, 256);
// 通过初始化选项调整GC(毫秒)。`textureGC.*`属性自8.15.0版本起已废弃——改为在Application初始化时使用这些配置。
await app.init({ gcMaxUnusedTime: 60_000, gcFrequency: 30_000 });相关技能: (销毁选项)、(渲染组、图层、剔除)、(用于动态内容的BitmapText)、(图集)、(自定义批处理器)。
pixijs-scene-containerpixijs-scene-core-conceptspixijs-scene-textpixijs-assetspixijs-custom-renderingCore Patterns
核心方案
Proper destroy with cleanup
带清理的正确销毁
ts
import { Sprite, Assets } from "pixi.js";
const texture = await Assets.load("character.png");
const sprite = new Sprite(texture);
// Destroy sprite only (preserve texture for reuse)
sprite.destroy();
// Destroy sprite AND its texture
sprite.destroy({ children: true, texture: true, textureSource: true });When done with a loaded asset entirely:
ts
Assets.unload("character.png");This removes it from the cache and unloads the GPU resource.
ts
import { Sprite, Assets } from "pixi.js";
const texture = await Assets.load("character.png");
const sprite = new Sprite(texture);
// 仅销毁精灵(保留纹理以供复用)
sprite.destroy();
// 销毁精灵及其纹理
sprite.destroy({ children: true, texture: true, textureSource: true });当完全不再使用某个已加载资源时:
ts
Assets.unload("character.png");这会将其从缓存中移除并卸载GPU资源。
Application destroy/recreate cycle
应用销毁/重建周期
ts
import { Application } from "pixi.js";
// Correct destroy that cleans global pools
app.destroy({ releaseGlobalResources: true });
const newApp = new Application();
await newApp.init({ width: 800, height: 600 });Without , pooled objects (batches, textures) from the old app leak into the new one, causing flickering and corruption.
releaseGlobalResources: truets
import { Application } from "pixi.js";
// 清理全局池的正确销毁方式
app.destroy({ releaseGlobalResources: true });
const newApp = new Application();
await newApp.init({ width: 800, height: 600 });如果不设置,旧应用中的池化对象(批处理、纹理)会泄漏到新应用中,导致闪烁和显示异常。
releaseGlobalResources: trueTexture garbage collection
纹理垃圾回收
PixiJS auto-collects unused textures and GPU resources via . Defaults: checks every 30 seconds, removes resources idle for 60 seconds. These are time-based (milliseconds).
GCSystemts
import { Application } from "pixi.js";
const app = new Application();
await app.init({
gcActive: true,
gcMaxUnusedTime: 120000, // idle time before cleanup in ms (default: 60000)
gcFrequency: 60000, // check interval in ms (default: 30000)
});For manual control:
ts
texture.source.unload(); // immediate GPU memory releasePixiJS通过自动回收未使用的纹理和GPU资源。默认设置:每30秒检查一次,移除闲置60秒的资源。这些配置基于时间(毫秒)。
GCSystemts
import { Application } from "pixi.js";
const app = new Application();
await app.init({
gcActive: true,
gcMaxUnusedTime: 120000, // 清理前的闲置时间(毫秒,默认值:60000)
gcFrequency: 60000, // 检查间隔(毫秒,默认值:30000)
});手动控制方式:
ts
texture.source.unload(); // 立即释放GPU内存PrepareSystem for GPU upload
用于GPU上传的PrepareSystem
Upload textures and graphics to GPU before rendering to avoid first-frame hitches:
ts
import "pixi.js/prepare";
import { Application, Assets } from "pixi.js";
const app = new Application();
await app.init();
// Don't render until assets are uploaded
app.stop();
const texture = await Assets.load("large-scene.png");
// Upload to GPU ahead of time
await app.renderer.prepare.upload(app.stage);
// Now rendering won't hitch on first frame
app.start();prepare.upload()在渲染前将纹理和图形上传到GPU,避免首帧卡顿:
ts
import "pixi.js/prepare";
import { Application, Assets } from "pixi.js";
const app = new Application();
await app.init();
// 资源上传完成前不要渲染
app.stop();
const texture = await Assets.load("large-scene.png");
// 提前上传到GPU
await app.renderer.prepare.upload(app.stage);
// 现在渲染首帧不会卡顿
app.start();prepare.upload()cacheAsTexture for performance
用于性能优化的cacheAsTexture
cacheAsTexture()When to use:
- Many static children (UI panels, decorative backgrounds, complex Graphics)
- Containers with expensive filters (cache the filter result)
- Large subtrees that rarely change
Tradeoffs:
- Uses GPU memory for the cached texture (larger containers = more memory)
- Max texture size is GPU-dependent (typically 4096x4096; check )
renderer.texture.maxTextureSize - Must call after modifying children
updateCacheTexture() - Combining with masks is fragile (see the masking skill)
ts
import { Container, Sprite } from "pixi.js";
const panel = new Container();
// ... add many static children ...
panel.cacheAsTexture(true);
// With options
panel.cacheAsTexture({ resolution: 2, antialias: true });
// Refresh after changes
panel.updateCacheTexture();
// MUST disable before destroying (see Common Mistakes below)
panel.cacheAsTexture(false);
panel.destroy();Avoid: toggling on/off repeatedly (constant re-caching negates benefits), caching sparse containers (negligible gain), caching containers larger than 4096x4096.
cacheAsTexture()适用场景:
- 包含大量静态子元素(UI面板、装饰背景、复杂Graphics)
- 带有昂贵滤镜的容器(缓存滤镜结果)
- 很少更改的大型子树
权衡点:
- 缓存纹理会占用GPU内存(容器越大,内存占用越多)
- 最大纹理尺寸取决于GPU(通常为4096x4096;可查看)
renderer.texture.maxTextureSize - 修改子元素后必须调用
updateCacheTexture() - 与遮罩结合使用时不稳定(请查看遮罩相关技能)
ts
import { Container, Sprite } from "pixi.js";
const panel = new Container();
// ... 添加大量静态子元素 ...
panel.cacheAsTexture(true);
// 带选项的配置
panel.cacheAsTexture({ resolution: 2, antialias: true });
// 修改后刷新缓存
panel.updateCacheTexture();
// 销毁前必须禁用(请查看下方常见错误)
panel.cacheAsTexture(false);
panel.destroy();避免: 反复开启/关闭(频繁重新缓存会抵消性能收益)、缓存稀疏容器(收益可忽略)、缓存尺寸超过4096x4096的容器。
Object recycling
对象复用
Reuse objects by changing their properties instead of destroy/recreate:
ts
import { Sprite, Container, Texture } from "pixi.js";
class BulletPool {
private _pool: Sprite[] = [];
private _container: Container;
constructor(container: Container) {
this._container = container;
}
public get(texture: Texture): Sprite {
let bullet = this._pool.pop();
if (!bullet) {
bullet = new Sprite(texture);
this._container.addChild(bullet);
}
bullet.texture = texture;
bullet.position.set(0, 0);
bullet.rotation = 0;
bullet.scale.set(1);
bullet.alpha = 1;
bullet.tint = 0xffffff;
bullet.blendMode = "normal";
bullet.visible = true;
return bullet;
}
public release(bullet: Sprite): void {
bullet.visible = false;
this._pool.push(bullet);
}
}Destroying and recreating is significantly more expensive than toggling and updating properties. GPU resources stay allocated; only scene graph visibility changes.
visible通过修改属性而非销毁/重建来复用对象:
ts
import { Sprite, Container, Texture } from "pixi.js";
class BulletPool {
private _pool: Sprite[] = [];
private _container: Container;
constructor(container: Container) {
this._container = container;
}
public get(texture: Texture): Sprite {
let bullet = this._pool.pop();
if (!bullet) {
bullet = new Sprite(texture);
this._container.addChild(bullet);
}
bullet.texture = texture;
bullet.position.set(0, 0);
bullet.rotation = 0;
bullet.scale.set(1);
bullet.alpha = 1;
bullet.tint = 0xffffff;
bullet.blendMode = "normal";
bullet.visible = true;
return bullet;
}
public release(bullet: Sprite): void {
bullet.visible = false;
this._pool.push(bullet);
}
}销毁和重建对象的成本远高于切换属性并更新其他属性。GPU资源会保持分配状态;仅场景图可见性发生变化。
visibleBatching optimization
批处理优化
PixiJS batches similar consecutive objects into single draw calls. Batch breaks occur on:
- Object type change (Sprite vs Graphics)
- Texture source change (beyond the per-batch texture limit, typically 16)
- Blend mode change
- Topology change
Optimize draw order:
ts
import { Sprite, Graphics, Container } from "pixi.js";
// 4 draw calls: type alternates
const bad = new Container();
bad.addChild(new Sprite(t1));
bad.addChild(new Graphics().rect(0, 0, 10, 10).fill(0xff0000));
bad.addChild(new Sprite(t2));
bad.addChild(new Graphics().rect(0, 0, 10, 10).fill(0x00ff00));
// 2 draw calls: types grouped
const good = new Container();
good.addChild(new Sprite(t1));
good.addChild(new Sprite(t2));
good.addChild(new Graphics().rect(0, 0, 10, 10).fill(0xff0000));
good.addChild(new Graphics().rect(0, 0, 10, 10).fill(0x00ff00));Same principle applies to blend modes: = 4 draws; = 2 draws.
screen/normal/screen/normalscreen/screen/normal/normalPixiJS会将相似的连续对象合并为单个绘制调用。以下情况会中断批处理:
- 对象类型变化(Sprite与Graphics)
- 纹理源变化(超出每批纹理限制,通常为16个)
- 混合模式变化
- 拓扑结构变化
优化绘制顺序:
ts
import { Sprite, Graphics, Container } from "pixi.js";
// 4次绘制调用:类型交替出现
const bad = new Container();
bad.addChild(new Sprite(t1));
bad.addChild(new Graphics().rect(0, 0, 10, 10).fill(0xff0000));
bad.addChild(new Sprite(t2));
bad.addChild(new Graphics().rect(0, 0, 10, 10).fill(0x00ff00));
// 2次绘制调用:类型分组
const good = new Container();
good.addChild(new Sprite(t1));
good.addChild(new Sprite(t2));
good.addChild(new Graphics().rect(0, 0, 10, 10).fill(0xff0000));
good.addChild(new Graphics().rect(0, 0, 10, 10).fill(0x00ff00));同样的原则适用于混合模式: = 4次绘制; = 2次绘制。
screen/normal/screen/normalscreen/screen/normal/normalSpritesheets over individual textures
使用精灵图集而非单个纹理
ts
import { Assets, Sprite } from "pixi.js";
// Load a spritesheet (single texture atlas)
const sheet = await Assets.load("game-atlas.json");
// All frames share one GPU texture; enables batching
const hero = new Sprite(sheet.textures["hero.png"]);
const enemy = new Sprite(sheet.textures["enemy.png"]);
const coin = new Sprite(sheet.textures["coin.png"]);Individual textures each require their own GPU upload and break batches when the texture limit is exceeded. Spritesheets consolidate many frames into one atlas texture.
Use filename suffix on half-resolution sheets so PixiJS auto-scales them.
@0.5xts
import { Assets, Sprite } from "pixi.js";
// 加载精灵图集(单个纹理 atlas)
const sheet = await Assets.load("game-atlas.json");
// 所有帧共享一个GPU纹理;支持批处理
const hero = new Sprite(sheet.textures["hero.png"]);
const enemy = new Sprite(sheet.textures["enemy.png"]);
const coin = new Sprite(sheet.textures["coin.png"]);单个纹理各自需要独立的GPU上传,且当超出纹理限制时会中断批处理。精灵图集将多个帧合并为一个 atlas 纹理。
使用带后缀的文件名作为半分辨率图集,PixiJS会自动缩放它们。
@0.5xText performance
文本性能
Text and HTMLText re-render to a canvas and re-upload to the GPU on every change. Never update them per frame unconditionally:
ts
import { BitmapText, Text } from "pixi.js";
// Wrong: re-renders canvas + GPU upload every frame
app.ticker.add(() => {
scoreText.text = `Score: ${score}`;
});
// Correct: use BitmapText for frequently changing content
const scoreText = new BitmapText({
text: "Score: 0",
style: { fontFamily: "Arial", fontSize: 24, fill: 0xffffff },
});
app.ticker.add(() => {
scoreText.text = `Score: ${score}`;
});BitmapText renders from a pre-generated glyph atlas. Updates only reposition quads; no canvas re-render or GPU upload. Use it for scores, timers, counters, and anything that changes frequently.
If you must use canvas Text, guard updates so they only happen when the value changes:
ts
app.ticker.add(() => {
const next = `Score: ${score}`;
if (scoreText.text !== next) {
scoreText.text = next;
}
});Text resolution matches the renderer resolution by default. Lower it independently via to reduce GPU memory on high-DPI displays.
text.resolution = 1Text和HTMLText在每次更改时都会重新渲染到画布并重新上传到GPU。绝不要无条件地逐帧更新它们:
ts
import { BitmapText, Text } from "pixi.js";
// 错误:逐帧重新渲染画布并上传GPU
app.ticker.add(() => {
scoreText.text = `Score: ${score}`;
});
// 正确:使用BitmapText处理频繁变化的内容
const scoreText = new BitmapText({
text: "Score: 0",
style: { fontFamily: "Arial", fontSize: 24, fill: 0xffffff },
});
app.ticker.add(() => {
scoreText.text = `Score: ${score}`;
});BitmapText基于预先生成的字形图集进行渲染。更新时仅重新定位四边形;无需重新渲染画布或上传GPU。将其用于分数、计时器、计数器以及任何频繁变化的内容。
如果必须使用画布Text,请添加判断,仅当值变化时才更新:
ts
app.ticker.add(() => {
const next = `Score: ${score}`;
if (scoreText.text !== next) {
scoreText.text = next;
}
});Text的分辨率默认与渲染器分辨率匹配。可通过设置独立降低分辨率,以减少高DPI显示器上的GPU内存占用。
text.resolution = 1Graphics performance
Graphics性能
Graphics objects are fastest when their shape doesn't change (transforms, alpha, and tint are fine). Small Graphics (under ~100 points) are batched like Sprites. Complex Graphics with hundreds of shapes are slow; convert them to textures instead:
ts
import { Graphics, Sprite } from "pixi.js";
const complex = new Graphics();
// ... draw complex shape ...
// Render once to texture, use as Sprite
const texture = app.renderer.generateTexture(complex);
const sprite = new Sprite(texture);当形状不变时,Graphics对象的性能最佳(变换、透明度和色调变化没问题)。小型Graphics(约100个点以下)可像Sprite一样高效批处理。包含数百个形状的复杂Graphics性能较慢;请将它们转换为纹理:
ts
import { Graphics, Sprite } from "pixi.js";
const complex = new Graphics();
// ... 绘制复杂形状 ...
// 渲染一次到纹理,作为Sprite使用
const texture = app.renderer.generateTexture(complex);
const sprite = new Sprite(texture);Culling
剔除
PixiJS skips rendering objects outside the visible area when is set. Disabled by default because it trades CPU cost (bounds checking) for GPU savings. Culling only runs when the is registered:
cullableCullerPlugints
import { extensions, CullerPlugin, Culler, Rectangle } from "pixi.js";
extensions.add(CullerPlugin); // before Application.init
// Enable on objects that may be off-screen
sprite.cullable = true;
// Optional: a pre-computed cull rectangle avoids per-frame bounds calculation.
// Without cullArea, the Culler uses the object's global bounds instead.
sprite.cullArea = new Rectangle(0, 0, 800, 600);
// Skip culling an entire subtree (static UI, always visible)
uiRoot.cullableChildren = false;
// Or cull manually without the plugin:
Culler.shared.cull(app.stage, app.renderer.screen);cullableChildrenCuller.shared.cull(container, rect)当设置后,PixiJS会跳过渲染可见区域外的对象。默认禁用该功能,因为它以CPU开销(边界检查)换取GPU资源节省。仅当注册后,剔除功能才会运行:
cullableCullerPlugints
import { extensions, CullerPlugin, Culler, Rectangle } from "pixi.js";
extensions.add(CullerPlugin); // 在Application.init之前注册
// 对可能移出屏幕的对象启用剔除
sprite.cullable = true;
// 可选:预计算的剔除矩形可避免逐帧计算边界。
// 如果不设置cullArea,Culler会使用对象的全局边界。
sprite.cullArea = new Rectangle(0, 0, 800, 600);
// 跳过整个子树的剔除(静态UI,始终可见)
uiRoot.cullableChildren = false;
// 或不使用插件手动执行剔除:
Culler.shared.cull(app.stage, app.renderer.screen);容器上的会阻止剔除器递归处理其子元素;这对包含大量子元素的静态UI面板来说是很大的性能提升。可为自定义渲染管道手动执行相同逻辑。当GPU性能受限使用剔除;CPU性能受限时避免使用,因为每个对象的边界检查会增加开销。
cullableChildrenCuller.shared.cull(container, rect)Resolution and antialias tradeoffs
分辨率与抗锯齿的权衡
ts
import { Application } from "pixi.js";
const app = new Application();
// Mobile-friendly: lower resolution, no antialias
await app.init({
resolution: 1,
antialias: false,
backgroundAlpha: 1, // opaque background is faster
});resolution: 2ts
import { Application } from "pixi.js";
const app = new Application();
// 移动端友好:低分辨率,无抗锯齿
await app.init({
resolution: 1,
antialias: false,
backgroundAlpha: 1, // 不透明背景性能更高
});resolution: 2Stagger bulk texture destruction
分批销毁大量纹理
ts
function staggerDestroy(textures: Texture[], perFrame: number = 5): void {
let index = 0;
const ticker = app.ticker;
const destroy = () => {
const end = Math.min(index + perFrame, textures.length);
for (let i = index; i < end; i++) {
textures[i].destroy(true);
}
index = end;
if (index >= textures.length) {
ticker.remove(destroy);
}
};
ticker.add(destroy);
}Destroying many textures in one frame causes a freeze. Spread the cost across frames.
ts
function staggerDestroy(textures: Texture[], perFrame: number = 5): void {
let index = 0;
const ticker = app.ticker;
const destroy = () => {
const end = Math.min(index + perFrame, textures.length);
for (let i = index; i < end; i++) {
textures[i].destroy(true);
}
index = end;
if (index >= textures.length) {
ticker.remove(destroy);
}
};
ticker.add(destroy);
}在一帧内销毁大量纹理会导致卡顿。将销毁成本分散到多个帧中。
Filters and masks cost
滤镜与遮罩的开销
- Set when you know the bounds. Without it, PixiJS measures bounds every frame.
container.filterArea = new Rectangle(x, y, w, h) - Release filter memory: .
container.filters = null - Mask cost (cheapest to most expensive): axis-aligned Rectangle masks (scissor rect) < Graphics masks (stencil buffer) < Sprite/alpha masks (filter pipeline). Hundreds of masks will slow things down regardless of type; prefer rectangle masks when bounds are axis-aligned.
- Set on containers with no interactive children.
interactiveChildren = false - Set on large containers to skip recursive child hit testing.
hitArea
- 当知道边界时,设置。如果不设置,PixiJS会逐帧测量边界。
container.filterArea = new Rectangle(x, y, w, h) - 释放滤镜内存:。
container.filters = null - 遮罩开销(从最低到最高):轴对齐矩形遮罩(裁剪矩形) < Graphics遮罩(模板缓冲区) < Sprite/alpha遮罩(滤镜管道)。无论类型如何,数百个遮罩都会降低性能;当边界为轴对齐时,优先使用矩形遮罩。
- 在没有交互子元素的容器上设置。
interactiveChildren = false - 在大型容器上设置,跳过递归子元素命中测试。
hitArea
Safe destroy order
安全的销毁顺序
Remove from scene before destroying:
ts
parent.removeChild(sprite);
sprite.destroy();Destroying while the render pipeline still holds a reference causes null-pointer crashes. If destruction must happen mid-frame, defer it:
ts
app.ticker.addOnce(() => {
parent.removeChild(sprite);
sprite.destroy();
});先从场景中移除再销毁:
ts
parent.removeChild(sprite);
sprite.destroy();当渲染管道仍持有引用时销毁对象会导致空指针崩溃。如果必须在帧中间销毁,请延迟执行:
ts
app.ticker.addOnce(() => {
parent.removeChild(sprite);
sprite.destroy();
});Common Mistakes
常见错误
[CRITICAL] App destroy without releaseGlobalResources
[严重] 未设置releaseGlobalResources销毁应用
Wrong:
ts
app.destroy();
const newApp = new Application();Correct:
ts
app.destroy({ releaseGlobalResources: true });
const newApp = new Application();Without this flag, stale pooled batches and textures from the old app persist in global pools and get reused by the new app, causing flickering and visual corruption.
错误示例:
ts
app.destroy();
const newApp = new Application();正确示例:
ts
app.destroy({ releaseGlobalResources: true });
const newApp = new Application();如果不设置该标志,旧应用中过时的池化批处理和纹理会保留在全局池中,并被新应用复用,导致闪烁和显示异常。
[HIGH] Interleaving object types in scene graph
[高风险] 场景图中交错排列不同类型的对象
sprite / graphic / sprite / graphicsprite / sprite / graphic / graphicGroup same object types together in the child order to minimize batch breaks. Same applies to blend mode ordering.
sprite / graphic / sprite / graphicsprite / sprite / graphic / graphic在子元素顺序中将相同类型的对象分组,以最小化批处理中断。同样的原则适用于混合模式排序。
[HIGH] Destroying and recreating objects instead of recycling
[高风险] 销毁并重建对象而非复用
Destroy/recreate is expensive: it deallocates GPU resources, triggers garbage collection, and requires fresh GPU uploads. Reuse objects by updating , , , and other properties. Use an object pool pattern for frequently spawned/despawned entities.
texturepositionvisible销毁/重建成本很高:它会释放GPU资源、触发垃圾回收,并且需要重新上传GPU资源。通过更新、、和其他属性来复用对象。对频繁生成/销毁的实体使用对象池模式。
texturepositionvisible[HIGH] Loading many individual textures instead of spritesheets
[高风险] 加载大量单个纹理而非精灵图集
Each separate texture consumes its own GPU memory slot and breaks batching when the per-batch texture limit is reached. Spritesheets consolidate textures into atlases. Also avoid textures exceeding 4096px on either axis, as they fail on some mobile GPUs.
每个单独的纹理都会占用自己的GPU内存槽,当超出每批纹理限制时会中断批处理。精灵图集将纹理合并为atlas。同时避免使用任何轴向上尺寸超过4096px的纹理,因为它们在某些移动GPU上无法正常工作。
[HIGH] Updating Text or HTMLText every frame
[高风险] 逐帧更新Text或HTMLText
Each update re-renders the full string to a canvas and uploads to the GPU. At 60fps this creates massive overhead. Use BitmapText for dynamic content (scores, timers, counters). If canvas Text is required, only update when the value actually changes. Source: src/docs/concepts/performance-tips.md
每次更新都会将整个字符串重新渲染到画布并上传到GPU。在60fps下这会产生巨大的性能开销。对动态内容(分数、计时器、计数器)使用BitmapText。如果必须使用画布Text,仅当值实际变化时才更新。来源:src/docs/concepts/performance-tips.md
[HIGH] Using complex Graphics instead of textures
[高风险] 使用复杂Graphics而非纹理
Hundreds of complex Graphics objects are slow to render. Small Graphics (under ~100 points) batch efficiently like Sprites, but complex ones do not. Render complex static shapes to a texture with and display as a Sprite. Source: src/docs/concepts/performance-tips.md
renderer.generateTexture()数百个复杂Graphics对象的渲染速度很慢。小型Graphics(约100个点以下)可像Sprite一样高效批处理,但复杂Graphics不行。使用将复杂静态形状渲染为纹理,并以Sprite形式显示。来源:src/docs/concepts/performance-tips.md
renderer.generateTexture()[MEDIUM] Not staggering bulk texture destruction
[中风险] 未分批销毁大量纹理
Destroying dozens of textures in a single frame causes a visible freeze. Spread destruction across multiple frames (e.g., 5 per frame via a ticker callback). Source: src/docs/concepts/garbage-collection.md
在一帧内销毁数十个纹理会导致明显卡顿。将销毁操作分散到多个帧中(例如,通过ticker回调每帧销毁5个)。来源:src/docs/concepts/garbage-collection.md
[MEDIUM] Not using PrepareSystem for large scenes
[中风险] 未对大型场景使用PrepareSystem
Without , textures upload to the GPU on first render, causing frame hitches. For loading screens or scene transitions, upload before displaying. Requires (not included even in the default bundle; always import it explicitly). Source: src/prepare/PrepareSystem.ts
renderer.prepare.upload()import 'pixi.js/prepare'如果不使用,纹理会在首次渲染时上传到GPU,导致帧卡顿。对于加载屏幕或场景过渡,请在显示前完成上传。需要(即使在默认包中也未包含;请始终显式导入)。来源:src/prepare/PrepareSystem.ts
renderer.prepare.upload()import 'pixi.js/prepare'[MEDIUM] Using high resolution or antialias without profiling
[中风险] 未进行性能分析就使用高分辨率或抗锯齿
resolution: 2antialias: trueresolution: 2antialias: true