pixijs-scene-container

Par pixijs · pixijs-skills

Utilisez cette skill pour regrouper, positionner ou transformer des objets d'affichage dans PixiJS v8. Couvre les options du constructeur Container (`isRenderGroup`, `sortableChildren`, `boundsArea`), `addChild`/`removeChild`/`addChildAt`/`swapChildren`/`setChildIndex`, `position`/`scale`/`rotation`/`pivot`/`skew`/`alpha`/`tint`, `getBounds`/`getGlobalPosition`/`toLocal`/`toGlobal`, le tri par `zIndex`, `cullable`, le callback par frame `onRender`, `destroy`. Se déclenche sur : `Container`, `addChild`, `removeChild`, `addChildAt`, `swapChildren`, `sortableChildren`, `zIndex`, `position`, `scale`, `rotation`, `pivot`, `getBounds`, `toGlobal`, `toLocal`, `onRender`, `destroy`, options du constructeur, `ContainerOptions`.

npx skills add https://github.com/pixijs/pixijs-skills --skill pixijs-scene-container

Container est le nœud polyvalent du graphe de scène PixiJS v8. Il contient des enfants et applique des transformations, de l'alpha, une teinte et un mode de mélange à tout son sous-arbre. Chaque objet d'affichage que vous créez sera soit un Container sur lequel vous construisez une branche, soit une feuille (Sprite, Graphics, Text, Mesh) que vous imbriquez à l'intérieur.

Suppose une familiarité avec pixijs-scene-core-concepts.

Démarrage rapide

const group = new Container({
  label: "hero-group",
  x: 200,
  y: 150,
  sortableChildren: true,
});

const body = new Sprite(await Assets.load("body.png"));
const head = new Sprite(await Assets.load("head.png"));
head.position.set(0, -40);
head.zIndex = 1;

group.addChild(body, head);
group.pivot.set(group.width / 2, group.height / 2);
group.scale.set(1.5);

app.stage.addChild(group);

Compétences associées : pixijs-scene-core-concepts (modèle conceptuel du graphe de scène, masquage, couches, groupes de rendu), pixijs-scene-sprite / pixijs-scene-graphics / pixijs-scene-text / pixijs-scene-mesh (objets feuilles à intégrer dans les conteneurs), pixijs-events (eventMode, test de sélection), pixijs-math (Matrix, détails toGlobal/toLocal), pixijs-performance (cacheAsTexture, culling, groupes de rendu).

Motifs fondamentaux

Options du constructeur

const container = new Container({
  label: "world",
  x: 100,
  y: 50,
  scale: 2,
  rotation: Math.PI / 4,
  alpha: 0.8,
  visible: true,
  tint: 0xffaa00,
  blendMode: "add",
  sortableChildren: true,
  isRenderGroup: true,
  origin: { x: 0, y: 0 },
  boundsArea: new Rectangle(0, 0, 1920, 1080),
});

Toutes les options de Container (position, scale, tint, label, filters, zIndex, etc.) sont également valides ici — voir skills/pixijs-scene-core-concepts/references/constructor-options.md.

Le constructeur Container utilise assignWithIgnore pour copier en masse chaque champ de l'objet options sur l'instance, sauf children, parent et effects. Toute propriété publique de Container est une option de constructeur valide : cullable, cullArea, mask, filterArea, eventMode, hitArea, et ainsi de suite. Le bloc d'options ci-dessus regroupe les plus courantes ; consultez la référence partagée ci-dessus pour la liste complète.

isRenderGroup: true promeut le conteneur en son propre groupe de rendu afin que ses transformations soient appliquées sur le GPU plutôt que recalculées par enfant sur le CPU. Utilisez-le sur des sous-arbres stables (grands mondes statiques, couches d'UI). Ne pas abuser ; la plupart des scènes n'ont pas besoin de groupes de rendu explicites et trop de groupes nuisent aux performances. Profilez avant de promouvoir. Voir pixijs-scene-core-concepts/references/scene-management.md.

sortableChildren: true force les enfants à être retriés par zIndex au prochain rendu. Voir zIndex ci-dessous.

origin est un helper de transformation de première classe en v8 : un ObservablePoint qui agit comme centre de rotation/mise à l'échelle sans déplacer le conteneur. Tandis que pivot décale la projection de l'origine locale dans l'espace parent (donc la changer déplace l'objet), origin laisse la position inchangée et tourne/met à l'échelle simplement autour du point local spécifié. Accepte PointData, un seul nombre (appliqué aux deux axes), ou peut être défini en direct via container.origin.set(x, y). Définir à la fois pivot et origin sur le même conteneur produit un comportement composé et est déconseillé ; choisissez l'un ou l'autre.

