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 appelleInput.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_inputset la constanteAIU_KEY2METHODdoivent rester publics (au-dessus deprivate). Le framework appelleupdate_inputsdepuis 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 unupdate_inputs/action_btemporaire directement dans001 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_KEY2METHODassocie une touche à un nom de méthode. On liste déjàA: :action_aici, mais on ne définit queaction_bpour l'instant --automatic_input_updatevérifierespond_to?avant d'appeler, donc appuyer sur A ne fait simplement rien jusqu'à ce qu'on ajouteaction_adans le guide dialogues.@composition.done?bloque les entrées pendant qu'une animation joue. Elle renvoie toujourstrueaujourd'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érifieInput.trigger?pour chaque touche mappée et appelle la méthode correspondante. Elle renvoiefalsequand elle a consommé un appui, ce qu'on propage pour stopper le traitement suivant.update_navigationgère les flèches séparément avecInput.repeat?. Elle renvoiefalsepour consommer l'input,truepour laisser le traitement continuer.play_cursor_seetplay_cancel_sesont les effets sonores standard de navigation et d'annulation, hérités deGamePlay::Base.action_bpasse@runningàfalsepour 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_rowmet 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_selectioncalcule le nouvel index, clampé pour que le curseur s'arrête aux bords de la liste. Elle renvoietrueseulement 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_countboucle : dépasser la dernière entrée revient à la première, et inversement.- Utilisez
.clamp(0, max)pour une liste bornée,% sizepour 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_inputsetAIU_KEY2METHODdoivent être publics -- le framework appelleupdate_inputsdepuis l'extérieur.- Les touches boutons (A/B) utilisent
Input.trigger?viaautomatic_input_update; les touches directionnelles (UP/DOWN) utilisentInput.repeat?. automatic_input_updateignore 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
.clamppour une liste bornée, le modulo pour un menu qui boucle.