원클릭으로
dev-phaser-fundamentals
Phaser game configuration, scenes, and lifecycle management
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Phaser game configuration, scenes, and lifecycle management
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Complete Developer workflow orchestration - task research sequence, implementation flow, validation gates, PRD synchronization, exit conditions.
Complete Game Designer workflow - skill invocation protocol, GDD creation, playtest flow with GDD review, design sessions. MUST load before starting assignments.
Complete PM Coordinator workflow - task assignment, project orchestration, PRD management, worker coordination. Use proactively when starting PM agent work.
Complete PM Coordinator workflow - task assignment, project orchestration, PRD management, worker coordination. Use proactively when starting PM agent work.
Complete QA Validator workflow orchestration. References specialized skills for each validation step. Load at session startup for full protocol.
Base instructions and guidelines for all agents in the system. This skill provides foundational behaviors and communication protocols that all agents should follow.
| name | dev-phaser-fundamentals |
| description | Phaser game configuration, scenes, and lifecycle management |
"2D web games made simple – scenes, sprites, and physics."
Use when:
import Phaser from "phaser";
import { MainScene } from "./scenes/MainScene";
const config: Phaser.Types.Core.GameConfig = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: "game-container",
backgroundColor: "#000000",
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH,
},
physics: {
default: "arcade",
arcade: {
gravity: { y: 300 },
debug: false,
},
},
scene: [MainScene],
};
new Phaser.Game(config);
// Manual game loop without Phaser
const canvas = document.getElementById("game") as HTMLCanvasElement;
const ctx = canvas.getContext("2d")!;
let playerX = 400;
let playerY = 300;
// Manual asset loading
const playerImg = new Image();
playerImg.src = "assets/player.png";
playerImg.onload = () => {
gameLoop();
};
// Manual game loop
function gameLoop() {
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw player
ctx.drawImage(playerImg, playerX, playerY);
// Handle input manually
document.addEventListener("keydown", (e) => {
if (e.key === "ArrowLeft") playerX -= 5;
// ... more manual input handling
});
requestAnimationFrame(gameLoop);
}
Problems:
// Phaser handles everything
export class GameScene extends Phaser.Scene {
private player!: Phaser.Physics.Arcade.Sprite;
preload() {
// Built-in asset loading with progress tracking
this.load.image("player", "assets/player.png");
}
create() {
// Physics-enabled sprite
this.player = this.physics.add.sprite(400, 300, "player");
// Built-in input handling
this.cursors = this.input.keyboard!.createCursorKeys();
}
update() {
// Frame-independent movement
if (this.cursors.left!.isDown) {
this.player.setVelocityX(-160);
}
// Built-in physics handles position updates
}
}
const config = {
// Phaser manages the game loop, canvas, rendering
scene: [GameScene],
physics: { default: "arcade" },
};
new Phaser.Game(config);
Benefits:
| Need | Use |
|---|---|
| Basic 2D game | Phaser.AUTO renderer type |
| Physics platformer | Arcade physics with gravity |
| Physics puzzle | Matter physics for realism |
| Responsive layout | Phaser.Scale.FIT with CENTER_BOTH |
| Multiple scenes | Array of scene classes in config |
export class MainScene extends Phaser.Scene {
constructor() {
super({ key: "MainScene" });
}
preload() {
// Load assets before create()
this.load.image("player", "assets/player.png");
this.load.image("background", "assets/bg.png");
}
create() {
// Create game objects
this.add.image(400, 300, "background");
this.player = this.physics.add.sprite(400, 300, "player");
}
update(time: number, delta: number) {
// Game loop (60fps)
// delta = time since last frame in ms
}
}
export class GameScene extends Phaser.Scene {
constructor() {
super({ key: "GameScene", active: false });
}
init(data: { level: number; score: number }) {
// Receive data from previous scene
this.level = data.level || 1;
this.score = data.score || 0;
}
preload() {
// Load level-specific assets
this.load.image(`level${this.level}`, `assets/level${this.level}.png`);
}
create() {
// Setup game objects
this.createPlayer();
this.createEnemies();
}
update(time: number, delta: number) {
this.updatePlayer();
this.updateEnemies();
}
}
const config: Phaser.Types.Core.GameConfig = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: "game-container",
backgroundColor: "#2d2d2d",
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH,
width: 800,
height: 600,
},
physics: {
default: "arcade",
arcade: {
gravity: { x: 0, y: 1000 },
debug: false,
},
},
scene: [BootScene, PreloadScene, TitleScene, GameScene, UIScene],
pipeline: { CustomPipeline: CustomPipeline },
};
interface ExtendedGameConfig extends Phaser.Types.Core.GameConfig {
customSettings: {
maxPlayers: number;
gameMode: "deathmatch" | "capture";
};
}
class CustomGame extends Phaser.Game {
constructor(config: ExtendedGameConfig) {
super(config);
this.customSettings = config.customSettings;
}
}
export class MainScene extends Phaser.Scene {
create() {
// Scene transitions
this.scene.start("GameScene", { level: 1 });
// Launch parallel scene (UI overlay)
this.scene.launch("UIScene");
// Pause current scene
this.scene.pause();
// Sleep scene (stops update but keeps rendering)
this.scene.sleep("BackgroundScene");
// Stop and remove scene
this.scene.stop("OldScene");
}
}
❌ DON'T:
create() - use preload()update() - causes GC pressurethis.scene.restart() frequently - expensive operationsuper() in scene constructor✅ DO:
preload() before useupdate()shutdown() methodscale.manager for responsive sizingthis.add.group()export class GameScene extends Phaser.Scene {
private player!: Phaser.Physics.Arcade.Sprite;
private enemies!: Phaser.GameObjects.Group;
private cursors!: Phaser.Types.Input.Keyboard.CursorKeys;
constructor() {
super({ key: "GameScene" });
}
create() {
// Always setup shutdown for cleanup
this.events.once(Phaser.Scenes.Events.SHUTDOWN, this.shutdown, this);
}
shutdown() {
// Clean up listeners
this.input.keyboard!.off("keydown-ESC");
}
update(time: number, delta: number) {
// Use delta for frame-independent movement
const dt = delta / 1000; // Convert to seconds
}
}
const config: Phaser.Types.Core.GameConfig = {
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH,
width: 800,
height: 600,
},
};
// In scene, get scale info
this.scale.width; // Actual canvas width
this.scale.height; // Actual canvas height
Before completing Phaser setup:
| Issue | Solution |
|---|---|
| Assets not loading | Check preload() runs before create() |
| Physics not working | Verify physics config and body type |
| Scene not updating | Check scene is active: true |
| Canvas size wrong | Configure scale manager |
| Memory leaks | Clean up in shutdown() |
Phaser 3 provides built-in support for loading JSON files containing level data:
// In preload(), load the JSON file
preload() {
// Load individual level files
this.load.json('level001', 'data/levels/level001.json');
// Load level index
this.load.json('levels', 'data/levels.json');
}
// In create(), access the loaded data
create() {
// Get level index
const levelsIndex = this.cache.json.get('levels');
console.log('Available levels:', levelsIndex.levels);
// Get specific level data
const level001Data = this.cache.json.get('level001');
console.log('Level 1 pigs:', level001Data.pigs);
// Use the data to spawn objects
level001Data.pigs.forEach(pigData => {
this.spawnPig(pigData.x, pigData.y, pigData.type);
});
level001Data.blocks.forEach(blockData => {
this.spawnBlock(blockData.x, blockData.y, blockData.material);
});
}
For type-safe JSON level loading, use Ajv for runtime validation:
import Ajv, { JSONSchemaType } from 'ajv';
// Define your level schema
interface LevelData {
id: string;
name: string;
birds: string[];
pigs: Array<{ x: number; y: number; type: string }>;
blocks: Array<{ x: number; y: number; material: string; rotation: number }>;
starThresholds: { one: number; two: number; three: number };
}
const levelSchema: JSONSchemaType<LevelData> = {
type: 'object',
required: ['id', 'name', 'birds', 'pigs', 'blocks', 'starThresholds'],
properties: {
id: { type: 'string' },
name: { type: 'string' },
birds: { type: 'array', items: { type: 'string' } },
pigs: {
type: 'array',
items: {
type: 'object',
required: ['x', 'y', 'type'],
properties: {
x: { type: 'number' },
y: { type: 'number' },
type: { type: 'string' }
}
}
},
blocks: {
type: 'array',
items: {
type: 'object',
required: ['x', 'y', 'material', 'rotation'],
properties: {
x: { type: 'number' },
y: { type: 'number' },
material: { type: 'string' },
rotation: { type: 'number' }
}
}
},
starThresholds: {
type: 'object',
required: ['one', 'two', 'three'],
properties: {
one: { type: 'number' },
two: { type: 'number' },
three: { type: 'number' }
}
}
}
};
// Validate before using
const ajv = new Ajv();
const validate = ajv.compile(levelSchema);
const levelData = this.cache.json.get('level001');
if (!validate(levelData)) {
console.error('Invalid level data:', validate.errors);
throw new Error('Level validation failed');
}
For dynamic level loading at runtime, use Phaser's plugin system:
class LevelLoaderPlugin extends Phaser.Plugins.BasePlugin {
constructor(pluginManager: Phaser.Plugins.PluginManager) {
super(pluginManager);
}
async loadLevel(levelId: string): Promise<any> {
const scene = this.scene;
const response = await fetch(`data/levels/${levelId}.json`);
const levelData = await response.json();
// Validate schema
if (!this.validateLevel(levelData)) {
throw new Error(`Invalid level data for ${levelId}`);
}
return levelData;
}
private validateLevel(data: any): boolean {
// Schema validation logic
return true;
}
}
| Issue | Solution |
|---|---|
| Assets not loading | Check preload() runs before create() |
| Physics not working | Verify physics config and body type |
| Scene not updating | Check scene is active: true |
| Canvas size wrong | Configure scale manager |
| Memory leaks | Clean up in shutdown() |
| JSON not loading | Verify file path and file extension |
| Invalid level data | Add schema validation with Ajv |