Godot输入
Godot 的输入系统强大而灵活,不仅支持键盘、鼠标、手柄,还可以很方便地自定义输入映射和处理多种输入事件。本教程将从以下几个方面展开:
1️⃣ 输入系统基础:Input 类和 InputEvent
2️⃣ 使用输入映射 (Input Map)
3️⃣ 处理复杂输入:组合键、连击、按住检测
4️⃣ 多点触控与手柄输入
5️⃣ 实践示例:移动角色、瞄准射击、UI 输入分离
1️⃣ 输入系统基础
Godot 通过两种核心机制处理输入:
Input
单例类:用于轮询输入状态(如Input.is_action_pressed()
)InputEvent
:用于捕获事件驱动输入(如_input(event)
或_unhandled_input(event)
)
🚩 使用 Input
轮询输入(C#)
using Godot;
public partial class InputExample : Node
{
public override void _Process(double delta)
{
if (Input.IsActionPressed("ui_right"))
{
GD.Print("Right key is held down");
}
if (Input.IsActionJustPressed("ui_accept"))
{
GD.Print("Accept key was just pressed");
}
}
}
is_action_pressed
与 is_action_just_pressed
的区别:
前者用于持续检测是否按住。
后者只在按下那一帧触发一次。
🚩 使用 _Input
捕获输入事件(C#)
using Godot;
public partial class InputEventExample : Node
{
public override void _Input(InputEvent @event)
{
if (@event is InputEventKey keyEvent && keyEvent.Pressed)
{
GD.Print($"Key pressed: {keyEvent.Keycode}");
}
if (@event is InputEventMouseButton mouseEvent && mouseEvent.ButtonIndex == MouseButton.Left)
{
if (mouseEvent.Pressed)
GD.Print($"Left mouse button down at {mouseEvent.Position}");
}
}
}
_input
会捕获所有输入事件,通常用于需要精准事件信息的场景。
2️⃣ 使用输入映射 (Input Map)
Godot 的输入映射允许你为动作(Action)分配多个物理按键或设备输入,方便跨平台和自定义按键。
👉 配置位置:Project > Project Settings > Input Map
例如添加:
move_left
:A 键、左箭头jump
:Space 键
在脚本里使用:
using Godot;
public partial class InputMapExample : Node
{
public override void _Process(double delta)
{
if (Input.IsActionPressed("jump"))
{
GD.Print("Jumping!");
}
}
}
💡 热更新输入映射:
using Godot;
public partial class AddInputMapExample : Node
{
public override void _Ready()
{
InputMap.AddAction("dash");
var dashEvent = new InputEventKey();
dashEvent.Keycode = Key.Shift;
InputMap.ActionAddEvent("dash", dashEvent);
}
}
3️⃣ 处理复杂输入
✅ 组合键
例如,按住 Shift + 方向键:
using Godot;
public partial class ComboKeyExample : Node
{
public override void _Process(double delta)
{
if (Input.IsActionPressed("ui_up") && Input.IsKeyPressed(Key.Shift))
{
GD.Print("Running up with Shift");
}
}
}
✅ 检测长按
using Godot;
public partial class LongPressExample : Node
{
private double _holdTime = 0.0;
public override void _Process(double delta)
{
if (Input.IsActionPressed("jump"))
{
_holdTime += delta;
if (_holdTime > 1.0)
{
GD.Print("Jump held for over 1 second");
}
}
else
{
_holdTime = 0.0;
}
}
}
✅ 双击/连击
using Godot;
public partial class DoubleClickExample : Node
{
private double _lastClickTime = 0.0;
private double _doubleClickThreshold = 0.3;
public override void _Input(InputEvent @event)
{
if (@event is InputEventMouseButton mouseEvent && mouseEvent.ButtonIndex == MouseButton.Left && mouseEvent.Pressed)
{
double now = Time.GetTicksMsec() / 1000.0;
if (now - _lastClickTime < _doubleClickThreshold)
{
GD.Print("Double click!");
}
_lastClickTime = now;
}
}
}
4️⃣ 多点触控 & 手柄输入
✅ 多点触控
using Godot;
public partial class MultiTouchExample : Node
{
public override void _Input(InputEvent @event)
{
if (@event is InputEventScreenTouch touchEvent)
{
if (touchEvent.Pressed)
{
GD.Print($"Finger {touchEvent.Index} touched at {touchEvent.Position}");
}
}
}
}
Godot 自动区分多点触控,每个手指对应不同的 index
。
✅ 手柄输入
using Godot;
public partial class JoystickExample : Node
{
public override void _Process(double delta)
{
float leftStickX = Input.GetJoyAxis(0, JoyAxis.LeftX);
float leftStickY = Input.GetJoyAxis(0, JoyAxis.LeftY);
GD.Print($"Left Stick: {new Vector2(leftStickX, leftStickY)}");
if (Input.IsJoyButtonPressed(0, JoyButton.A))
{
GD.Print("A button pressed");
}
}
}
0
是手柄 ID。JOY_AXIS_*
和JOY_BUTTON_*
是内置常量。
5️⃣ 实践示例:移动、射击、UI 输入分离
✅ 角色移动与瞄准
using Godot;
public partial class Player : CharacterBody2D
{
[Export] public float Speed = 200.0f;
public override void _PhysicsProcess(double delta)
{
Vector2 direction = Vector2.Zero;
if (Input.IsActionPressed("move_right"))
direction.X += 1;
if (Input.IsActionPressed("move_left"))
direction.X -= 1;
if (Input.IsActionPressed("move_up"))
direction.Y -= 1;
if (Input.IsActionPressed("move_down"))
direction.Y += 1;
if (direction != Vector2.Zero)
Velocity = direction.Normalized() * Speed;
else
Velocity = Vector2.Zero;
MoveAndSlide();
}
}
✅ UI 输入分离
对于 UI,使用 _unhandled_input
来防止与游戏输入冲突:
using Godot;
public partial class UIInputExample : Node
{
public override void _UnhandledInput(InputEvent @event)
{
if (@event is InputEventKey keyEvent && keyEvent.Keycode == Key.Escape)
{
GD.Print("Escape pressed, open pause menu");
}
}
}
当输入被 UI 节点消费(如 Button),它不会传递到 _unhandled_input
。
🔑 小结
✅ Input
:轮询式,适合持续状态检测
✅ _input
:事件驱动,适合捕获精准信息
✅ 输入映射:跨平台兼容 + 可自定义
✅ 手柄/多点触控:跨设备支持
✅ 分离 UI 与游戏输入,防止冲突
📂 进阶:自动化输入录制与回放
Godot 支持记录输入事件保存为 JSON,方便重放或制作测试用例:
using Godot;
using System.Collections.Generic;
public partial class InputRecorder : Node
{
private List<Godot.InputEvent> recording = new List<Godot.InputEvent>();
public override void _Input(InputEvent @event)
{
// 录制事件,存进列表
recording.Add(@event.Duplicate() as InputEvent); // 建议 Duplicate,避免引用问题
}
public void SaveInput()
{
// 将输入事件序列化成 JSON
var data = new Godot.Collections.Array();
foreach (var evt in recording)
{
data.Add(evt);
}
string json = JSON.Stringify(data);
using var file = FileAccess.Open("res://input.json", FileAccess.ModeFlags.Write);
file.StoreString(json);
file.Close();
🚀 结语
掌握输入系统是成为 Godot 高阶用户的必经之路,尤其是跨平台项目、多人游戏、复杂 UI,输入设计尤为重要。