pixijs-rendering

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

PixiJS v8 Rendering

PixiJS v8 渲染

Set up and structure a PixiJS v8 application: the async
Application
, asset loading via
Assets
, the
Container
/
Sprite
scene graph, the ticker loop, pointer events, and render groups. Pins the v8 API (async
init
, unified
Assets
,
eventMode
).
搭建并构建PixiJS v8应用:异步
Application
、通过
Assets
加载资源、
Container
/
Sprite
场景图、ticker循环、指针事件以及渲染组。锁定v8 API(异步
init
、统一的
Assets
eventMode
)。

When to use

使用场景

  • Use when starting a PixiJS v8 project, fixing a blank canvas, structuring the display list, loading textures, animating via the ticker, or handling pointer input.
  • Use when
    package.json
    depends on
    pixi.js
    (v8) and code does
    import { Application } from 'pixi.js'
    .
When not to use: Phaser's scene/loader model →
phaser-core
. 3D scenes →
threejs-scene-setup
. PixiJS v7-and-earlier code (synchronous
new Application({...})
,
Loader
,
interactive = true
) needs the v8 migration first; this skill targets v8 only.
  • 适用于启动PixiJS v8项目、修复空白画布问题、构建显示列表、加载纹理、通过ticker实现动画或处理指针输入时使用。
  • 适用于
    package.json
    依赖
    pixi.js
    (v8版本)且代码中包含
    import { Application } from 'pixi.js'
    的场景。
不适用于: Phaser的场景/加载器模型 → 请使用
phaser-core
。3D场景 → 请使用
threejs-scene-setup
。PixiJS v7及更早版本的代码(同步
new Application({...})
Loader
interactive = true
)需要先进行v8迁移;本技能仅针对v8版本。

Core workflow

核心工作流程

  1. Create and
    await
    the Application.
    In v8,
    new Application()
    is empty; configuration happens in
    await app.init({...})
    . Append
    app.canvas
    (not
    app.view
    ) to the DOM. Wrap top-level
    await
    in an async function for bundlers.
  2. Load assets with
    Assets
    .
    await Assets.load(url)
    returns a
    Texture
    . For many assets, register a manifest/bundle and load by name. There is no v7
    Loader
    .
  3. Build the scene graph. Everything descends from
    app.stage
    (a
    Container
    ). Group related objects in
    Container
    s; child transforms are relative to the parent. Draw order = insertion order (later = on top).
  4. Animate with the ticker.
    app.ticker.add((ticker) => {...})
    . Scale motion by
    ticker.deltaTime
    (frames, ~1 at 60fps) or
    ticker.deltaMS
    (milliseconds) so speed is frame-rate independent.
  5. Enable events per object by setting
    eventMode = 'static'
    (or
    'dynamic'
    ), then
    obj.on('pointerdown', ...)
    . Federated pointer events cover mouse/touch/pen.
  6. Promote big static subtrees to render groups (
    isRenderGroup: true
    ) so the GPU caches their transforms. Profile before and after; confirm pixels on screen.
  1. 创建并
    await
    Application实例
    。在v8版本中,
    new Application()
    会创建空实例;配置需在
    await app.init({...})
    中完成。将
    app.canvas
    (而非
    app.view
    )添加到DOM中。对于打包工具,需将顶层
    await
    包裹在异步函数中。
  2. 使用
    Assets
    加载资源
    await Assets.load(url)
    会返回一个
    Texture
    。若需加载多个资源,可注册清单/资源包并通过名称加载。v8版本已移除v7中的
    Loader
  3. 构建场景图。所有元素都从
    app.stage
    (一个
    Container
    )派生。将相关对象分组到
    Container
    中;子元素的变换相对于父元素。绘制顺序等于插入顺序(后插入的元素在上方)。
  4. 通过ticker实现动画
    app.ticker.add((ticker) => {...})
    。使用
    ticker.deltaTime
    (帧数,60fps下约为1)或
    ticker.deltaMS
    (自上一帧以来的毫秒数)缩放运动,确保速度不受帧率影响。
  5. 为每个对象启用事件:设置
    eventMode = 'static'
    (或
    'dynamic'
    ),然后通过
    obj.on('pointerdown', ...)
    绑定事件。联合指针事件涵盖鼠标/触摸/手写笔操作。
  6. 将大型静态子树提升为渲染组(设置
    isRenderGroup: true
    ),让GPU缓存其变换。请在使用前后进行性能分析;确认屏幕上的像素显示正常。

Patterns

实现模式

1. Async Application boot (the v8 entry point)

1. 异步Application启动(v8入口)

