
pixijs-scene-core-concepts
热门在整体推理 PixiJS v8 场景图时使用此技能:容器、叶子节点、变换和渲染顺序如何组合。涵盖叶子与容器的区别、局部/世界坐标、裁剪、渲染组、可排序子节点、遮罩、RenderLayer、每个场景节点共享的构造函数选项,以及每个叶子技能覆盖哪个显示对象。触发词:场景图、显示列表、Container、Sprite、Graphics、Text、Mesh、ParticleContainer、DOMContainer、GifSprite、遮罩、渲染组、RenderLayer、世界变换、构造函数选项、ContainerOptions。
在整体推理 PixiJS v8 场景图时使用此技能:容器、叶子节点、变换和渲染顺序如何组合。涵盖叶子与容器的区别、局部/世界坐标、裁剪、渲染组、可排序子节点、遮罩、RenderLayer、每个场景节点共享的构造函数选项,以及每个叶子技能覆盖哪个显示对象。触发词:场景图、显示列表、Container、Sprite、Graphics、Text、Mesh、ParticleContainer、DOMContainer、GifSprite、遮罩、渲染组、RenderLayer、世界变换、构造函数选项、ContainerOptions。
此技能是所有 pixijs-scene-* 叶子技能共享的心智模型。它解释 PixiJS v8 中的场景图是什么、Container 与叶子的区别,以及每个概念的位置。它不深入任何单个 API;而是勾勒各个部分并指向相应的技能或参考文件。
快速开始
const world = new Container({ isRenderGroup: true });
app.stage.addChild(world);
const hero = new Container({ label: "hero" });
hero.addChild(new Sprite(bodyTexture));
hero.addChild(new Sprite(faceTexture));
world.addChild(hero);
const mask = new Graphics().rect(0, 0, 800, 600).fill(0xffffff);
world.mask = mask;
world.addChild(mask);
hero.position.set(world.width / 2, world.height / 2);
相关技能: pixijs-scene-container(Container API 详解)、叶子技能(pixijs-scene-sprite、pixijs-scene-graphics、pixijs-scene-text、pixijs-scene-mesh、pixijs-scene-particle-container、pixijs-scene-dom-container、pixijs-scene-gif)、pixijs-events(命中测试遍历场景图)、pixijs-performance(缓存、裁剪、渲染组)、pixijs-math(Matrix、toGlobal/toLocal 详解)。
核心概念
场景图是什么
PixiJS 场景图是一棵以 app.stage 为根的显示对象树。每个节点都有一个父节点、一个相对于父节点的变换(位置、缩放、旋转、锚点、倾斜),以及可选的视觉状态(alpha、色调、混合模式、可见性)。每帧渲染器遍历树,将变换和视觉状态组合到世界空间,裁剪屏幕外的内容,并发出绘制调用。场景图既是布局模型也是渲染顺序:较早的兄弟节点绘制在较晚的兄弟节点之后。
v8 中的每个显示对象都是 Container 的子类。早期版本中的 DisplayObject 已被移除。
容器与叶子(关键)
树中有两种角色:
- 容器:持有子节点的节点。对于任何分组、定位或变换其他节点的节点,使用
Container(或RenderLayer)。 - 叶子:绘制某些内容且没有子节点的节点。使用
Sprite、Graphics、Text、Mesh、ParticleContainer的Particle、DOMContainer或GifSprite作为叶子。
在 PixiJS v8 中,叶子不能有子节点。向 Sprite / Graphics / Text / Mesh 添加子节点会记录弃用警告,并计划成为硬错误。规则是:对于任何需要子节点的节点,使用 Container;不要在叶子场景对象内部嵌套子节点。 如果需要将叶子与其他叶子分组,将它们包装在 Container 中。
这个区别就是为什么 pixijs-scene-* 技能如此划分:pixijs-scene-container 覆盖分组节点,每个叶子都有自己的技能专注于其绘制行为。
变换与坐标空间
每个容器从其 position、scale、rotation、pivot 和 skew 组合出一个 localTransform(一个 Matrix)。渲染器将父节点的局部变换相乘,产生 worldTransform(如果链中有渲染组,还有 groupTransform),它将局部点映射到场景根空间。使用 toGlobal(point) 和 toLocal(point, from?) 在空间之间转换,使用 getGlobalPosition() 获取此对象的世界位置。完整的 Matrix 细节在 pixijs-math 中;变换设置器和 toLocal/toGlobal 在 pixijs-scene-container 中。
渲染顺序与显式 z 排序
子节点按数组顺序渲染:索引 0 最先,最后一个索引最后。对于单个容器上的显式 z 排序,设置 sortableChildren = true 并为子节点分配 zIndex 值。对于与逻辑层次结构解耦的渲染顺序(例如,角色的父节点是游戏世界,但其绘制发生在 UI 层上),使用 RenderLayer。何时优先使用可排序子节点与 RenderLayer 的深入细节在 references/scene-management.md 中。
渲染组
将容器标记为 isRenderGroup: true(或调用 container.enableRenderGroup())告诉 PixiJS 将其变换作为单个矩阵在 GPU 上应用,而不是每帧在 CPU 上重新计算每个后代的 world transform。在大型、稳定的子树(如世界、UI 层或视差条)上使用渲染组。深入细节在 references/scene-management.md 中。
裁剪
cullable = true + cullArea: Rectangle 告诉 CullerPlugin(或任何裁剪过程)跳过渲染落在可见区域之外的对象。cullableChildren = false 为子节点始终在屏幕上的子树短路递归裁剪。裁剪是一个性能主题;pixijs-performance 和 references/scene-management.md 涵盖了权衡。
遮罩
设置 container.mask 为另一个显示对象以裁剪其渲染。PixiJS 自动选择遮罩类型:Graphics 或 Container 遮罩使用模板缓冲,Sprite 遮罩使用 alpha 滤镜,数字选择 ColorMask。所有四种遮罩类型(AlphaMask、StencilMask、ScissorMask、ColorMask)在 references/masking.md 中都有介绍。
可见性、alpha、色调和混合模式
visible = false 跳过渲染和变换更新;renderable = false 跳过渲染但仍更新变换(当命中测试或边界查询需要保持活动时使用)。alpha 和 tint 向下乘到子树;blendMode 控制此容器的绘制指令如何与目标上已有的内容合成。完整的混合模式列表见 pixijs-blend-modes,每个节点的状态见 pixijs-scene-container。
销毁语义
container.destroy() 取消链接一个节点。container.destroy({ children: true }) 递归销毁整个子树;销毁分支时始终使用此方法。texture: true 和 textureSource: true 额外销毁叶子拥有的 GPU 资源。如果启用了 cacheAsTexture,在销毁前禁用它。pixijs-scene-container 记录了完整签名。
生命周期事件
容器为层次结构和可见性变化发出事件:父节点上的 childAdded / childRemoved,子节点上的 added / removed,以及容器本身的 visibleChanged 和 destroyed。用于连接响应式 UI 更新或资源记账。完整细节在 references/container-hierarchy.md 中。
叶子比较:哪个技能覆盖哪个对象
| 叶子 | 主要用途 | 技能 |
|---|---|---|
Sprite |
在某个位置绘制单个纹理(变体 NineSliceSprite 用于可调整大小的 UI 面板,TilingSprite 用于重复背景)。 |
pixijs-scene-sprite |
Text / BitmapText / HTMLText / SplitText / SplitBitmapText |
渲染文本。基于 Canvas 的 Text 用于一般用途,BitmapText 用于高吞吐量廉价文本,HTMLText 用于富 HTML/CSS 布局,分割变体用于逐字符动画。 |
pixijs-scene-text |
Graphics |
矢量绘制:形状、线条、路径、填充、描边。由 GraphicsContext 支持。 |
pixijs-scene-graphics |
Mesh / MeshSimple / MeshPlane / MeshRope / PerspectiveMesh |
带有着色器或纹理的自定义几何体。使用 MeshRope 用于纹理路径跟随的带状,PerspectiveMesh 用于 2D 透视。 |
pixijs-scene-mesh |
ParticleContainer + Particle |
数千个轻量级精灵,具有受限的变换集,用于高吞吐量粒子效果。 | pixijs-scene-particle-container |
DOMContainer |
在场景图内定位的 HTML 元素渲染(用于输入、iframe、无障碍覆盖)。 | pixijs-scene-dom-container |
GifSprite |
作为显示对象的动画 GIF 播放。需要 pixi.js/gif。 |
pixijs-scene-gif |
Container 本身在 pixijs-scene-container 中介绍,是每个叶子所在的节点。
何时使用什么(快速决策)
- “我想分组并变换一些显示对象” →
Container,见pixijs-scene-container。 - “我想绘制一个纹理” →
Sprite,见pixijs-scene-sprite。 - “我想绘制矢量形状或路径” →
Graphics,见pixijs-scene-graphics。 - “我想绘制文本” →
Text/BitmapText/HTMLText,见pixijs-scene-text。 - “我想要数千个廉价精灵” →
ParticleContainer,见pixijs-scene-particle-container。 - “我想要一个自定义几何体网格或变形精灵” →
Mesh或其变体之一,见pixijs-scene-mesh。 - “我想裁剪一个子树” → 设置
.mask,见references/masking.md。 - “我想要解耦的渲染顺序” →
RenderLayer,见references/scene-management.md。 - “我想要一个大型稳定子树的 GPU 级变换” →
isRenderGroup: true,见references/scene-management.md。 - “我想跳过屏幕外渲染” →
cullable = true+CullerPlugin,见pixijs-performance。
参考
- references/constructor-options.md:每个
Container派生节点继承的约 30 个字段(变换、显示、层次结构、排序、布局、效果、回调),包含默认值、类型以及何时适合逐行赋值。所有叶子技能的共享参考。 - references/container-hierarchy.md:添加/移除/交换子节点、保留变换的重新父级、标签导航、销毁子树。
- references/transforms.md:位置、缩放、旋转、锚点、原点、倾斜、toGlobal/toLocal、三个矩阵(局部/组/世界)、边界。
- references/masking.md:AlphaMask、StencilMask、ScissorMask、ColorMask、反向遮罩、成本比较。
- references/layers.md:
RenderLayer、附加/分离、排序层、层与逻辑父级分离。 - references/render-groups.md:
isRenderGroup、GPU 级变换、何时使用、渲染组与cacheAsTexture。 - references/scene-management.md:综合视图;渲染组、
RenderLayer、裁剪、zIndex 排序、boundsArea。
常见错误
[关键] 向叶子显示对象添加子节点
错误:
const sprite = new Sprite(texture);
sprite.addChild(new Graphics().rect(0, 0, 10, 10).fill(0xff0000));
正确:
const group = new Container();
group.addChild(new Sprite(texture));
group.addChild(new Graphics().rect(0, 0, 10, 10).fill(0xff0000));
在 v8 中,叶子(Sprite、Graphics、Text、Mesh、ParticleContainer、DOMContainer、GifSprite)技术上扩展了 Container,但不应持有子节点。向叶子添加子节点会产生未定义的渲染行为。当需要分组时,将叶子包装在 Container 中。
[关键] 引用 DisplayObject
错误:
import { DisplayObject } from "pixi.js"; // v8 中没有此导出
function moveNode(node: DisplayObject) {
node.x += 1;
}
正确:
import { Container } from "pixi.js";
function moveNode(node: Container) {
node.x += 1;
}
DisplayObject 在 v8 中被移除。每个显示对象——包括 Sprite、Graphics、Text、Mesh——现在都是 Container 的子类。使用 Container 作为基类型。
[高] 在大型静态子树上忘记 isRenderGroup
错误:
const world = new Container();
for (let i = 0; i < 5000; i++) {
world.addChild(new Sprite(texture));
}
app.stage.addChild(world);
正确:
const world = new Container({ isRenderGroup: true });
for (let i = 0; i < 5000; i++) {
world.addChild(new Sprite(texture));
}
app.stage.addChild(world);
没有 isRenderGroup: true,渲染器每帧重新组合每个子节点相对于其父节点的变换。将子树标记为渲染组会缓存变换和绘制状态,直到子节点发生变化,这对于大型或大部分静态的树至关重要。
[高] 将 child.x 视为世界空间
错误:
const enemy = new Container();
enemy.x = 500;
world.addChild(enemy);
world.x = 200;
console.log(enemy.x); // 500(局部),不是 700(世界)
正确:
const worldPos = enemy.toGlobal({ x: 0, y: 0 });
console.log(worldPos.x); // 700
Container.x/y/scale/rotation 是相对于父节点的局部值。使用 toGlobal(point) 计算世界空间坐标,或使用 getGlobalPosition() 获取容器在世界空间中的原点。世界变换不作为简单的 x/y 对暴露。
[中] 没有 zIndex 的 sortableChildren
错误:
const layer = new Container();
layer.sortableChildren = true;
layer.addChild(bg); // 无 zIndex
layer.addChild(mid); // 无 zIndex
layer.addChild(fg); // 无 zIndex
// 顺序不变——所有 zIndex 默认为 0
正确:
const layer = new Container();
layer.sortableChildren = true;
bg.zIndex = 0;
mid.zIndex = 10;
fg.zIndex = 20;
layer.addChild(bg, mid, fg);
sortableChildren 在渲染前按 zIndex 重新排序子节点,但仅当子节点实际具有不同的 zIndex 值时生效。仅设置父节点标志没有可见效果。
工具
PixiJS Devtools Chrome 扩展 允许您实时检查和操作正在运行的场景图。对于任何非平凡的布局或渲染顺序调试,请安装它。