boundsArea force getBounds() à retourner un rectangle fixe au lieu de mesurer récursivement les enfants ; c'est un gain de performance pour les conteneurs avec des centaines d'enfants bon marché et prévisibles.

cullable et cullArea sont des options de constructeur valides (la passe assignWithIgnore les copie comme n'importe quel autre champ), mais ils sont documentés dans pixijs-performance car la configuration du culling est une préoccupation de performance plutôt qu'une préoccupation du graphe de scène.

Feuilles vs conteneurs

const parent = new Container();
const sprite = new Sprite(texture);

parent.addChild(sprite);

Seul Container (et les sous-classes destinées à tenir des enfants, comme RenderLayer) doivent avoir des enfants. Sprite, Graphics, Text, Mesh, les particules ParticleContainer et le contenu DOMContainer sont des feuilles par convention dans PixiJS v8. Enveloppez-les dans un Container chaque fois que vous avez besoin de regrouper des choses : donnez au conteneur la logique de disposition et gardez les feuilles comme données visuelles pures. Ajouter des enfants à une feuille enregistre un avertissement de déppréciation et est prévu de devenir une erreur stricte.

Ajouter et supprimer des enfants

const parent = new Container();

parent.addChild(a, b, c);
parent.addChildAt(d, 0);
parent.swapChildren(a, b);
parent.setChildIndex(c, 0);

parent.removeChild(b);
parent.removeChildAt(0);
parent.removeChildren();

parent.removeChildren(0, 2);

addChild accepte n'importe quel nombre d'enfants et retourne le premier. Les enfants s'affichent dans l'ordre du tableau : l'index 0 est dessiné en premier (derrière), le dernier index est dessiné en dernier (devant). addChildAt insère à un index spécifique ; setChildIndex déplace un enfant existant ; swapChildren échange les positions de deux enfants.

removeChildren(beginIndex?, endIndex?) supprime une tranche et retourne le tableau supprimé.

Appeler addChildAt avec un enfant qui appartient déjà au même conteneur le déplace silencieusement vers le nouvel index. Aucun événement added / childAdded / removed / childRemoved n'est déclenché, car la relation parent-enfant n'a pas changé. Les événements sont déclenchés uniquement quand l'enfant vient d'un parent différent (ou d'aucun parent).

Pour une réaffectation de parent qui préserve la transformation mondiale (afin que l'enfant ne saute pas visuellement), utilisez reparentChild / reparentChildAt. Pour remplacer un enfant en place tout en copiant la transformation locale du vieil enfant, utilisez replaceChild.

Propriétés de transformation

const obj = new Container();

obj.x = 100;
obj.y = 200;
obj.position.set(100, 200);

obj.scale.set(2);
obj.scale = 2;

obj.rotation = Math.PI / 4;
obj.angle = 45;

obj.pivot.set(50, 50);
obj.skew.set(0.1, 0.2);

obj.alpha = 0.5;
obj.tint = 0xff0000;
obj.visible = false;
obj.renderable = false;
  • position, scale, pivot, skew sont des ObservablePoint. Assigner scale = 2 est valide et définit les deux axes.
  • rotation est en radians ; angle est en degrés ; ce sont des alias qui restent synchronisés.
  • pivot définit le point en espace local qui correspond à position en espace parent ; le changer déplace et tourne le conteneur.
  • alpha et tint se multiplient vers le bas à travers les enfants. blendMode s'applique aux instructions de dessin de ce conteneur.
  • visible = false saute le rendu et les mises à jour de transformation. renderable = false saute le rendu mais met à jour quand même les transformations (à utiliser quand vous avez besoin de getBounds() ou du test de sélection sans dessiner).

zIndex et sortableChildren

const world = new Container({ sortableChildren: true });

const ground = new Sprite(groundTexture);
ground.zIndex = 0;

const player = new Sprite(playerTexture);
player.zIndex = 10;

const ui = new Sprite(uiTexture);
ui.zIndex = 100;

world.addChild(ground, player, ui);

Quand sortableChildren est true, le conteneur retrie ses enfants par zIndex avant le prochain rendu. Changer le zIndex de n'importe quel enfant marque automatiquement le parent comme ayant besoin d'un tri. Triez uniquement ce que vous avez besoin de trier ; laisser sortableChildren désactivé est moins cher. Si vous voulez un contrôle complètement manuel, appelez container.sortChildren() vous-même après avoir changé les valeurs de zIndex.

Pour un contrôle de l'ordre de rendu découplé de la hiérarchie (les enfants gardent leur parent logique pour les transformations mais se rendent à un z différent), utilisez RenderLayer. Voir pixijs-scene-core-concepts/references/scene-management.md.

Limites et conversion de coordonnées

const bounds = container.getBounds();
console.log(bounds.x, bounds.y, bounds.width, bounds.height);

const rect = container.getBounds().rectangle;

const local = new Point(10, 20);
const world = container.toGlobal(local);
const backToLocal = container.toLocal(world);

const selfPos = container.getGlobalPosition();

getBounds() retourne un objet Bounds (pas un Rectangle) ; il expose x, y, width, height, et un getter .rectangle pour les API qui ont besoin d'un vrai Rectangle. La signature est getBounds(skipUpdate?: boolean, bounds?: Bounds) — passez true comme premier argument pour sauter la mise à jour forcée des transformations, et une instance Bounds optionnelle comme deuxième argument pour éviter d'en allouer une nouvelle.

toGlobal(point) convertit un point dans l'espace local de ce conteneur en espace de racine de scène. toLocal(point, from?) convertit depuis l'espace local d'un autre conteneur (ou l'espace global si from est omis). getGlobalPosition() est un raccourci pour parent.toGlobal(this._position).

Dimensionnement

const sprite = new Sprite(texture);

sprite.setSize(200, 100);
const { width, height } = sprite.getSize();

setSize ajuste scale pour que les limites du conteneur s'ajustent à la taille de pixel demandée, en une seule opération. Définir .width et .height individuellement fonctionne, mais chaque assignation déclenche un recalcul de limites séparé ; préférez setSize quand vous changez les deux axes.

Événements de conteneur

const parent = new Container();

parent.on("childAdded", (child, container, index) => {
  console.log("added at", index, child.label);
});

parent.on("childRemoved", (child, container, index) => {
  console.log("removed from", index);
});

const child = new Container();
child.on("added", (newParent) => console.log("entered", newParent.label));
child.on("removed", (oldParent) => console.log("left", oldParent.label));
child.on("visibleChanged", (visible) => console.log("visible:", visible));
child.on("destroyed", (destroyed) => console.log("gone", destroyed.label));

parent.addChild(child);
Événement Déclenché sur Arguments
childAdded le parent recevant l'enfant (child, container, index)
childRemoved le parent perdant l'enfant (child, container, index)
added l'enfant qui a été attaché (parent)
removed l'enfant qui a été détaché (parent)
destroyed le conteneur détruit (container)
visibleChanged le conteneur dont visible a basculé (visible)

Ces événements sont émis du côté EventEmitter de Container ; ne les confondez pas avec les événements de pointeur de pixijs-events.

destroyed est déclenché après le nettoyage interne mais avant la suppression des écouteurs, donc au moment où votre gestionnaire s'exécute position, scale, pivot, origin, skew et parent ont déjà été annulés, et children a été vidé (longueur 0, mais la référence du tableau elle-même n'est pas annulée). Capturez les données dont vous avez besoin du conteneur avant d'appeler destroy(), pas à l'intérieur du gestionnaire.

Mises à jour par frame avec onRender

const container = new Container();

container.onRender = (renderer) => {
  container.rotation += 0.01;
};

container.onRender = null;

onRender s'exécute chaque frame tandis que le conteneur est rendu, et reçoit le Renderer actif. Utilisez-le pour l'animation légère ou les mises à jour par frame liées à un conteneur spécifique. En v7 ce motif était fait en remplaçant updateTransform, qui ne s'exécute plus à chaque frame en v8. Définissez onRender = null pour détacher le callback.

Recherche et suppression du parent

const player = world.getChildByLabel("player");
const enemies = world.getChildrenByLabel(/enemy-\d+/, true);

const bounds = hud.getLocalBounds();

oldSprite.removeFromParent();
  • getChildByLabel(label, deep?) — première correspondance par chaîne ou RegExp. Passez true pour une recherche récursive.
  • getChildrenByLabel(label, deep?, out?) — toutes les correspondances. Accepte un tableau de sortie réutilisable optionnel.
  • getLocalBounds() — limites dans l'espace de coordonnées propre de ce conteneur, en ignorant les transformations du parent. Moins cher que getBounds() pour les mathématiques de disposition autonomes.
  • removeFromParent() — détache this de son parent actuel (pas d'opération s'il est déjà orphelin).

Destruction

container.destroy();

container.destroy({
  children: true,
  texture: true,
  textureSource: true,
});

console.log(container.destroyed);

Par défaut destroy() délien ce conteneur de son parent et démantèle son propre état. Passez { children: true } pour détruire récursivement chaque descendant ; c'est l'appel habituel pour tuer un sous-arbre entier. texture: true et textureSource: true détruisent en outre les ressources GPU référencées par les enfants feuilles (utile pour les sprites dont les textures vous avez chargées uniquement pour eux). Si cacheAsTexture est activé, désactivez-le avec container.cacheAsTexture(false) avant de détruire.

Erreurs courantes

[CRITIQUE] Ajouter des enfants aux objets de scène feuille

Mauvais :

const sprite = new Sprite(texture);
const overlay = new Sprite(overlayTexture);
sprite.addChild(overlay);

Correct :

const group = new Container();
const sprite = new Sprite(texture);
const overlay = new Sprite(overlayTexture);
group.addChild(sprite, overlay);

Sprites, Graphics, Text et Mesh sont des feuilles. Ajouter des enfants à ces derniers enregistre un avertissement de dépréciation maintenant et sera une erreur dans une version future. Enveloppez toujours-les dans un Container quand vous avez besoin de regroupement.

[HAUTE] S'attendre à ce que getBounds() retourne un Rectangle

Mauvais :

const rect = container.getBounds();
rect.contains(x, y); // TypeError: contains is not a function

Correct :

const rect = container.getBounds().rectangle;
rect.contains(x, y);

const bounds = container.getBounds();
console.log(bounds.width, bounds.height);

getBounds() retourne une instance Bounds en v8. Ses getters basiques (x, y, width, height) fonctionnent, mais pour les méthodes spécifiques à Rectangle comme .contains() ou le passage aux API qui nécessitent un Rectangle, lisez la propriété .rectangle.

[HAUTE] Utiliser cacheAsBitmap au lieu de cacheAsTexture

Mauvais :

container.cacheAsBitmap = true;

Correct :

container.cacheAsTexture(true);

cacheAsBitmap (propriété v7) a été renommé en cacheAsTexture() (une méthode) en v8. Toujours le désactiver avec cacheAsTexture(false) avant d'appeler destroy().

[MOYEN] Utiliser container.name au lieu de container.label

name a été renommé en label en v8. L'ancienne propriété fonctionne toujours en tant qu'alias déprécié ; getChildByLabel est la manière v8 de rechercher les enfants par nom.

[MOYEN] Définir à la fois pivot et origin sur le même conteneur

Pivot décale la projection de l'origine locale dans l'espace parent (déplace l'objet comme effet secondaire du changement du centre de rotation). Origin change le centre de rotation/mise à l'échelle sans déplacement. Définir les deux sur le même conteneur produit un comportement composé inattendu ; choisissez l'un ou l'autre.

Référence API

Skills similaires