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
Phaserdesde su CDN: usa<script>para el motor ytype="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.jsen tu zip y cárgalo con una ruta relativa.