Aller au contenu principal
Voir
Mystery Gift — Etape 6 / 11Gérer les entrées clavier
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

Gérer les entrées clavier

Ce guide s'appuie sur le guide couche de données : la scène affiche maintenant les cadeaux réclamés par le joueur. Ici, on ajoute la gestion clavier -- naviguer dans la liste avec les flèches et quitter avec B -- et on sort le code d'entrée de 001 Main.rb vers son propre fichier.

Principe

Les entrées clavier se répartissent en deux mécanismes :

  • Touches boutons (A/B/X/Y) : gérées par automatic_input_update, qui appelle Input.trigger? -- le bouton se déclenche une fois par appui.
  • Touches directionnelles (UP/DOWN) : gérées avec Input.repeat? -- la touche se déclenche en continu tant qu'elle est maintenue, après un délai initial.

Deux règles importantes :

  • update_inputs et la constante AIU_KEY2METHOD doivent rester publics (au-dessus de private). Le framework appelle update_inputs depuis l'extérieur de la classe ; si elle était privée, le framework ne pourrait pas l'atteindre.
  • La gestion des entrées vit dans son propre fichier qui rouvre la classe de scène (003 Input.rb). Dans le guide de la scène, on avait mis un update_inputs/action_b temporaire directement dans 001 Main.rb ; on les déplace maintenant ici et on les étoffe. Les mêmes méthodes d'action sont partagées par le clavier et la souris.

Le fichier Input

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

module GamePlay
# Keyboard input handling for the Mystery Gift scene
class MysteryGift < BaseCleanUpdate::FrameBalanced
# Key-to-action mapping
AIU_KEY2METHOD = { A: :action_a, B: :action_b }

# Handle keyboard input each frame
# @return [Boolean]
def update_inputs
return false unless @composition.done?
return false unless automatic_input_update(AIU_KEY2METHOD)

return update_navigation
end

private

# Handle directional key navigation in the gift list
# @return [Boolean]
def update_navigation
if Input.repeat?(:UP)
play_cursor_se if @composition.move_selection(-1)
return false
elsif Input.repeat?(:DOWN)
play_cursor_se if @composition.move_selection(1)
return false
end

return true
end

# Action triggered by the B button -- quit
def action_b
play_cancel_se
@running = false
end
end
end
  • AIU_KEY2METHOD associe une touche à un nom de méthode. On liste déjà A: :action_a ici, mais on ne définit que action_b pour l'instant -- automatic_input_update vérifie respond_to? avant d'appeler, donc appuyer sur A ne fait simplement rien jusqu'à ce qu'on ajoute action_a dans le guide dialogues.
  • @composition.done? bloque les entrées pendant qu'une animation joue. Elle renvoie toujours true aujourd'hui (pas encore d'animation), mais brancher la garde maintenant fait que les entrées seront automatiquement bloquées une fois les animations ajoutées.
  • automatic_input_update(AIU_KEY2METHOD) vérifie Input.trigger? pour chaque touche mappée et appelle la méthode correspondante. Elle renvoie false quand elle a consommé un appui, ce qu'on propage pour stopper le traitement suivant.
  • update_navigation gère les flèches séparément avec Input.repeat?. Elle renvoie false pour consommer l'input, true pour laisser le traitement continuer.
  • play_cursor_se et play_cancel_se sont les effets sonores standard de navigation et d'annulation, hérités de GamePlay::Base.
  • action_b passe @running à false pour sortir de la scène.

Comme ce fichier rouvre GamePlay::MysteryGift, retirez les update_inputs et action_b temporaires de 001 Main.rb -- ils vivent ici désormais. 001 Main.rb devient :

module GamePlay
# Mystery Gift scene -- displays the player's claimed gifts
class MysteryGift < BaseCleanUpdate::FrameBalanced
include UI::MysteryGift

# Create the scene
def initialize
super
@running = true
$user_data[:mystery_gift] ||= PFM::MysteryGift.new
end

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

private

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

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

# Create the composition
def create_composition
@composition = Composition.new(@viewport, $user_data[:mystery_gift])
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
end
end

GamePlay.mystery_gift_class = GamePlay::MysteryGift

La sélection dans la Composition

La navigation demande à la Composition de déplacer la ligne sélectionnée. Ajoutez ces deux méthodes publiques à scripts/20 MysteryGift/002 UI/999 Composition.rb (à côté de refresh) :

# Select a row by index
# @param index [Integer]
def select_row(index)
@rows.each_with_index { |row, row_index| row.selected = (row_index == index) }
@selected_index = index
end

# Move selection by delta, clamped to the valid range
# @param delta [Integer] -1 for up, +1 for down
# @return [Boolean] true if the selection changed
def move_selection(delta)
gift_count = @mystery_data.claimed_count
return false if gift_count == 0

new_index = (@selected_index + delta).clamp(0, [gift_count - 1, VISIBLE_ROWS - 1].min)
return false if new_index == @selected_index

select_row(new_index)
return true
end
  • select_row met en surbrillance une ligne et stocke son index dans @selected_index. Elle est aussi réutilisée par la gestion souris dans le guide suivant.
  • move_selection calcule le nouvel index, clampé pour que le curseur s'arrête aux bords de la liste. Elle renvoie true seulement si la sélection a réellement changé -- la scène s'en sert pour ne jouer le son de curseur que quand quelque chose a bougé.
  • La borne haute du clamp est [gift_count - 1, VISIBLE_ROWS - 1].min : on ne peut pas sélectionner au-delà du nombre de cadeaux réclamés, ni au-delà du nombre de lignes visibles.

Bouclage vs clamp

Mystery Gift utilise .clamp : le curseur s'arrête à la première et à la dernière entrée. Pour un menu où le curseur doit revenir au début après le dernier élément, utilisez plutôt le modulo :

# Wrap the index around (loops back to the start)
new_index = (@selected_index + delta) % gift_count
  • % gift_count boucle : dépasser la dernière entrée revient à la première, et inversement.
  • Utilisez .clamp(0, max) pour une liste bornée, % size pour un menu qui boucle. Le choix dépend de la scène.

Essayez

Réclamez quelques codes depuis la console pour avoir de quoi naviguer, puis ouvrez la scène :

$user_data[:mystery_gift].claim('POTION50')
$user_data[:mystery_gift].claim('MASTERBALL')
GamePlay.open_mystery_gift

UP et DOWN déplacent la surbrillance entre les deux lignes (avec le son de curseur), et B ferme la scène.

Conclusion

  • update_inputs et AIU_KEY2METHOD doivent être publics -- le framework appelle update_inputs depuis l'extérieur.
  • Les touches boutons (A/B) utilisent Input.trigger? via automatic_input_update ; les touches directionnelles (UP/DOWN) utilisent Input.repeat?.
  • automatic_input_update ignore les touches dont la méthode d'action n'est pas encore définie, donc vous pouvez mapper une touche avant d'implémenter son action.
  • La gestion des entrées rouvre la classe de scène dans son propre fichier (003 Input.rb) ; les méthodes d'action sont partagées avec la souris.
  • Vérifiez toujours @composition.done? avant d'accepter une entrée.
  • Utilisez .clamp pour une liste bornée, le modulo pour un menu qui boucle.