Use when working with 2D-specific systems — TileMaps, parallax scrolling, 2D lights and shadows, canvas layers, particles 2D, custom drawing, and 2D meshes in Godot 4.3+
中文简介正在准备中。当前显示原文说明。
Use when implementing input — InputEvent system, Input Map actions, controllers/gamepads, mouse/touch, action rebinding, and input architecture
中文简介正在准备中。当前显示原文说明。
查看安装方法安装前可以查看交给 AI 代理的指令内容。
All examples target Godot 4.3+ with no deprecated APIs. GDScript is shown first, then C#.
Related skills: player-controller for movement driven by input, godot-ui for UI input focus and navigation, save-load for persisting custom key bindings, responsive-ui for touch vs desktop input adaptation, xr-development for XR controller and hand tracking input, mobile-development for mobile sensors and app lifecycle.
Hardware Event (key, mouse, gamepad)
↓
Engine converts to InputEvent
↓
_input() ← raw input, runs first
↓
UI Control nodes ← _gui_input: buttons, sliders consume events
↓
_shortcut_input() ← for global shortcuts
↓
_unhandled_key_input() ← unhandled key-only events
↓
_unhandled_input() ← game input (movement, actions)
| Method | Use For | When It Runs |
|---|---|---|
_input() | Camera look, global hotkeys | First — before everything |
_shortcut_input() | Global shortcuts (pause, screenshot) | After UI, before unhandled |
_unhandled_key_input() | Key-only events that UI didn't consume | After UI, keys only |
_unhandled_input() | Gameplay actions (jump, attack, interact) | Last — after UI consumes |
Input.is_action_pressed() in _physics_process() | Continuous movement | N/A — polling, not event-driven |
Rule of thumb: Use _unhandled_input() for discrete game actions (jump, attack). Use Input polling in _physics_process() for continuous movement. Use _input() only when you need input before UI consumes it (e.g., mouse look).
InputEvent
├── InputEventFromWindow
│ ├── InputEventWithModifiers
│ │ ├── InputEventKey ← keyboard
│ │ ├── InputEventMouse
│ │ │ ├── InputEventMouseButton ← mouse clicks
│ │ │ └── InputEventMouseMotion ← mouse movement
│ │ └── InputEventGesture ← Magnify / Pan gestures
│ ├── InputEventScreenTouch ← touchscreen tap
│ └── InputEventScreenDrag ← touchscreen drag
├── InputEventJoypadButton ← gamepad buttons
├── InputEventJoypadMotion ← gamepad sticks/triggers
├── InputEventAction ← synthetic action events
├── InputEventMIDI ← MIDI devices
└── InputEventShortcut
Define actions in Project > Project Settings > Input Map instead of checking raw keycodes. This decouples game logic from specific keys and enables rebinding.
Godot ships with ui_* actions: ui_accept, ui_cancel, ui_left, ui_right, ui_up, ui_down, etc. These are used by UI controls for keyboard navigation. You can use them for gameplay but creating custom actions is preferred to avoid conflicts.
Actions can be created at runtime with InputMap.add_action() + InputMap.action_add_event() — typically in an autoload _ready(), guarded by InputMap.has_action(). Define actions in the editor Input Map; only add them in code for dynamically generated bindings or mod support.
See references/action-rebinding.md for the GDScript and C# snippet.
Use descriptive, game-specific names instead of key names:
| Good | Bad | Why |
|---|---|---|
move_left | press_a | Decoupled from physical key |
attack | left_click | Works for mouse and gamepad |
interact | press_e | Rebindable without changing logic |
sprint | hold_shift | Input-agnostic |
pause | press_escape | Can map to gamepad Start button too |
Use _unhandled_input() for one-shot actions: jump, attack, interact, pause.
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("jump"):
_jump()
get_viewport().set_input_as_handled() # prevent further propagation
if event.is_action_pressed("interact"):
_interact()
if event.is_action_pressed("pause"):
get_tree().paused = not get_tree().paused
get_viewport().set_input_as_handled()
public override void _UnhandledInput(InputEvent @event)
{
if (@event.IsActionPressed("jump"))
{
Jump();
GetViewport().SetInputAsHandled();
}
if (@event.IsActionPressed("interact"))
Interact();
if (@event.IsActionPressed("pause"))
{
GetTree().Paused = !GetTree().Paused;
GetViewport().SetInputAsHandled();
}
}
Use Input singleton in _physics_process() for held buttons and analog axes.
func _physics_process(delta: float) -> void:
# Movement vector from 4 directional actions
var direction := Input.get_vector("move_left", "move_right", "move_up", "move_down")
velocity = direction * speed
# Check if a button is held
if Input.is_action_pressed("sprint"):
velocity *= 1.5
move_and_slide()
public override void _PhysicsProcess(double delta)
{
Vector2 direction = Input.GetVector("move_left", "move_right", "move_up", "move_down");
Velocity = direction * Speed;
if (Input.IsActionPressed("sprint"))
Velocity *= 1.5f;
MoveAndSlide();
}
| Method | Returns | Use For |
|---|---|---|
Input.is_action_pressed() | bool | Held buttons (sprint, crouch, fire) |
Input.is_action_just_pressed() | bool | One-shot triggers (jump, interact) |
Input.is_action_just_released() | bool | Release triggers (variable jump cut) |
Input.get_action_strength() | float | Analog pressure (0.0–1.0) |
Input.get_axis() | float | Single axis (-1.0 to 1.0) |
Input.get_vector() | Vector2 | 2D direction, length capped at 1 |
event.is_action_pressed() | bool | Check in _unhandled_input callback |
event.is_action_released() | bool | Check in _unhandled_input callback |
Input.is_action_just_pressed()in_physics_process()reports a press on the next physics tick, even if the key was already released — a low tick rate does not drop taps, but several presses inside one tick count once. When each press matters, catch it in_unhandled_input()and set a flag.
Buffer discrete actions so a press made shortly before it can take effect (jump just before landing) still counts: catch the action in _unhandled_input(), set a flag with a short timer (0.1 s is typical), and consume the flag in _physics_process().
See references/input-buffering.md for the full GDScript and C# jump-buffer implementation.
InputEventMouseMotion.relative for camera look (with Input.MOUSE_MODE_CAPTURED), InputEventMouseButton for clicks. Mouse modes: VISIBLE, HIDDEN, CAPTURED, CONFINED. Custom cursor via Input.set_custom_mouse_cursor(texture, shape, hotspot).
See references/mouse.md for the full GDScript and C# recipes (camera-look with sensitivity + invert toggle, mouse-mode switching, button events, custom cursor with shape variants).
Input.get_connected_joypads() for runtime detection, Input.joy_connection_changed signal for hot-plug. Use Input Map actions with joypad button events for portability. Analog sticks: Input.get_vector("left", "right", "up", "down", deadzone) returns a length-clamped Vector2 with built-in deadzone.
See references/gamepad.md for the GDScript and C# recipes (controller detection, deadzone analog reading, vibration via
start_joy_vibration, motion sensors, detecting last-input-device for UI prompt swapping).
Godot 4.7+: Joypad motion sensors —
Input.get_joy_accelerometer(device)/get_joy_gyroscope(device)(bothVector3), guarded byhas_joy_motion_sensors()and enabled withset_joy_motion_sensors_enabled(); recipe in references/gamepad.md. Vibration is now queryable —Input.has_joy_vibration(device)plusget_joy_vibration_strength/duration/remaining_duration().JoyButtongainsJOY_BUTTON_MISC2(21) throughJOY_BUTTON_MISC6(25) (C#:JoyButton.Misc2…). New project settinginput_devices/joypads/ignore_joypad_on_unfocused_application(defaultfalse) ignores joypad input (including motion sensors) and LED changes and stops vibration while the app is unfocused.
InputEventScreenTouch for tap/release, InputEventScreenDrag for finger drag; multi-touch is tracked by event.index. To test on desktop, enable Project Settings → Input Devices → Pointing → Emulate Touch From Mouse; Emulate Mouse From Touch is on by default so UI works on touchscreens.
See references/touch.md for the touch event recipes (GDScript and C#) and the
VirtualJoystickon-screen stick (Godot 4.7+).
Three steps: (1) capture the user's chosen key via _input while in "rebinding" mode, (2) call InputMap.action_erase_events(action) then InputMap.action_add_event(action, new_event), (3) persist via ConfigFile and reload on launch.
See references/action-rebinding.md for the full GDScript and C# rebinding flow including ConfigFile save/load and the typical "press a key" capture UI.
Input propagates in reverse scene tree order (the node lowest in the Scene dock first, root last); call get_viewport().set_input_as_handled() after consuming an event to stop it reaching other nodes. During pause, only nodes with process_mode PROCESS_MODE_ALWAYS or PROCESS_MODE_WHEN_PAUSED receive input.
See references/event-propagation.md for the GDScript and C# recipes (stopping propagation, node processing order, receiving input while paused).
| Symptom | Cause | Fix |
|---|---|---|
| Action not recognized | Action name not defined in Input Map | Add the action in Project > Project Settings > Input Map |
| Fast repeated presses count once | is_action_just_pressed() polled in _physics_process; presses share one tick | Catch discrete actions in _unhandled_input() instead |
| Input still fires when UI is open | Using _input() instead of _unhandled_input() | Switch to _unhandled_input() so UI consumes events first |
| Mouse look works through menus | Mouse motion in _input() without mode check | Guard with if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED |
| Gamepad stick drifts | Deadzone too low or not set | Set deadzone per-action in Input Map (0.2 is a good default) |
| Controller not detected | Not connected before game start | Connect joy_connection_changed signal, handle hot-plug |
| Key rebinding captures modifier keys | No filter for Shift/Ctrl/Alt alone | Skip events where keycode is a modifier key |
| Touch input doesn't work on desktop | "Emulate Touch From Mouse" is disabled | Enable in Project Settings > Input Devices > Pointing |
| Pause menu ignores input while paused | Node process_mode is INHERIT (pauses with parent) | Set pause menu to PROCESS_MODE_ALWAYS |
| Action triggers twice per press | Same action checked in both _input and _unhandled_input | Pick one callback per action |
⚠️ Changed in Godot 4.7: Mouse and keyboard device IDs changed from
0toInputEvent.DEVICE_ID_MOUSE(32) andInputEvent.DEVICE_ID_KEYBOARD(16), because some joypads use0as their device ID. Code checkingevent.device == 0to detect keyboard/mouse input silently breaks — compare against the constants or check the event type (event is InputEventKey) instead. See the 4.7 migration guide.
_unhandled_input(), not polling in _physics_process()Input.get_vector() / Input.is_action_pressed() in _physics_process()Input.mouse_mode == MOUSE_MODE_CAPTURED to avoid rotating through menusprocess_mode = PROCESS_MODE_ALWAYS to receive input while pausedget_viewport().set_input_as_handled() is called after consuming events that shouldn't propagateuser:// on game launch还没有评价。欢迎分享你的使用感受。
无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。
还没有评论。来写第一条吧。
Use when working with 2D-specific systems — TileMaps, parallax scrolling, 2D lights and shadows, canvas layers, particles 2D, custom drawing, and 2D meshes in Godot 4.3+
中文简介正在准备中。当前显示原文说明。
Use when working with 3D-specific systems — materials, lighting, shadows, environment, global illumination, fog, LOD, occlusion culling, and decals in Godot 4.3+
中文简介正在准备中。当前显示原文说明。
Use when building character abilities — Resource-based abilities with cost/cooldown/cast, buffs/debuffs, stat modifiers, gameplay tags, and HUD binding
中文简介正在准备中。当前显示原文说明。
Use when creating Godot editor plugins — EditorPlugin, @tool scripts, custom inspectors, and dock panels
中文简介正在准备中。当前显示原文说明。
Use when implementing AI movement — NavigationAgent2D/3D, steering behaviors, behavior trees, and patrol patterns
中文简介正在准备中。当前显示原文说明。
Use when implementing animations — AnimationPlayer, AnimationTree, blend trees, state machines, sprite animation, and code-driven animation
中文简介正在准备中。当前显示原文说明。