Aller au contenu principal
Voir
Mystery Gift — Etape 2 / 11Créer une scène UI
1. Préparer les assets et les textes avant de créer une UI
2. Créer une scène UI
3. Créer une Composition
4. Créer un composant SpriteStack
5. Ajouter une couche de données avec PFM
6. Gérer les entrées clavier
7. Gérer la souris
8. Ajouter du texte multilingue
9. Utiliser les dialogues de confirmation
10. Créer des animations
11. Personnaliser GenericBase

Créer une scène UI

C'est le premier guide de code d'une série où l'on construit pas à pas une UI Mystery Gift complète. Ce système permet aux joueurs d'entrer des codes pour recevoir des récompenses. Le guide de préparation a déjà mis en place les graphismes et les textes ; ici, on crée la structure de fichiers et une scène minimale qui s'affiche et se ferme avec B.

Principe

Une UI dans PSDK est organisée en couches distinctes, chacune ayant un rôle précis :

  • PFM (optionnel) : le modèle de données. Utilisé uniquement si la scène a besoin de persistence. Dans notre UI Mystery Gift, cette couche stockera les codes déjà utilisés par le joueur.
  • UI : les composants visuels. Contient les constantes, les sous-composants graphiques (basés sur SpriteStack) et la Composition qui orchestre l'ensemble.
  • GamePlay : la logique de scène. Gère le cycle de vie, les inputs clavier et souris, et les transitions.

Le nom doit être identique dans les trois couches : PFM::MysteryGift, UI::MysteryGift, GamePlay::MysteryGift. Cette convention est obligatoire dans PSDK.

Structure des fichiers

Voici la structure complète de fichiers de l'UI Mystery Gift que l'on va construire au fil des guides suivants :

scripts/20 MysteryGift/
000 Entry.rb -> GamePlay accessor
001 Constants.rb -> UI::MysteryGift module constants
001 PFM/
000 MysteryGift.rb -> PFM::MysteryGift (persistence)
002 UI/
000 GiftRow.rb -> Gift row component
001 ReceivedBanner.rb -> Gift received animation banner
999 Composition.rb -> Visual orchestrator
003 GamePlay/
000 Base.rb -> GenericBase subclass
001 Main.rb -> Scene class
002 Logic.rb -> Business logic
003 Input.rb -> Keyboard input
004 Mouse.rb -> Mouse input
  • Les fichiers et dossiers sont préfixés de numéros qui définissent l'ordre de chargement.
  • Un fichier portant le même préfixe qu'un dossier est chargé avant le contenu du dossier. Par exemple, 001 Constants.rb est chargé avant tout ce qui se trouve dans le dossier 001 PFM/.
  • Le dossier 001 PFM/ contient la couche de persistence (optionnelle), le dossier 002 UI/ contient les composants visuels, le dossier 003 GamePlay/ contient la logique de scène.
  • Dans ce premier guide, on ne crée que trois fichiers : 000 Entry.rb, 003 GamePlay/000 Base.rb et 003 GamePlay/001 Main.rb. Les autres fichiers sont ajoutés dans les guides suivants.

Point d'entrée

Le point d'entrée expose un accesseur et une méthode d'ouverture sur le module GamePlay. C'est ainsi que la scène Mystery Gift est lancée depuis n'importe où dans le jeu.

Créez scripts/20 MysteryGift/000 Entry.rb :

module GamePlay
class << self
# @return [Class] the Mystery Gift scene class
attr_accessor :mystery_gift_class

# Open the Mystery Gift scene
def open_mystery_gift
return current_scene.call_scene(mystery_gift_class)
end
end
end
  • attr_accessor :mystery_gift_class crée un attribut de classe qui stocke la référence vers la classe de la scène. Cela permet à d'autres scripts de remplacer la scène par une version personnalisée via monkey-patching.
  • open_mystery_gift est la méthode publique que le jeu appelle pour ouvrir la scène. Elle utilise current_scene.call_scene qui empile la nouvelle scène par-dessus la scène courante.
  • La classe de la scène est enregistrée dans cet accesseur en bas de 001 Main.rb, ce que l'on verra plus loin dans ce guide.

GenericBase personnalisé

La classe GenericBase fournit les éléments visuels de base communs à toutes les scènes : image de fond, barre de boutons, boutons ctrl (A/X/Y/B), et le win_text (objet texte réutilisable). Il ne faut jamais reconstruire ces éléments manuellement : héritez de GenericBase et surchargez ses méthodes privées pour personnaliser le rendu.

Créez scripts/20 MysteryGift/003 GamePlay/000 Base.rb :

module UI
# Custom base UI for the Mystery Gift scene
class MysteryGiftBase < GenericBase
private

# Return the background filename
# @return [String]
def background_filename
return 'mystery_gift/background'
end

# Disable the background scroll animation
def create_background_animation; end
end
end
  • MysteryGiftBase < GenericBase : on hérite de GenericBase pour récupérer toute la fondation visuelle sans rien réécrire.
  • background_filename : surcharge de la méthode privée qui renvoie le chemin de l'image de fond (graphics/interface/mystery_gift/background.png, installée dans le guide de préparation). Le framework charge cette image automatiquement.
  • create_background_animation : en définissant une méthode vide, on désactive l'animation de défilement du fond. Si vous voulez l'animation, ne redéfinissez tout simplement pas cette méthode.
  • C'est une version minimale. On personnalise la barre de boutons et les boutons ctrl dans le guide GenericBase.

