Saltar al contenido principal

Ejemplo: Phaser 3

Conecta un juego de Phaser 3 con el anfitrión de juegos externos de IncentIA. La parte de Phaser es un proyecto normal; solo el script de arranque usa el módulo auxiliar del inicio rápido.

Estructura del proyecto​

my-phaser-game/
index.html
main.js
incentia-sdk.js
game/
Boot.js
Play.js
assets/
bg.png
button.png

Ejecuta zip -r my-phaser-game.zip * dentro de la carpeta y sube el zip en el maestro de juegos (consulta Envío de un juego).

index.html​

<!doctype html>
<html>
<body>
<div id="game-root"></div>
<script src="https://cdn.jsdelivr.net/npm/phaser@3.80.1/dist/phaser.min.js"></script>
<script type="module" src="./main.js"></script>
</body>
</html>

main.js​

import { readPlayContext, complete } from './incentia-sdk.js';
import { BootScene } from './game/Boot.js';
import { PlayScene } from './game/Play.js';

const ctx = readPlayContext();

// Stash the play context on the global registry so any scene can submit a
// completion signal without re-parsing the URL.
const game = new Phaser.Game({
type: Phaser.AUTO,
width: 480,
height: 320,
parent: 'game-root',
scene: [BootScene, PlayScene],
backgroundColor: '#1b1b1f',
});
game.registry.set('incentia.ctx', ctx);
game.registry.set('incentia.complete', complete);

game/Play.js​

export class PlayScene extends Phaser.Scene {
constructor() {
super('Play');
}

create() {
this.add.image(240, 160, 'bg');
const button = this.add.image(240, 250, 'button').setInteractive({ useHandCursor: true });

let score = 0;
const text = this.add.text(20, 20, 'Score: 0', { fontFamily: 'sans-serif', fontSize: 18, color: '#fff' });

// Demo: tap the button to score, then submit on a long press.
button.on('pointerdown', () => {
score += 10;
text.setText('Score: ' + score);
});

this.input.keyboard?.on('keydown-SPACE', () => this.submit(score));
button.on('pointerover', () => button.setScale(1.05));
button.on('pointerout', () => button.setScale(1));
this.add.text(20, 290, 'Press Space to submit', { fontSize: 12, color: '#999' });
}

async submit(score) {
const ctx = this.registry.get('incentia.ctx');
const complete = this.registry.get('incentia.complete');
if (!ctx) {
this.scene.add('Outcome', { create: function () { this.add.text(20, 20, 'Dev outcome: win'); } }, true);
return;
}
try {
const outcome = await complete(ctx, { score });
const msg = outcome.outcome === 'win' ? `You won ${outcome.prize?.name ?? 'a prize'}` : 'Better luck next time';
this.add.text(120, 140, msg, { fontSize: 18, color: '#fff', backgroundColor: '#000', padding: { x: 8, y: 4 } });
} catch (err) {
this.add.text(20, 280, `Error: ${err.message}`, { fontSize: 12, color: '#f66' });
}
}
}

game/Boot.js​

export class BootScene extends Phaser.Scene {
constructor() {
super('Boot');
}
preload() {
this.load.image('bg', 'assets/bg.png');
this.load.image('button', 'assets/button.png');
}
create() {
this.scene.start('Play');
}
}

Esquema de señal​

{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["score"],
"properties": { "score": { "type": "integer", "minimum": 0 } }
}

Consejos​

  • Phaser se publica como un global Phaser desde su CDN: usa <script> para el motor y type="module" solo para el módulo auxiliar y los módulos de tu juego.
  • Phaser pesa unos 1,2 MB. El límite de 25 MB por paquete deja mucho margen, pero vigila la carpeta de recursos.
  • El script de Phaser de arriba se carga desde un CDN público. Si necesitas que el juego funcione sin conexión o en una red restringida, mete phaser.min.js en tu zip y cárgalo con una ruta relativa.