js
import { Application, Assets, Sprite } from 'pixi.js';

(async () => {
  // v8: construct empty, then await init(). Config does NOT go in the constructor.
  const app = new Application();
  await app.init({
    background: '#1099bb',
    resizeTo: window,        // track the window size
    antialias: true,
    // preference: 'webgpu',  // opt into WebGPU; default 'webgl'
  });

  document.body.appendChild(app.canvas); // v8 uses app.canvas, not app.view

  const texture = await Assets.load('https://pixijs.com/assets/bunny.png');
  const bunny = new Sprite(texture);
  bunny.anchor.set(0.5);
  bunny.position.set(app.screen.width / 2, app.screen.height / 2);
  app.stage.addChild(bunny);
})();
js
import { Application, Assets, Sprite } from 'pixi.js';

(async () => {
  // v8:先构造空实例,再await init()。配置参数不能放在构造函数中。
  const app = new Application();
  await app.init({
    background: '#1099bb',
    resizeTo: window,        // 跟踪窗口大小
    antialias: true,
    // preference: 'webgpu',  // 选择WebGPU;默认使用WebGL
  });

  document.body.appendChild(app.canvas); // v8使用app.canvas,而非app.view

  const texture = await Assets.load('https://pixijs.com/assets/bunny.png');
  const bunny = new Sprite(texture);
  bunny.anchor.set(0.5);
  bunny.position.set(app.screen.width / 2, app.screen.height / 2);
  app.stage.addChild(bunny);
})();

2. Containers for a relative-transform scene graph

2. 使用Container构建相对变换场景图

js
import { Container, Sprite } from 'pixi.js';

const world = new Container();
app.stage.addChild(world);

// Children are positioned relative to `world`; move/scale/rotate the whole group
// by transforming the parent.
for (let i = 0; i < 10; i++) {
  const coin = new Sprite(coinTexture);
  coin.x = i * 40;
  world.addChild(coin);
}
world.position.set(100, 100);
world.scale.set(2);            // every coin scales with the container
js
import { Container, Sprite } from 'pixi.js';

const world = new Container();
app.stage.addChild(world);

// 子元素相对于`world`定位;通过变换父元素来移动/缩放/旋转整个组
for (let i = 0; i < 10; i++) {
  const coin = new Sprite(coinTexture);
  coin.x = i * 40;
  world.addChild(coin);
}
world.position.set(100, 100);
world.scale.set(2);            // 所有硬币会随容器一起缩放

3. The ticker loop (frame-rate independent)

3. Ticker循环(帧率无关)

js
let elapsed = 0;
app.ticker.add((ticker) => {
  // deltaTime ≈ 1 at 60fps; deltaMS is milliseconds since last frame.
  elapsed += ticker.deltaMS;
  bunny.rotation += 0.05 * ticker.deltaTime;          // smooth at any frame rate
  bunny.y = app.screen.height / 2 + Math.sin(elapsed / 500) * 50;
});
js
let elapsed = 0;
app.ticker.add((ticker) => {
  // deltaTime在60fps下约为1;deltaMS是自上一帧以来的毫秒数。
  elapsed += ticker.deltaMS;
  bunny.rotation += 0.05 * ticker.deltaTime;          // 在任意帧率下保持流畅
  bunny.y = app.screen.height / 2 + Math.sin(elapsed / 500) * 50;
});

4. Pointer events (federated)

4. 指针事件(联合事件)

js
bunny.eventMode = 'static';   // 'static' = interactive, doesn't move on its own
bunny.cursor = 'pointer';
bunny.on('pointerdown', (event) => {
  bunny.tint = 0xff0000;
  // event.global is the pointer position in stage space.
});
bunny.on('pointerover', () => bunny.scale.set(1.1));
bunny.on('pointerout',  () => bunny.scale.set(1.0));
js
bunny.eventMode = 'static';   // 'static' = 可交互,自身不移动
bunny.cursor = 'pointer';
bunny.on('pointerdown', (event) => {
  bunny.tint = 0xff0000;
  // event.global是指针在舞台空间中的位置。
});
bunny.on('pointerover', () => bunny.scale.set(1.1));
bunny.on('pointerout',  () => bunny.scale.set(1.0));

5. Loading many assets by name (bundles)

5. 通过名称加载多个资源(资源包)

js
import { Assets } from 'pixi.js';

await Assets.init({
  manifest: {
    bundles: [{
      name: 'level-1',
      assets: [
        { alias: 'hero',  src: 'assets/hero.png' },
        { alias: 'tiles', src: 'assets/tiles.png' },
      ],
    }],
  },
});

