鼠标和键盘输入处理
在上一节中,我们介绍了如何在Godot引擎中创建和管理UI元素。接下来,我们将深入探讨如何处理鼠标和键盘输入,以实现用户与UI的交互。用户输入是任何游戏开发中不可或缺的一部分,特别是在动作游戏中,玩家需要通过键盘和鼠标进行快速、精确的操作。本节将详细介绍如何在Godot引擎中捕捉和处理这些输入,包括基本的输入检测、事件处理和高级的输入映射。
基本输入检测
在Godot引擎中,处理鼠标和键盘输入的基本方法是通过 _input
函数。这个函数在每次输入事件发生时都会被调用。我们可以通过检查事件类型来确定是鼠标事件还是键盘事件。
_input
函数
extends Node
func _input(event):
# 检查事件类型
if event is InputEventKey:
_handle_keyboard_input(event)
elif event is InputEventMouse:
_handle_mouse_input(event)
elif event is InputEventMouseButton:
_handle_mouse_button_input(event)
elif event is InputEventMouseMotion:
_handle_mouse_motion_input(event)
键盘输入
处理键盘输入时,我们需要检查按键是否被按下或释放,并根据不同的按键执行相应的操作。
检测按键
func _handle_keyboard_input(event: InputEventKey):
if event.pressed:
match event.scancode:
KEY_UP:
print("上箭头键被按下")
KEY_DOWN:
print("下箭头键被按下")
KEY_LEFT:
print("左箭头键被按下")
KEY_RIGHT:
print("右箭头键被按下")
KEY_SPACE:
print("空格键被按下")
else:
match event.scancode:
KEY_UP:
print("上箭头键被释放")
KEY_DOWN:
print("下箭头键被释放")
KEY_LEFT:
print("左箭头键被释放")
KEY_RIGHT:
print("右箭头键被释放")
KEY_SPACE:
print("空格键被释放")
使用 is_action_pressed
和 is_action_just_pressed
Godot引擎提供了一个更高级的方式来处理输入,即使用动作。通过在项目设置中定义动作,我们可以更灵活地处理输入。
-
打开项目设置,进入
Input Map
选项卡。 -
添加新的动作,例如
ui_up
、ui_down
、ui_left
、ui_right
和ui_space
。 -
为每个动作分配相应的按键。
func _process(delta):
if Input.is_action_pressed("ui_up"):
print("上箭头键或分配的键被按下")
if Input.is_action_just_pressed("ui_space"):
print("空格键或分配的键被按下")
鼠标输入
处理鼠标输入时,我们需要捕捉鼠标移动、鼠标按钮点击等事件。
检测鼠标移动
func _handle_mouse_motion_input(event: InputEventMouseMotion):
print("鼠标移动: ", event.relative)
检测鼠标按钮点击
func _handle_mouse_button_input(event: InputEventMouseButton):
if event.pressed:
match event.button_index:
BUTTON_LEFT:
print("左键被按下")
BUTTON_RIGHT:
print("右键被按下")
BUTTON_MIDDLE:
print("中键被按下")
else:
match event.button_index:
BUTTON_LEFT:
print("左键被释放")
BUTTON_RIGHT:
print("右键被释放")
BUTTON_MIDDLE:
print("中键被释放")
事件处理
在Godot引擎中,我们可以使用信号来处理UI元素的输入事件。信号是一种异步通信机制,当某个特定事件发生时,信号会被触发,从而调用相应的函数。
按钮点击事件
在Godot引擎中,按钮点击事件可以通过连接按钮的 pressed
信号来处理。
-
创建一个按钮节点。
-
在脚本中连接按钮的
pressed
信号。
extends Control
# 按钮点击事件处理函数
func _on_button_pressed():
print("按钮被点击")
# 在 _ready 函数中连接信号
func _ready():
$Button.connect("pressed", self, "_on_button_pressed")
其他UI元素的输入事件
除了按钮,其他UI元素(如 Label
、TextureRect
等)也可以处理输入事件。这些元素通常没有内置的信号,但我们可以通过 _input
函数来捕获事件。
检测鼠标悬停
extends Control
func _input(event):
if event is InputEventMouseMotion:
if $TextureRect.rect_has_point(event.position):
print("鼠标悬停在 TextureRect 上")
检测鼠标点击
extends Control
func _input(event):
if event is InputEventMouseButton:
if event.pressed and $TextureRect.rect_has_point(event.position):
print("TextureRect 被点击")
高级输入映射
Godot引擎的输入映射功能允许我们定义多个输入设备的按键或触控手势来触发同一个动作。这对于多平台开发非常有用,可以确保游戏在不同设备上的输入体验一致。
定义输入动作
-
打开项目设置,进入
Input Map
选项卡。 -
添加新的动作,例如
jump
、move_left
、move_right
、move_up
和move_down
。 -
为每个动作分配相应的按键和手势。
使用输入动作
extends Node2D
func _process(delta):
# 检测跳跃动作
if Input.is_action_just_pressed("jump"):
print("跳跃动作被触发")
# 检测移动动作
var move_dir = Vector2()
if Input.is_action_pressed("move_left"):
move_dir.x -= 1
if Input.is_action_pressed("move_right"):
move_dir.x += 1
if Input.is_action_pressed("move_up"):
move_dir.y -= 1
if Input.is_action_pressed("move_down"):
move_dir.y += 1
# 应用移动方向
position += move_dir * delta * 100
输入映射的多平台支持
输入映射不仅支持键盘和鼠标,还支持游戏手柄和触摸屏。例如,我们可以为 jump
动作分配手柄的 A 键和触摸屏的点击事件。
-
在
Input Map
中为jump
动作分配手柄的 A 键。 -
为
jump
动作分配触摸屏的点击事件。
func _process(delta):
if Input.is_action_just_pressed("jump"):
print("跳跃动作被触发")
输入过滤
在某些情况下,我们可能希望在特定条件下忽略某些输入事件。Godot引擎提供了一些方法来实现输入过滤。
使用 accept_event
在 _input
函数中,我们可以使用 accept_event
方法来忽略当前事件,防止它被传递到其他节点。
extends Node2D
func _input(event):
if event is InputEventKey and event.scancode == KEY_SPACE:
print("空格键被按下")
event.accept() # 忽略当前事件
使用 set_process_input
我们可以通过 set_process_input
方法来控制节点是否处理输入事件。这在需要暂停输入处理时非常有用。
extends Node2D
var input_enabled = true
func _ready():
set_process_input(input_enabled)
func toggle_input():
input_enabled = not input_enabled
set_process_input(input_enabled)
func _input(event):
if event is InputEventKey and event.scancode == KEY_SPACE:
print("空格键被按下")
输入缓冲
在动作游戏中,玩家的输入往往需要立即响应。为了确保输入的即时性,我们可以使用输入缓冲来存储一段时间内的输入事件。
使用 InputEventAction
InputEventAction
是一种特殊的输入事件,表示某个输入动作被触发。我们可以使用它来实现输入缓冲。
extends Node2D
var input_buffer = []
func _input(event):
if event is InputEventKey and event.pressed:
input_buffer.append(event.scancode)
elif event is InputEventAction and event.pressed:
input_buffer.append(event.action)
func _process(delta):
if Input.is_action_just_pressed("ui_space"):
input_buffer.append("jump")
# 处理输入缓冲
for input in input_buffer:
match input:
KEY_SPACE:
print("空格键被按下")
"jump":
print("跳跃动作被触发")
# 清空输入缓冲
input_buffer.clear()
鼠标锁定和解锁
在某些游戏中,特别是第一人称射击游戏(FPS)中,我们可能需要锁定鼠标以防止玩家在游戏过程中移动鼠标到屏幕边缘。Godot引擎提供了 Input.mouse_mode
属性来实现鼠标锁定和解锁。
锁定鼠标
func lock_mouse():
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
print("鼠标已锁定")
解锁鼠标
func unlock_mouse():
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
print("鼠标已解锁")
示例:鼠标锁定和解锁
extends Node2D
var mouse_locked = false
func _input(event):
if event is InputEventKey and event.scancode == KEY_SPACE and event.pressed:
if mouse_locked:
unlock_mouse()
else:
lock_mouse()
mouse_locked = not mouse_locked
func lock_mouse():
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
print("鼠标已锁定")
func unlock_mouse():
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
print("鼠标已解锁")
拖放操作
拖放操作是UI交互中常见的功能,特别是在动作游戏中,玩家可能需要拖动物品或角色。Godot引擎提供了 InputEventMouseMotion
和 InputEventMouseButton
来实现拖放操作。
示例:实现拖放操作
-
创建一个
Sprite
节点。 -
在脚本中实现拖放逻辑。
extends Sprite
var dragging = false
func _input(event):
if event is InputEventMouseButton:
if event.button_index == BUTTON_LEFT and event.pressed:
if get_global_mouse_position().distance_to(global_position) < 10:
dragging = true
print("开始拖动 Sprite")
elif event.button_index == BUTTON_LEFT and not event.pressed and dragging:
dragging = false
print("停止拖动 Sprite")
elif event is InputEventMouseMotion and dragging:
global_position = get_global_mouse_position() - (get_size() / 2)
print("拖动 Sprite 到新位置")
触摸屏输入
对于支持触摸屏的设备,Godot引擎提供了特定的输入事件来处理触摸屏输入。这些事件包括 InputEventScreenTouch
和 InputEventScreenDrag
。
检测触摸屏点击
func _input(event):
if event is InputEventScreenTouch:
if event.pressed:
print("触摸屏被点击: ", event.position)
else:
print("触摸屏被释放: ", event.position)
检测触摸屏拖动
func _input(event):
if event is InputEventScreenDrag:
print("触摸屏拖动: ", event.relative)
示例:触摸屏拖动角色
-
创建一个
KinematicBody2D
节点,添加Sprite
和CollisionShape2D
子节点。 -
在脚本中实现触摸屏拖动逻辑。
extends KinematicBody2D
var dragging = false
var drag_start = Vector2()
func _input(event):
if event is InputEventScreenTouch:
if event.pressed:
if get_global_mouse_position().distance_to(global_position) < 10:
dragging = true
drag_start = event.position
print("开始拖动角色")
else:
dragging = false
print("停止拖动角色")
elif event is InputEventScreenDrag and dragging:
var drag_dir = event.position - drag_start
move_and_slide(drag_dir)
print("拖动角色: ", drag_dir)
自定义输入处理
在某些情况下,我们可能需要自定义输入处理逻辑。Godot引擎提供了 InputEvent
类的子类,我们可以根据需要创建自定义的输入事件类型。
示例:自定义输入事件
-
创建一个自定义的输入事件类型。
-
在脚本中处理自定义输入事件。
extends InputEvent
# 自定义输入事件类型
class_name CustomInputEvent
var custom_data: Vector2
func _init(custom_data: Vector2):
self.custom_data = custom_data
extends Node2D
func _input(event):
if event is InputEventMouseButton and event.pressed:
var custom_event = CustomInputEvent(event.position)
Input.parse_input_event(custom_event)
func _unhandled_input(event):
if event is CustomInputEvent:
print("自定义输入事件: ", event.custom_data)
输入调试
在开发过程中,调试输入事件是非常重要的。Godot引擎提供了一些工具和方法来帮助我们调试输入。
使用 InputEvent
的 print
方法
func _input(event):
print(event)
使用 InputDebug
模块
Godot引擎没有内置的 InputDebug
模块,但我们可以自己创建一个用于调试输入的模块。
extends Node
func _input(event):
print("输入事件: ", event)
if event is InputEventKey:
print("按键: ", event.scancode, " 按下: ", event.pressed)
elif event is InputEventMouse:
print("鼠标移动: ", event.relative)
elif event is InputEventMouseButton:
print("鼠标按钮: ", event.button_index, " 按下: ", event.pressed)
elif event is InputEventMouseMotion:
print("鼠标悬停: ", event.position)
elif event is InputEventScreenTouch:
print("触摸屏点击: ", event.position, " 按下: ", event.pressed)
elif event is InputEventScreenDrag:
print("触摸屏拖动: ", event.relative)
输入反馈
为了提高用户体验,我们可以在游戏UI中提供输入反馈。这可以通过改变UI元素的外观、播放音效或显示提示信息来实现。
示例:按钮点击反馈
-
创建一个按钮节点。
-
在脚本中实现点击反馈。
extends Button
func _ready():
connect("pressed", self, "_on_button_pressed")
func _on_button_pressed():
modulate = Color(1, 0.5, 0.5) # 改变按钮颜色
await get_tree().create_timer(0.1).timeout
modulate = Color(1, 1, 1) # 恢复按钮颜色
print("按钮被点击")
示例:鼠标悬停反馈
-
创建一个
TextureRect
节点。 -
在脚本中实现悬停反馈。
extends Control
func _input(event):
if event is InputEventMouseMotion:
if $TextureRect.rect_has_point(event.position):
$TextureRect.modulate = Color(0.5, 1, 0.5) # 改变 TextureRect 颜色
else:
$TextureRect.modulate = Color(1, 1, 1) # 恢复 TextureRect 颜色
输入组合
在动作游戏中,玩家可能需要同时按下多个键来执行特定的操作。Godot引擎提供了多种方法来处理输入组合。
使用 InputEventKey
组合
extends Node
var shift_pressed = false
func _input(event):
if event is InputEventKey:
if event.scancode == KEY_SHIFT and event.pressed:
shift_pressed = true
elif event.scancode == KEY_SHIFT and not event.pressed:
shift_pressed = false
elif event.scancode == KEY_UP and event.pressed:
if shift_pressed:
print("Shift + 上箭头键被按下")
else:
print("上箭头键被按下")
使用 InputEventAction
组合
extends Node
var shift_pressed = false
func _input(event):
if event is InputEventKey and event.scancode == KEY_SHIFT and event.pressed:
shift_pressed = true
elif event is InputEventKey and event.scancode == KEY_SHIFT and not event.pressed:
shift_pressed = false
elif event is InputEventAction and event.action == "ui_up" and event.pressed:
if shift_pressed:
print("Shift + 上箭头键被按下")
else:
print("上箭头键被按下")
示例:组合按键跳跃
-
在项目设置中定义
jump
和shift
动作。 -
在脚本中实现组合按键跳跃。
extends Node2D
var shift_pressed = false
func _input(event):
if event is InputEventKey and event.scancode == KEY_SHIFT and event.pressed:
shift_pressed = true
elif event is InputEventKey and event.scancode == KEY_SHIFT and not event.pressed:
shift_pressed = false
elif event is InputEventAction and event.action == "jump" and event.pressed:
if shift_pressed:
print("Shift + 跳跃键被按下")
jump_with_shift()
else:
print("跳跃键被按下")
jump()
func jump():
print("普通跳跃")
func jump_with_shift():
print("带 Shift 的跳跃")
输入重映射
在某些情况下,我们可能需要根据玩家的偏好或设备特性重映射输入。Godot引擎提供了 InputMap
类来实现输入重映射。这在多平台开发和玩家自定义控制方案时非常有用。
示例:输入重映射
-
创建一个新的输入动作。
-
为新动作分配按键。
-
在脚本中实现输入重映射。
extends Node
func _ready():
# 为新动作分配按键
InputMap.add_action("custom_jump")
InputMap.action_add_event("custom_jump", InputEventKey.new().scancode = KEY_SPACE)
InputMap.action_add_event("custom_jump", InputEventKey.new().scancode = KEY_W)
func _process(delta):
if Input.is_action_just_pressed("custom_jump"):
print("自定义跳跃动作被触发")
func _input(event):
if event is InputEventKey and event.scancode == KEY_R and event.pressed:
# 重映射跳跃动作
InputMap.action_erase_event("custom_jump", InputEventKey.new().scancode = KEY_SPACE)
InputMap.action_add_event("custom_jump", InputEventKey.new().scancode = KEY_E)
print("跳跃动作已重映射到 E 键")
动态重映射
我们还可以在运行时动态地重映射输入,以适应不同的游戏状态或玩家设置。
extends Node
func _ready():
# 为新动作分配按键
InputMap.add_action("custom_jump")
InputMap.action_add_event("custom_jump", InputEventKey.new().scancode = KEY_SPACE)
func _process(delta):
if Input.is_action_just_pressed("custom_jump"):
print("自定义跳跃动作被触发")
func _input(event):
if event is InputEventKey and event.scancode == KEY_R and event.pressed:
# 重映射跳跃动作
InputMap.action_erase_event("custom_jump", InputEventKey.new().scancode = KEY_SPACE)
InputMap.action_add_event("custom_jump", InputEventKey.new().scancode = KEY_E)
print("跳跃动作已重映射到 E 键")
elif event is InputEventKey and event.scancode == KEY_T and event.pressed:
# 重映射跳跃动作
InputMap.action_erase_event("custom_jump", InputEventKey.new().scancode = KEY_E)
InputMap.action_add_event("custom_jump", InputEventKey.new().scancode = KEY_SPACE)
print("跳跃动作已重映射回 Space 键")
多玩家输入
在多人游戏中,处理多个玩家的输入是常见的需求。Godot引擎提供了 InputEventJoypad
和 InputEventKey
类来处理多玩家输入。我们可以通过检查输入设备的ID来区分不同的玩家。
示例:多玩家跳跃
-
在项目设置中定义
jump
动作,并为每个玩家分配不同的按键或手柄按钮。 -
在脚本中实现多玩家输入处理。
extends Node
func _process(delta):
for i in range(4): # 假设有4个玩家
if Input.is_action_just_pressed("jump", i):
print("玩家 ", i + 1, " 跳跃动作被触发")
func _input(event):
if event is InputEventKey and event.scancode == KEY_R and event.pressed:
# 重映射玩家1的跳跃动作
InputMap.action_erase_event("jump", InputEventKey.new().scancode = KEY_SPACE, device = 0)
InputMap.action_add_event("jump", InputEventKey.new().scancode = KEY_E, device = 0)
print("玩家1的跳跃动作已重映射到 E 键")
elif event is InputEventKey and event.scancode == KEY_T and event.pressed:
# 重映射玩家1的跳跃动作
InputMap.action_erase_event("jump", InputEventKey.new().scancode = KEY_E, device = 0)
InputMap.action_add_event("jump", InputEventKey.new().scancode = KEY_SPACE, device = 0)
print("玩家1的跳跃动作已重映射回 Space 键")
使用手柄输入
对于手柄输入,我们可以通过 InputEventJoypad
类来处理。
extends Node
func _process(delta):
for i in range(4): # 假设有4个玩家
if Input.is_action_just_pressed("jump", i):
print("玩家 ", i + 1, " 跳跃动作被触发")
func _input(event):
if event is InputEventJoypadButton and event.button_index == BUTTON_A:
print("手柄 A 键被按下,设备ID: ", event.device)
输入延迟
在某些情况下,我们可能需要延迟处理输入事件,以实现更复杂的游戏逻辑。Godot引擎提供了多种方法来实现输入延迟,例如使用计时器或缓冲区。
使用计时器
extends Node
var jump_timer = Timer.new()
func _ready():
add_child(jump_timer)
jump_timer.connect("timeout", self, "_on_jump_timeout")
jump_timer.wait_time = 0.5 # 延迟时间
func _input(event):
if event is InputEventKey and event.scancode == KEY_SPACE and event.pressed:
jump_timer.start()
print("跳跃动作延迟触发")
func _on_jump_timeout():
print("跳跃动作被触发")
jump()
func jump():
print("执行跳跃操作")
使用输入缓冲区
extends Node
var input_buffer = []
func _input(event):
if event is InputEventKey and event.scancode == KEY_SPACE and event.pressed:
input_buffer.append(event.scancode)
print("跳跃动作被添加到缓冲区")
func _process(delta):
for input in input_buffer:
if input == KEY_SPACE:
print("跳跃动作从缓冲区中被触发")
jump()
# 清空输入缓冲
input_buffer.clear()
func jump():
print("执行跳跃操作")
总结
通过上述内容,我们详细介绍了如何在Godot引擎中处理鼠标和键盘输入,包括基本的输入检测、事件处理、高级的输入映射、输入过滤、输入缓冲、鼠标锁定和解锁、拖放操作、触摸屏输入、自定义输入处理、输入反馈、输入组合和多玩家输入。这些技术不仅适用于UI交互,也适用于各种游戏开发场景。希望本节内容能帮助你更好地理解和应用Godot引擎的输入处理功能。
在接下来的章节中,我们将探讨如何在Godot引擎中实现更高级的用户交互功能,例如物理引擎的使用、动画和粒子系统等。敬请期待!