Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Používání vstupních událostí (InputEvent)
Co to je?
Správa vstupu je obvykle složitá, nehledě na operační systém nebo platformu. Abychom ji trochu usnadnili, je k dispozici speciální vestavěný typ, InputEvent ("vstupní událost"). Tento datový typ lze nakonfigurovat tak, aby obsahoval několik typů vstupních událostí. Vstupní události procházejí enginem a mohou být zpracování na více místech v závislosti na účelu.
Zde je rychlý příklad - ukončení hry při stisknutí klávesy Escape:
func _unhandled_input(event):
if event is InputEventKey:
if event.pressed and event.keycode == KEY_ESCAPE:
get_tree().quit()
public override void _UnhandledInput(InputEvent @event)
{
if (@event is InputEventKey eventKey)
{
if (eventKey.Pressed && eventKey.Keycode == Key.Escape)
{
GetTree().Quit();
}
}
}
Je nicméně čistší a flexibilnější používat dostupný objekt InputMap, který vám umožňuje definovat vstupní akce a přiřadit jim různé klávesy. Takto můžete jedné akci přiřadit více kláves (např. Escape na klávesnici a tlačítko Start na gamepadu). Toto mapování je pak snazší změnit v nastavení projektu, aniž byste museli aktualizovat svůj kód. Navíc nad ním můžete postavit dynamické mapování, které vám umožní měnit přiřazené klávesy akcím za běhu hry!
InputMap můžete nastavit v okně Projekt > Nastavení projektu > Mapa vstupů a poté použít vámi definované akce takto:
func _process(delta):
if Input.is_action_pressed("ui_right"):
# Move right.
public override void _Process(double delta)
{
if (Input.IsActionPressed("ui_right"))
{
// Move right.
}
}
Jak to funguje?
Každá vstupní událost pochází od uživatele/hráče (je nicméně možné InputEvent i vygenerovat a odeslat jej zpět do enginu, což je užitečné pro gesta). DisplayServer ("okenní systém") každé platformy načte události z operačního systému a poté je pošle do kořenového okna Window.
Viewport ("průzor") okna přijatý vstup zpracuje poměrně mnoha způsovy, v tomto pořadí:
Pokud jsou v průzoru vložena okna, pokusí se událost interpretovat jako správce oken (např. pro změnu velikosti nebo přesunutí určitého vloženého okna).
Next if an embedded Window is focused, the event is sent to that Window and processed in the Window's Viewport and afterwards treated as handled. If no embedded Window is focused, the event is sent to the nodes of the current viewport in the following order.
Za prvé, bude zavolána standardní funkce Node._input() ("vstup") v každém uzlu, který ji přepisuje (a nebylo mu zakázáno zpracování vstupu pomocí Node.set_process_input() ("nastavit zpracování vstupu"). Pokud nějaká funkce událost zkonzumuje, může zavolat Viewport.set_input_as_handled() ("označit vstup za zpracovaný") a událost se dále nebude šířit. Tím je zajištěno, že můžete filtrovat všechny události ještě před GUI. Pro herní vstup je obecně vhodnější použít Node._unhandled_input() ("nezpracovaný vstup"), protože umožňuje GUI zachytit události dříve.
Zadruhé se pokusí předložit vstup do GUI a zjistí, zda jej může přijmout nějaký ovládací prvek. Pokud ano, zavolá se odpovídající Control ("ovládací prvek") prostřednictvím virtuální funkce Control._gui_input(), která vyšle signál "gui_input" (tuto funkci lze znovu implementovat pomocí skriptu zděděním od něj). Pokud chce ovládací prvek událost "zkonzumovat", zavolá Control.accept_event() ("přijmout vstup") a událost se dále nebude šířit. Pomocí vlastnosti Control.mouse_filter ("filtr myši") můžete ovládat, zda je Control upozorňován na události myši prostřednictvím zpětného volání Control._gui_input() a zda jsou tyto události dále šířeny.
Pokud dosud událost nikdo nezkonzumoval, bude zavoláno zpětné volání Node._shortcut_input() ("vstup zkratky"), pokud je tato funkce přepsána (a není zakázána pomocí Node.set_process_shortcut_input()). To se stane pouze pro InputEventKey ("klávesová vstupní událost"), InputEventShortcut ("vstupní událost zkratky") a InputEventJoypadButton ("vstupní událost tlačítka joypadu"). Pokud nějaká funkce událost zkonzumuje, může zavolat Viewport.set_input_as_handled() a událost se dále nebude šířit. Zpětné volání vstupu zkratky je ideální pro zpracování událostí, které jsou zamýšleny jako zkratky.
Pokud dosud událost nikdo nezkonzumoval, bude zavoláno zpětné volání Node._unhandled_key_input() ("nezpracovaný klávesový vstup"), pokud je tato funkce přepsána (a není deaktivována pomocí Node.set_process_unhandled_key_input()). To se stane pouze pro InputEventKey. Pokud nějaká funkce událost zkomzumuje, může zavolat Viewport.set_input_as_handled() a událost se dále nebude šířit. Metoda zpětného volání pro nezpracovaný klávesový vstup je ideální pro klávesové události.
Pokud dosud událost nikdo nezkonzumoval, bude zavoláno zpětné volání Node._unhandled_input(), pokud je tato funkce přepsána (a není deaktivována pomocí Node.set_process_unhandled_input()). Pokud nějaká funkce událost zkonzumuje, může zavolat Viewport.set_input_as_handled() a událost se dále nebude šířit. Metoda zpětného volání pro nezpracovaný vstup je ideální pro herní události napříč celou obrazovkou, takže nejsou přijímány, když je aktivní GUI.
Pokud událost zatím nikdo nezpracoval a je zapnuté Vybírání objektů, použije se událost pro výběr objektu. Pro kořenový průzor to lze také povolit v Nastavení projektu. V případě 3D scény, pokud je k průzoru přiřazena Camera3D, vrhne paprsek do fyzikálního světa (v paprskovém směru od kliknutí). Pokud tento paprsek zasáhne objekt, zavolá funkci CollisionObject3D._input_event() v příslušném fyzikálním objektu. V případě 2D scény nastane konceptuálně totéž s CollisionObject2D._input_event().
Když průzor posílá události do svého potomka a podřízených uzlů, provede to od nejhlubšího uzlu nahoru, jak je znázorněno na následujícím obrázku. Začne uzlem ve spodní části stromu scény a skončí v kořenovém uzlu. Z tohoto procesu jsou vyloučena okna a podprůzory.
Poznámka
Toto pořadí se nevztahuje na Control._gui_input(), které používá jinou metodu založenou na poloze události nebo zaměřeném ovládacím prvku. GUI události myši se také pohybují nahoru po stromové struktuře scény, s výhradou výše popsaných omezení Control.mouse_filter. Protože se však tyto události zaměřují na konkrétní ovládací prvky, událost obdrží pouze přímí předci cílového kontrolního uzlu. GUI události klávesnice a joypadu nepostupují po stromové struktuře scény a může je zpracovat pouze ovládací prvek, který je přijal. Jinak budou šířeny jako normální události prostřednictvím Node._unhandled_input().
Protože průzory neodesílají události do jiných SubViewports ("podprůzorů"), je třeba použít jednu z následujících metod:
Použijte SubViewportContainer ("kontejner podprůzorů"), který automaticky odesílá události svým potomkům SubViewports po Node._input() nebo Control._gui_input().
Implementujte propagaci událostí na základě individuálních požadavků.
V souladu s designem Godotu založeným na uzlech toto umožňuje specializovaným podřízeným uzlům zpracovávat a konzumovat konkrétní události, zatímco jejich předci a kořen scény mohou v případě potřeby poskytovat obecnější chování.
Anatomie InputEventu
InputEvent je pouze základní vestavěný typ, nic konkrétního nepředstavuje a obsahuje pouze některé základní informace, jako je ID události (které se zvyšuje pro každou událost), index zařízení atd.
Existuje několik specializovaných typů InputEvent popsaných v tabulce níže:
Událost |
Popis |
InputEvent ("vstupní událost") |
Prázdná vstupní událost. |
InputEventKey ("klávesová vstupní událost") |
Obsahuje kód klávesy, hodnotu Unicode a také modifikátory. |
InputEventMouseButton ("vstupní událost tlačítka myši") |
Obsahuje informace o kliknutí, jako je tlačítko, modifikátory atd. |
InputEventMouseMotion ("vstupní událost pohybu myši") |
Obsahuje informace o pohybu, jako je relativní a absolutní poloha a rychlost. |
InputEventJoypadMotion ("vstupní událost pohybu joypadu") |
Obsahuje informace o analogové ose joysticku/joypadu. |
InputEventJoypadButton ("vstupní událost tlačítka joypadu") |
Obsahuje informace o tlačítku joysticku/joypadu. |
InputEventScreenTouch ("vstupní událost dotyku obrazovky") |
Obsahuje vícedotykové informace o stisknutí/spuštění. (k dispozici pouze na mobilních zařízeních) |
InputEventScreenDrag ("vstupní událost táhnutí obrazovky") |
Obsahuje informace o vícedotykovém přetažení. (k dispozici pouze na mobilních zařízeních) |
InputEventMagnifyGesture ("vstupní událost gesta přiblížení") |
Obsahuje pozici, faktor a také modifikátory. |
InputEventPanGesture ("vstupní událost gesta posunu") |
Obsahuje pozici, deltu a také modifikátory. |
InputEventMIDI ("vstupní událost MIDI") |
Obsahuje informace týkající se MIDI. |
InputEventShortcut ("vstupní událost zkratky") |
Obsahuje zkratku. |
InputEventAction ("vstupní událost akce") |
Obsahuje obecnou akci. Tyto události často generuje programátor jako zpětnou vazbu. (více k tomuto níže) |
Vstupní akce
Vstupní akce jsou seskupení nula nebo více InputEventů pod srozumitelný název (například výchozí akce "ui_left" seskupuje jak vstup z levého joypadu, tak klávesu levé šipky na klávesnici). Nemusí představovat InputEvent, ale jsou užitečné, protože při programování herní logiky abstrahují různé vstupy.
Tento přístup má několik výhod:
Stejný kód funguje na různých zařízeních s různými vstupy (např. klávesnice na PC, joypad na konzoli).
Vstup lze překonfigurovat za běhu.
Akce lze spouštět programově za běhu.
Akce lze vytvořit a přiřadit jim vstupní události v nabídce Nastavení projektu na kartě Mapa vstupu.
Any event has the methods InputEvent.is_action(), InputEvent.is_pressed() and InputEvent.is_echo().
Alternativně může být žádoucí dodat do hry akci v kódu (dobrým příkladem je detekce gest). Singleton Input má metodu přesně pro tento případ: Input.parse_input_event() ("rozebrat vstupní událost"). Normálně byste ji použili takto:
var ev = InputEventAction.new()
# Set as ui_left, pressed.
ev.action = "ui_left"
ev.pressed = true
# Feedback.
Input.parse_input_event(ev)
var ev = new InputEventAction();
// Set as ui_left, pressed.
ev.Action = "ui_left";
ev.Pressed = true;
// Feedback.
Input.ParseInputEvent(ev);
Viz také
Pro návod ke přidávání vstupních akcí v nastavení projektu viz Vytváření vstupních akcí.
Mapa vstupů (InputMap)
Přizpůsobení a přemapování vstupu v kódu je často žádoucí. Pokud celý váš pracovní postup závisí na akcích, je singleton InputMap ideální pro opětovné přiřazení nebo vytváření různých akcí za běhu. Tento singleton se neukládá (je nutné jej upravit ručně) a jeho stav se spouští z nastavení projektu (project.godot). Každý dynamický systém tohoto typu tak musí ukládat nastavení způsobem, který programátor nejlépe uzná za vhodný.