phaserjs/phaser1 file

Groups And Containers

Use this skill when using Groups or Containers in Phaser 4. Covers organizing game objects, object pooling, batch operations, and nested transforms with Containers. Triggers on: Group, Container, object pool, getFirstDead, children.

Specification
Skill ID
phaserjs/phaser/groups-and-containers
Publisher
phaserjs
Repository
phaser
Installs
0
Files
1
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

phaserjs/phaser/groups-and-containersInstalls these files
  • SKILL.md

What this skill tells the agent

Groups and Containers

Logical grouping (Group), visual grouping with transform inheritance (Container), render-layer grouping (Layer), object pooling, and when to use each in Phaser 4.

Key source paths: src/gameobjects/group/, src/gameobjects/container/, src/gameobjects/layer/ Related skills: ../sprites-and-images/SKILL.md, ../physics-arcade/SKILL.md

Quick Start

// In a Scene's create() method:

// --- Group: logical collection, no transform, great for pooling ---
const enemies = this.add.group();
enemies.create(100, 200, 'enemy');       // creates Sprite at (100,200)
enemies.create(300, 200, 'enemy');

// --- Container: visual parent with inherited transform ---
const hud = this.add.container(10, 10);
const icon = this.add.image(0, 0, 'heart');
const label = this.add.text(20, 0, 'x3');
hud.add([icon, label]);                  // children move/scale/rotate with hud

// --- Layer: render-ordering bucket, no position/scale ---
const bgLayer = this.add.layer();
const fgLayer = this.add.layer();
bgLayer.add(this.add.image(400, 300, 'sky'));
fgLayer.add(this.add.sprite(400, 300, 'player'));

Core Concepts

Group vs Container vs Layer

FeatureGroupContainerLayer
PurposeLogical collection / poolVisual parent with transformRender-order bucket
On display listNo (children are)Yes (renders children)Yes (renders children)
Position/rotation/scaleNoYes (children inherit)No
Children storagechildren (Set)list (Array)List (Structs.List)
PhysicsVia physics.add.group()Limited (offsets if not at 0,0)No
InputNo (children can)Yes (needs hit area shape)No
Object poolingYes (getFirstDead, kill)NoNo
MasksNoYes (not per-child in Canvas)Yes
Alpha/blend/visibleNo (batch via setVisible)YesYes
NestingN/AContainer in ContainerCannot go in Container
ExtendsEventEmitterGameObjectList
Factorythis.add.group()this.add.container(x, y)this.add.layer()

When to Use Each

Group: Managing collections of similar objects (enemies, bullets, coins), object pooling with active/inactive lifecycle, physics group collisions. No shared visual transform. Members can belong to multiple Groups simultaneously.

Container: Children inherit position, rotation, scale, alpha. Composite UI elements (health bars, inventory slots), moving/rotating clusters as one unit, nested transforms. By default exclusive -- a child can only belong to one Container (use setExclusive(false) to override).

Layer: Controlling render order of object batches, applying shared alpha/blend/mask. No position/scale/rotation. Lightweight render bucketing.

Container vs Group at a Glance

  • Container has position, rotation, scale, alpha -- Group does not. If you need children to move/rotate as a unit, use Container.
  • Container is exclusive by default -- adding a child removes it from its previous Container. Group is non-exclusive; a game object can be in many Groups.
  • Container is on the display list -- it renders its children. Group is not on the display list; its children render individually on the Scene.
  • Group supports object pooling -- getFirstDead, kill, killAndHide. Container does not.
  • Container has performance cost -- each child requires matrix math per frame. Deeper nesting = more cost. Prefer Group or Layer when transforms are not needed.

Common Patterns

Creating and Populating Groups

// Empty group, add existing objects
const gems = this.add.group();
gems.add(existingSprite);
gems.addMultiple([sprite1, sprite2, sprite3]);

// Group with config -- creates children automatically
const coins = this.add.group({
    classType: Phaser.GameObjects.Sprite,
    key: 'coin',
    quantity: 10,           // overrides frameQuantity
    setXY: { x: 50, y: 300, stepX: 60 },
    setScale: { x: 0.5, y: 0.5 }
});

