Routeur de scènes
Le routeur de scènes orchestre les transitions entre scènes à l'aide d'un automate fini. Définissez des états, des transitions et naviguez par programmation.
Les scènes sont définies séparément avec
defineScene(). Voir Scènes.
Définir un routeur
defineSceneRouter() déclare les états et les transitions :
import { defineSceneRouter } from '@gwenjs/core/scene'
import { MenuScene, GameScene, GameOverScene } from './scenes'
export const AppRouter = defineSceneRouter({
initial: 'menu',
routes: {
menu: {
scene: MenuScene,
on: { START: 'game' },
},
game: {
scene: GameScene,
on: { PAUSE: 'pause', GAME_OVER: 'gameOver' },
},
gameOver: {
scene: GameOverScene,
on: { RESTART: 'game', MENU: 'menu' },
},
},
})initial— l'état de démarrage (doit être une clé dansroutes)on— mappe les noms d'événements aux états ciblesoverlay: true— la scène est rendue par-dessus la scène précédente (utile pour les menus de pause)
Naviguer
Appelez useSceneRouter() à l'intérieur d'un acteur ou système pour obtenir un handle, puis appelez .send() pour déclencher les transitions :
import { defineActor, useSceneRouter, onUpdate, useComponent } from '@gwenjs/core/actor'
import { AppRouter } from '../router'
import { Health } from '../components'
import { PlayerPrefab } from './prefabs/Player'
export const PlayerActor = defineActor(PlayerPrefab, () => {
const nav = useSceneRouter(AppRouter)
const health = useComponent(Health)
onUpdate(async () => {
if (health.value <= 0) {
await nav.send('GAME_OVER') // transition vers 'gameOver'
}
})
return {}
})API Handle
const nav = useSceneRouter(AppRouter)
await nav.send('START') // déclencher une transition
nav.can('START') // vérifier si la transition est valide
nav.current // nom de l'état actuel
nav.params // paramètres passés lors de la transitionPasser des paramètres
Passez des données lors de l'envoi d'un événement :
async () => {
await nav.send('START', { level: 2, difficulty: 'hard' })
}
// Dans la GameScene :
export const GameScene = defineScene('game', () => ({
systems: [GameSystem],
onEnter: async () => {
const nav = useSceneRouter(AppRouter)
const params = nav.params
console.log('Starting level', params.level)
},
}))Cycle de vie des scènes
Quand une transition se déclenche :
onExitde la scène actuelle est appelé (sauf sioverlay: true)onEnterde la scène cible est appelé- Les systèmes de l'ancienne scène sont désenregistrés, les nouveaux sont enregistrés
export const GameScene = defineScene('Game', () => ({
systems: [PlayerSystem, EnemySystem],
onEnter: async () => {
console.log('Game scene loaded!')
await loadAssets()
},
onExit: () => {
console.log('Game scene unloading')
cleanup()
},
}))Scènes en superposition
Définissez overlay: true pour garder la scène précédente chargée et rendue derrière la nouvelle :
const AppRouter = defineSceneRouter({
initial: 'game',
routes: {
game: { scene: GameScene, on: { PAUSE: 'pause' } },
pause: {
scene: PauseScene,
overlay: true, // Le jeu continue de s'exécuter derrière le menu de pause
on: { RESUME: 'game' },
},
},
})Lors de la transition vers pause :
- La scène du jeu reste chargée (les systèmes continuent de s'exécuter)
- La scène du jeu continue de se rendre (derrière l'UI de pause)
onExitn'est pas appelé sur la scène du jeuonEnterest appelé sur la scène de pause- La physique et la logique de mise à jour continuent pour la scène du jeu
Quand vous revenez de pause :
onExitest appelé sur la scène de pause- La scène du jeu reprend immédiatement (
onEntern'est pas appelé à nouveau)
Validation
defineSceneRouter() valide au moment de la définition :
initialdoit être une clé dansroutes- Tous les cibles de transition doivent être des clés de route valides
Les erreurs sont levées immédiatement (pas au runtime), donc les routeurs mal configurés sont détectés pendant le développement.
Enregistrer le routeur
Enregistrez le routeur dans gwen.config.ts en tant qu'option de module :
// gwen.config.ts
export default defineConfig({
modules: [
['@gwenjs/core', { router: AppRouter }],
],
})Le routeur est passé comme option de module, pas via un appel engine.use() standalone.
Exemple complet
// src/router.ts
import { defineSceneRouter } from '@gwenjs/core/scene'
import { MenuScene, GameScene, GameOverScene } from './scenes'
export const AppRouter = defineSceneRouter({
initial: 'menu',
routes: {
menu: {
scene: MenuScene,
on: { START: 'game' },
},
game: {
scene: GameScene,
on: { PAUSE: 'pause', GAME_OVER: 'gameOver' },
},
gameOver: {
scene: GameOverScene,
on: { RESTART: 'game', MENU: 'menu' },
},
},
})
// gwen.config.ts
import { defineConfig } from '@gwenjs/core'
import { AppRouter } from './router'
export default defineConfig({
modules: [
['@gwenjs/core', { router: AppRouter }],
],
})Résumé de l'API
defineSceneRouter(options) | Déclarer la FSM |
useSceneRouter(router) | Obtenir le handle au runtime à l'intérieur d'un acteur/système |
nav.send(event, params?) | Déclencher une transition (async) |
nav.can(event) | Vérifier si la transition est valide |
nav.current | Nom d'état actuel |
nav.params | Paramètres passés à l'état actuel |
nav.onTransition(fn) | S'abonner aux changements d'état |
nav.onTransition((from, to) => {
// appelé à chaque transition
console.log(`Transitioned from ${from} to ${to}`)
})