控制器、手柄和摇杆
Godot支持数百种控制器模型,这要归功于社区提供的 SDL游戏控制器数据库 。
控制器支持Windows、macOS、Linux、Android、iOS和HTML5。
请注意,诸如方向盘、方向盘踏板和 HOTAS 等更专业的设备测试较少,可能并不总是按照预期工作。目前尚未实现在这些设备上的力反馈覆盖。如果你有机会使用这些设备,请不要犹豫,在 GitHub 上报告错误。
在本指南中,您将学会:
如何编写你的输入逻辑,从而支持键盘和控制器输入。
控制器的行为如何与键盘/鼠标输入不同。
解决 Godot 中控制器的问题。
支持通用导出
得益于 Godot 的输入动作系统,Godot 可以同时支持键盘和控制器输入,而不需要编写单独的代码路径。你不应该在脚本中对控制器的按键进行硬编码,应该在项目设置中创建输入动作,这些动作引用按键和控制器输入。
输入动作在 使用 InputEvent 页面上有详细解释。
备注
与键盘输入不同,支持鼠标和控制器输入的动作将需要不同的代码路径,例如在第一人称游戏中四处查看,因为这些必须被分开处理。
我应该使用哪个输入单例方法?
有3种方式可以以模拟感知的方式获得输入:
- 当你有两个轴,如操纵杆或WASD运动,并希望两个轴都表现为单一输入时,使用
Input.get_vector()
:
GDScriptC#
# `velocity` will be a Vector2 between `Vector2(-1.0, -1.0)` and `Vector2(1.0, 1.0)`.
# This handles deadzone in a correct way for most use cases.
# The resulting deadzone will have a circular shape as it generally should.
var velocity = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
# The line below is similar to `get_vector()`, except that it handles
# the deadzone in a less optimal way. The resulting deadzone will have
# a square-ish shape when it should ideally have a circular shape.
var velocity = Vector2(Input.get_action_strength("move_right") - Input.get_action_strength("move_left"),
Input.get_action_strength("move_back") - Input.get_action_strength("move_forward")).clamped(1)
// `velocity` will be a Vector2 between `Vector2(-1.0, -1.0)` and `Vector2(1.0, 1.0)`.
// This handles deadzone in a correct way for most use cases.
// The resulting deadzone will have a circular shape as it generally should.
Vector2 velocity = Input.GetVector("move_left", "move_right", "move_forward", "move_back");
// The line below is similar to `get_vector()`, except that it handles
// the deadzone in a less optimal way. The resulting deadzone will have
// a square-ish shape when it should ideally have a circular shape.
Vector2 velocity = new Vector2(Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left"),
Input.GetActionStrength("move_back") - Input.GetActionStrength("move_forward")).Clamped(1);
- 当你有一个轴可以双向移动时,比如飞行操纵杆上的油门,或者你想单独处理不同的轴时,使用
Input.get_axis()
:
GDScriptC#
# `walk` will be a floating-point number between `-1.0` and `1.0`.
var walk = Input.get_axis("move_left", "move_right")
# The line above is a shorter form of:
var walk = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
// `walk` will be a floating-point number between `-1.0` and `1.0`.
float walk = Input.GetAxis("move_left", "move_right");
// The line above is a shorter form of:
float walk = Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left");
- 对于其他类型的模拟输入,例如处理一个触发器或一次处理一个方向,使用
Input.get_action_strength()
:
GDScriptC#
# `strength` will be a floating-point number between `0.0` and `1.0`.
var strength = Input.get_action_strength("accelerate")
// `strength` will be a floating-point number between `0.0` and `1.0`.
float strength = Input.GetActionStrength("accelerate");
对于非模拟数字/布尔输入(只有 “按下 “ 或 “未按下 “ 的值),如控制器按钮、鼠标按钮或键盘按键,使用 Input.is_action_pressed()
:
GDScript
# `jumping` will be a boolean with a value of `true` or `false`.
var jumping = Input.is_action_pressed("jump")
C#
// `jumping` will be a boolean with a value of `true` or `false`.
bool jumping = Input.IsActionPressed("jump");
在3.4之前的Godot版本,如3.3, Input.get_vector()
和 Input.get_axis()
不可用。只有 Input.get_action_strength()
和 Input.is_action_pressed()
在Godot 3.3中可用。
键盘/鼠标和控制器输入之间的差异
如果您习惯于处理键盘和鼠标输入,可能会对控制器处理特定情况的方式感到惊讶。
死区
与键盘和鼠标不同,控制器提供带有模拟输入的轴。模拟输入的好处是它们为动作提供了额外的灵活性。不像数字输入只能提供 0.0
和 1.0
的强度,模拟输入可以提供 0.0
和 1.0
之间的任何强度。缺点是没有死区系统,由于控制器的物理结构,模拟轴的强度永远不会等于 0.0
。相反,它将徘徊在一个低值,如 0.062
。这种现象被称为漂移,在旧的或有问题的控制器上会更加明显。
让我们把赛车游戏作为一个现实世界的例子。由于有了模拟输入,我们可以将汽车慢慢地转向一个或另一个方向。然而,如果没有死区系统,即使玩家不接触操纵杆,汽车也会自己慢慢转向。这是因为方向轴的强度在我们期望的时候不会等于 0.0
。因为我们不希望我们的车在这种情况下自动转向,我们定义了一个“死区”值 0.2
,它将忽略所有强度低于 0.2
的输入。一个理想的死区值是足够高的,可以忽略操纵杆漂移引起的输入,但又足够低,不会忽略玩家的实际输入。
Godot 有一个内置的死区系统来解决这个问题。默认值是 0.2
,但你可以在“项目设置”的“按键映射”选项卡中根据每个动作增加或减少它。对于 Input.get_vector()
,可以指定死区,否则它将从向量中的所有动作计算出平均死区值。
“回声”事件
与键盘输入不同,按住一个控制器按钮,如十字方向键,不会产生固定间隔的重复输入事件(也被称为“回声”事件)。这是因为操作系统首先不会为控制器输入发送“回声”事件。
如果你想让控制器按钮发送回声事件,你将不得不通过代码生成 InputEvent 对象,并使用 Input.parse_input_event() 定期解析它们。这可以在 Timer 节点的帮助下完成。
故障排除
参见
你可以在 GitHub 上查看控制器支持的已知问题列表。
Godot 无法识别我的控制器。
首先,检查你的控制器是否被其他应用程序识别。你可以使用 Gamepad Tester 网站来确认你的控制器被识别。
我的控制器的按钮或轴映射不正确。
如果按钮存在映射错误,可能是由于来自 SDL 游戏控制器数据库的错误的映射。你可以在链接的仓库中提交拉取请求,为下一个 Godot 版本提供映射更新。
有很多方法来创建映射。一个选择是使用 官方Joypads演示 中的映射向导。一旦你有了控制器可工作的映射,你可以在运行Godot之前通过定义 SDL_GAMECONTROLLERCONFIG
环境变量来测试它:
Linux/macOSWindows (cmd)Windows (powershell)
export SDL_GAMECONTROLLERCONFIG="your:mapping:here"
./path/to/godot.x86_64
set SDL_GAMECONTROLLERCONFIG=your:mapping:here
path\to\godot.exe
$env:SDL_GAMECONTROLLERCONFIG="your:mapping:here"
path\to\godot.exe
要在非桌面平台上测试映射,或者用额外的控制器映射来分发你的项目,你可以通过调用 Input.add_joy_mapping() 尽早在脚本的 _ready()
函数中添加它们。
我的控制器在特定的平台上工作,但在另一个平台上却不能。
Linux
在 Godot 3.3 之前,官方的 Godot 可执行文件在编译时支持 udev,但自编译的可执行文件在编译时不支持 udev,除非在 SCons 命令行中传递 udev=yes
。这使得控制器的热插拔支持在自编译的可执行文件中不可用。
HTML5
与 “本地” 平台相比,HTML5 控制器的支持通常不太可靠。各个浏览器对控制器的支持质量往往相差甚远。因此,如果玩家无法使用他们的控制器,你可能不得不指示他们使用不同的浏览器。
另外,请注意,在 Godot 3.3 及以后的版本中,对控制器的支持得到了很大的改善。