const bundle = await Assets.loadBundle('level-1'); // { hero: Texture, tiles: Texture }
const hero = new Sprite(bundle.hero);
js
import { Assets } from 'pixi.js';

await Assets.init({
  manifest: {
    bundles: [{
      name: 'level-1',
      assets: [
        { alias: 'hero',  src: 'assets/hero.png' },
        { alias: 'tiles', src: 'assets/tiles.png' },
      ],
    }],
  },
});

const bundle = await Assets.loadBundle('level-1'); // { hero: Texture, tiles: Texture }
const hero = new Sprite(bundle.hero);

6. Render groups for large static layers

6. 为大型静态层使用渲染组

js
// A big, rarely-changing background subtree: let the GPU cache its transforms.
const background = new Container({ isRenderGroup: true });
app.stage.addChild(background);
// Add hundreds of static tiles to `background`. Moving `background` itself stays
// cheap; constantly re-adding/removing children negates the benefit.
js
// 大型、极少变更的背景子树:让GPU缓存其变换。
const background = new Container({ isRenderGroup: true });
app.stage.addChild(background);
// 向`background`添加数百个静态瓦片。移动`background`本身的开销很低;频繁添加/移除子元素会抵消该优化的收益。

Pitfalls

常见陷阱

  • Blank canvas / "app.stage is undefined" → you didn't
    await app.init()
    , or you configured the constructor. In v8 the constructor is empty; all options go to
    init()
    .
  • app.view
    is undefined
    → v8 renamed it to
    app.canvas
    .
  • v7 code throwing
    interactive = true
    eventMode = 'static'
    ;
    Loader
    /
    loader.add
    Assets.load
    ; synchronous
    new Application({...})
    → async
    init
    .
  • Top-level await build error (Vite ≤6.0.6) → wrap boot in
    (async () => { ... })()
    .
  • Speed varies with frame rate → multiply movement by
    ticker.deltaTime
    (or use
    deltaMS
    ); never assume 60fps.
  • Clicks do nothing → the object's
    eventMode
    is still
    'none'
    (the default); set it to
    'static'
    or
    'dynamic'
    .
  • Textures look blurry on pixel art → set
    texture.source.scaleMode = 'nearest'
    (or pass it when loading).
  • Memory grows
    removeChild
    does not free GPU memory; call
    sprite.destroy()
    and
    Assets.unload(url)
    for assets you're done with.
  • 空白画布 / "app.stage is undefined" → 你没有
    await app.init()
    ,或者在构造函数中传入了配置。v8版本的构造函数是空的;所有选项都要传入
    init()
  • app.view
    未定义
    → v8版本已将其重命名为
    app.canvas
  • v7代码报错 → 将
    interactive = true
    改为
    eventMode = 'static'
    ;将
    Loader
    /
    loader.add
    改为
    Assets.load
    ;将同步
    new Application({...})
    改为异步
    init
  • 顶层await构建错误(Vite ≤6.0.6) → 将启动代码包裹在
    (async () => { ... })()
    中。
  • 速度随帧率变化 → 运动数值乘以
    ticker.deltaTime
    (或使用
    deltaMS
    );永远不要假设帧率是60fps。
  • 点击无响应 → 对象的
    eventMode
    仍为默认值
    'none'
    ;需将其设置为
    'static'
    'dynamic'
  • 像素艺术纹理模糊 → 设置
    texture.source.scaleMode = 'nearest'
    (或在加载时传入该参数)。
  • 内存持续增长
    removeChild
    不会释放GPU内存;对于不再使用的资源,需调用
    sprite.destroy()
    Assets.unload(url)

References

参考资料

  • For the texture/asset pipeline (sprite sheets/atlases,
    Assets.add
    , background loading, unloading) and Graphics/Text/
    TilingSprite
    /
    ParticleContainer
    plus filters, read
    references/assets-and-display.md
    .
  • 关于纹理/资源流水线(精灵图/图集、
    Assets.add
    、后台加载、卸载)以及Graphics/Text/
    TilingSprite
    /
    ParticleContainer
    和滤镜的内容,请阅读
    references/assets-and-display.md

Related skills

相关技能

  • phaser-core
    — a batteries-included 2D framework (scenes, physics, input).
  • threejs-scene-setup
    — 3D in the browser with three.js.
  • prototype-fast
    — greybox a playable slice quickly (often cites PixiJS).
  • phaser-core
    — 功能完备的2D框架(包含场景、物理、输入系统)。
  • threejs-scene-setup
    — 使用three.js在浏览器中实现3D效果。
  • prototype-fast
    — 快速构建可玩的原型切片(常引用PixiJS)。