Scène minimale

La classe de scène elle-même hérite de BaseCleanUpdate::FrameBalanced, qui fournit le cycle de vie standard et l'équilibrage de frames. Pour ce premier guide, on crée une version simplifiée sans composition ni navigation dans une liste -- ces éléments sont ajoutés dans les guides suivants. Elle gère déjà le bouton B pour que vous puissiez fermer la scène.

Créez scripts/20 MysteryGift/003 GamePlay/001 Main.rb :

module GamePlay
# Mystery Gift scene -- a minimal scene that displays and closes with B
class MysteryGift < BaseCleanUpdate::FrameBalanced
# Create the scene
def initialize
super
@running = true
end

# Handle keyboard input each frame
# @return [Boolean]
def update_inputs
return automatic_input_update
end

# Update graphics each frame
def update_graphics
@base_ui.update_background_animation
end

private

# Create all the graphics for the scene
def create_graphics
create_viewport
create_base_ui
Graphics.sort_z
end

# Create the base UI with button texts
def create_base_ui
@base_ui = UI::MysteryGiftBase.new(@viewport, button_texts)
end

# Return the button texts for the ctrl buttons [A, X, Y, B]
# @return [Array<String, nil>]
def button_texts
return [nil, nil, nil, 'Quit']
end

# Action triggered by the B button -- quit the scene
def action_b
@running = false
end
end
end

GamePlay.mystery_gift_class = GamePlay::MysteryGift
  • super appelle GamePlay::Base#initialize qui crée la fenêtre de message et l'horloge interne de la scène.
  • @running = true indique que la scène est active. La passer à false fait sortir de la scène.
  • create_graphics est appelée automatiquement par le framework après initialize. Elle crée le viewport, instancie la base UI, puis appelle Graphics.sort_z pour trier tous les éléments visuels par profondeur.
  • create_viewport est héritée de GamePlay::Base. Elle crée le viewport principal @viewport en z=10_000, ce qui garantit que la scène s'affiche au-dessus des éléments du jeu.
  • create_base_ui instancie la sous-classe de GenericBase définie plus haut. Le deuxième argument button_texts définit les textes des boutons ctrl.
  • button_texts renvoie un tableau de 4 éléments correspondant aux boutons ctrl dans l'ordre [A, X, Y, B]. Mettre nil cache le bouton correspondant. Ici, seul le bouton B est visible avec le texte « Quit ». (On déplace ce texte vers le CSV dans le guide i18n.)
  • update_inputs est appelée à chaque frame par le framework. automatic_input_update vérifie chaque touche et appelle la méthode action_* correspondante si elle est pressée et définie. Ici, seule action_b existe, donc appuyer sur B fait sortir.
  • action_b passe @running à false pour sortir de la scène. Dans le guide clavier, on extrait update_inputs et les actions dans leur propre fichier, 003 Input.rb, et on ajoute la navigation.
  • update_graphics est appelée à chaque frame pour mettre à jour les animations. update_background_animation anime le défilement du fond (sans effet ici puisqu'on l'a désactivé).
  • La dernière ligne GamePlay.mystery_gift_class = GamePlay::MysteryGift enregistre la classe dans l'accesseur défini dans 000 Entry.rb, ce qui fait fonctionner GamePlay.open_mystery_gift.

Cycle de vie

Le framework exécute la scène selon un cycle précis :

  1. initialize : le constructeur est appelé. On initialise les variables d'état mais on ne crée aucun graphisme.
  2. create_graphics : le framework appelle cette méthode une fois, juste après initialize. C'est là qu'on crée les viewports, la base UI et (plus tard) la composition.
  3. Boucle de mise à jour : à chaque frame, le framework appelle dans l'ordre :
    • update_inputs : gestion des entrées clavier
    • update_mouse(moved) : gestion des entrées souris (ajoutée dans le guide souris)
    • update_graphics : mises à jour des animations
  4. La boucle se répète jusqu'à ce que @running soit mis à false.

Ce cycle est le même pour toutes les scènes PSDK. Le framework gère automatiquement l'équilibrage de frames via la classe BaseCleanUpdate::FrameBalanced. Dans notre scène minimale, on n'a pas encore défini update_mouse -- on l'ajoute dans le guide souris.

Essayez

Une fois les trois fichiers en place, ouvrez la scène depuis un événement de map (« Appel de script ») ou la console PSDK :

GamePlay.open_mystery_gift

Vous devriez voir le fond personnalisé avec un bouton « Quit » en bas, et appuyer sur B ferme la scène.

Conclusion

  • Une scène UI a besoin d'au minimum trois fichiers : 000 Entry.rb (point d'entrée), 003 GamePlay/000 Base.rb (sous-classe de GenericBase) et 003 GamePlay/001 Main.rb (classe de scène).
  • Utilisez toujours GenericBase pour la couche de base UI. Ne reconstruisez jamais manuellement le fond, la barre de boutons ou les boutons ctrl.
  • Le create_viewport hérité crée le viewport en z=10_000.
  • Le tableau button_texts contrôle la visibilité des boutons ctrl : nil cache le bouton, une chaîne l'affiche avec le texte donné.
  • Le framework n'appelle update_inputs que si vous la définissez ; automatic_input_update route un appui touche vers sa méthode action_*. Mettez @running à false pour sortir de la scène.
  • Enregistrez la classe en bas de 001 Main.rb avec GamePlay.mystery_gift_class = GamePlay::MysteryGift.