// Custom class type with pool limit
const bullets = this.add.group({
    classType: Bullet,       // must accept (scene, x, y, key, frame)
    maxSize: 30,
    defaultKey: 'bullet',
    runChildUpdate: true     // calls child.update() each frame
});

Object Pooling with getFirstDead

The core pooling pattern: deactivate objects instead of destroying them, then reuse inactive ones.

// Setup pool
const bullets = this.add.group({
    classType: Phaser.GameObjects.Sprite,
    defaultKey: 'bullet',
    maxSize: 30
});

// Fire a bullet -- get() finds first inactive member or creates one
function fireBullet(x, y) {
    const bullet = bullets.get(x, y);

    if (bullet) {
        bullet.setActive(true);
        bullet.setVisible(true);
        bullet.body.velocity.y = -300;   // if physics enabled
    }
}

// Deactivate when off-screen or on hit
function killBullet(bullet) {
    bullets.killAndHide(bullet);         // sets active=false, visible=false
    // If using physics, also reset the body:
    // bullet.body.stop();
}

// Alternative: manual getFirst
const inactive = bullets.getFirst(false);     // first where active===false
const active = bullets.getFirstAlive();       // first where active===true
const dead = bullets.getFirstDead(true, x, y); // first inactive, create if null

Pool helper methods on Group:

MethodDescription
get(x, y, key, frame)Shortcut: getFirst(false, true, ...) -- finds inactive or creates
getFirst(state, createIfNull, x, y, key, frame)First member matching active state
getFirstAlive(createIfNull, x, y, key, frame)First member where active===true
getFirstDead(createIfNull, x, y, key, frame)First member where active===false
getLast(state, createIfNull, x, y, key, frame)Like getFirst but searches back-to-front
kill(gameObject)Sets active=false on a member
killAndHide(gameObject)Sets active=false and visible=false
countActive(value)Count members where active===value (default true)
getTotalUsed()Count of active members
getTotalFree()maxSize - active count (remaining pool capacity)
isFull()True if children.size >= maxSize

Physics Groups

Physics groups extend Group with automatic body assignment. See ../physics-arcade/SKILL.md for full details.

// Arcade Physics group -- every member gets a dynamic body
const enemies = this.physics.add.group({
    key: 'enemy',
    quantity: 5,
    setXY: { x: 100, y: 100, stepX: 80 }
});

// Static physics group -- immovable bodies
const platforms = this.physics.add.staticGroup();
platforms.create(400, 568, 'ground');

// Collide physics groups with each other
this.physics.add.collider(player, platforms);
this.physics.add.overlap(bullets, enemies, onHit);

Containers with Nested Transforms

// HUD that follows camera
const hud = this.add.container(10, 10);
hud.setScrollFactor(0);     // pinned to camera

const healthBar = this.add.rectangle(0, 0, 200, 20, 0x00ff00);
const healthText = this.add.text(210, -5, '100 HP');
hud.add([healthBar, healthText]);

// Move everything at once
hud.setPosition(50, 50);

// Scale and rotate propagate to children
hud.setScale(1.5);
hud.setRotation(0.1);

// Alpha affects all children
hud.setAlpha(0.8);

// Nested containers
const inventory = this.add.container(300, 500);
for (let i = 0; i < 5; i++) {
    const slot = this.add.container(i * 55, 0);
    slot.add([
        this.add.rectangle(0, 0, 48, 48, 0x333333),
        this.add.image(0, 0, `item-${i}`)
    ]);
    inventory.add(slot);    // Container inside Container
}

Key Container methods:

MethodDescription
add(child) / addAt(child, index)Add Game Object(s); removes from display list
remove(child, destroyChild)Remove; optionally destroy
getAt(index) / getIndex(child)Access by index

Use this skill in a project

Open any RiverX project, search the Skills panel for phaserjs/phaser/groups-and-containers, and install it in one click.

Use this skill