<footer><div id=version></div></footer>
html, body {
  height: 100%;
}

body {
  margin: 0;
  padding: 0;
  background: #111;
  color: #eee;
  font: caption;
}

#version {
  position: absolute;
  left: 5px;
  top: 5px;
}
/* global Phaser */

var config = {
  width: 800,
  height: 600,
  loader: {
    baseURL: 'https://labs.phaser.io',
    crossOrigin: 'anonymous'
  },
  scene: {
    preload: preload,
    create: create,
    update: update
  },
  physics: {
    default: 'arcade',
    arcade: {
      debug: true,
      debugShowVelocity: false
    }
  },
  plugins: {
    scene: [
      { key: 'DebugBodyColors', plugin: PhaserDebugBodyColorsPlugin, start: true }
    ]
  }
};

var group;

var caption;

var captionStyle = {
  fill: '#7fdbff',
  fontFamily: 'monospace',
  lineSpacing: 4
};

var captionTextFormat = (
  'Total:    %1\n' +
  'Max:      %2\n' +
  'Active:   %3\n' +
  'Inactive: %4\n' +
  'Used:     %5\n' +
  'Free:     %6\n' +
  'Full:     %7\n'
);

new Phaser.Game(config);

function preload () {
  this.load.image('space', 'assets/skies/space2.png');
  this.load.spritesheet('alien', 'assets/tests/invaders/invader1.png', { frameWidth: 32, frameHeight: 32 });
}

function create () {
  this.anims.create({
    key: 'creep',
    frames: this.anims.generateFrameNumbers('alien', { start: 0, end: 1 }),
    frameRate: 2,
    repeat: -1
  });

  this.add.image(400, 300, 'space');

  group = this.physics.add.group({
    defaultKey: 'alien',
    defaultFrame: 0,
    maxSize: 40,
    // `enable` configures the group itself, setting `defaults.enable`.
    // We'll create sprites with bodies disabled, then enable in activeAlien().
    enable: false
  });

  group.createMultiple({
    key: group.defaultKey,
    frame: group.defaultFrame,
    // We'll seed the group with 40 inactive sprites, the maximum.
    frameQuantity: group.maxSize,
    active: false,
    visible: false
  });

  caption = this.add.text(16, 16, '', captionStyle);

  this.time.addEvent({
    delay: 100,
    loop: true,
    callback: addAlien
  });
}

function update () {
  group.children.iterate(function (alien) {
    if (alien.y > 400) {
      deactivateAlien(alien);
    }
  });

  updateCaption();
}

function activateAlien (alien, x, y) {
  alien.enableBody( // Enable physics body
    true, // Reset body and game object, at (x, y)
    x,
    y,
    true, // Activate sprite
    true  // Show sprite
  );
  
  console.assert(alien.body.enable, 'enabled');
  console.assert(alien.active, 'active');
  console.assert(alien.visible, 'visible');
  // Reset also stops the body:
  console.assert(alien.body.speed === 0, 'stopped');
  
  alien.setVelocityY(60);
  alien.setTint(Phaser.Display.Color.RandomRGB().color);
  alien.play('creep');
}

function deactivateAlien(alien) {
  alien.disableBody( // Stop and disable physics body
    true, // Deactivate sprite (active=false)
    true  // Hide sprite (visible=false)
  );
  
  console.assert(!alien.body.enable, 'disabled');
  console.assert(!alien.active, 'inactive');
  console.assert(!alien.visible, 'invisible');
  console.assert(alien.body.speed === 0);
}

function addAlien () {
  // Get first inactive sprite or create a new sprite (unless group is full).
  var alien = group.get();

  if (!alien) return; // None free.

  activateAlien(alien, Phaser.Math.Between(250, 800), Phaser.Math.Between(136, 200));
}

function updateCaption () {
  caption.setText(Phaser.Utils.String.Format(captionTextFormat, [
    group.getLength(),
    group.maxSize,
    group.countActive(true),
    group.countActive(false),
    group.getTotalUsed(),
    group.getTotalFree(),
    group.isFull()
  ]));
}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdn.jsdelivr.net/npm/phaser@3.19.0/dist/phaser.js
  2. https://cdn.jsdelivr.net/npm/colors.css@3.0.0/js/colors.js
  3. https://cdn.jsdelivr.net/npm/phaser-plugin-debug-body-colors@2.0.2/dist/PhaserDebugBodyColorsPlugin.js