【Godot】组合键的实现

本文介绍如何在Godot 3.4中实现复杂的组合键输入。通过自定义脚本,能够灵活配置各种按键组合,并在特定组合被按下时触发相应事件。文中详细解释了组合键的判定逻辑与实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Godot 3.4

组合键,连招时对按键的判定,实现代码。底部有使用的示例文件

关键代码:

#==================================================
#	Componse Input - 组合输入
#==================================================
# * 延迟判断按键是否被按下,防止操作过于快速导致组合键失效
# * 例,按下:小键盘方向键左+空格,则触发操作:
#	add_mapper(
#		"刺" 
#		, ["ui_accept", "ui_left", "ui_right"]	# 包含的组合键
#		, ["ui_accept"]		# 在按下的一刻才被检测到的键
#		, ["ui_left", "ui_right"]	# 其中的一个键被检测到则这个数组内的按钮都算作被检测到
#	)
#==================================================
# @datetime: 2021-12-21 22:50:05
#==================================================

extends Node


# 每个按键组合会在其中一个按键被触发时进行计时器倒计时
# 进行组合件判定,如果到达时间,则会进行释放掉所有已按
# 下的记录,会在此进行发出释放掉的按键,以便可以连接这
# 个信号去执行其他可能的操作 
## @keys  释放掉的key
## @release_all  是否全部释放掉了
## @map_name  释放掉的是哪个组合键
signal released(keys, release_all, map_name)


## 按键映射
var input_mapper : Dictionary = {}



#==================================================
#   自定义方法
#==================================================
#(override)
func _physics_process(delta):
	for m in input_mapper.values():
		m.physics_process()


##  添加 key 映射
## @key  判断的 key
## @input_maps  触发的键盘映射
## @just  仅仅在按下那一刻才检测到
## @or_input  其中的一个按下即为各个都按下
func add_mapper(
	key: String, 
	input_maps: PoolStringArray, 
	just: PoolStringArray = [],
	or_input: PoolStringArray = []
):
	input_mapper[key] = ComponseKey.new(
		self, key, input_maps, just, or_input
	)


##  获取已按下的键
## @key  
func get_inputed_key(key: String) -> Array:
	return input_mapper[key].get_inputed()


##  清除按键记录 
## @key  
func clear(key: String):
	input_mapper[key].clear()


##  清空所有按键记录
func clear_all():
	for key in input_mapper:
		input_mapper[key].clear()


##  回调方法
##(每个组合键会在释放掉记录的按键时,调用这个方法)
## @data  
func callback(data):
	emit_signal("released", 
		data.released_keys, 
		data.released_all, 
		data.map_name
	)



#==================================================
#   组合键
#==================================================
class ComponseKey:
	
	# 在这个时间内按下的组合键则进行释放,可自行调整修改这个时间
	# 不过如果值太小,会判定困难,因为用户可能两个键按键间隔没有那么快
	const DURATION = 0.1
	
	var _host : Node
	var _map_name : String = ""
	var _release_timer := Timer.new()
	var _delta = 1.0 / ProjectSettings.get("physics/common/physics_fps")
	# 仅仅在按下的时候才被检测
	var _just := {}
	# 或输入(其中一个按下了,则全部都算作按下了)
	var _or_input := {}
	
	# 已按下的按键
	var _inputted := {}
	# 已按下按键的数量
	var _inputted_count : int = 0
	
	
	func _init(
		host: Node 	# 这个对象的宿主,用于添加计时器到这个节点上
		, map_name : String
		, input_maps: PoolStringArray 	# 判定的按键 
		, just: PoolStringArray = []	# 是否只是在按下那一刻才测到
		, or_input: PoolStringArray = []	# 其中一个按下,即为都按下
	) -> void:
		_host = host
		_map_name = map_name
		# 添加重置计时器
		_release_timer.wait_time = DURATION
		_release_timer.one_shot = true
		_release_timer.autostart = false
		if _release_timer.connect("timeout", self, "release") != OK:
			printerr(self, "连接信号时出现错误")
		_host.add_child(_release_timer)
		# 初始化数据
		for key in input_maps:
			self._inputted[key] = false
		for key in just:
			self._just[key] = key
		for key in or_input:
			self._or_input[key] = key
	
	
	## 检测
	func physics_process() -> void:
		for key in _inputted.keys():
			# 按下时捕获输入
			if _just.has(key):
				if Input.is_action_just_pressed(key):
					set_inputted_key(key)
			# 每帧都捕获输入
			else:
				if  Input.is_action_pressed(key):
					set_inputted_key(key)
	
	
	## 设置已输入的按键
	func set_inputted_key(key: String):
		if key in _or_input:
			for i in _or_input:
				if !_inputted[i]:
					_inputted[i] = true
					_inputted_count += 1
		else:
			if !_inputted[key]:
				_inputted[key] = true
				_inputted_count += 1
		# 开始倒计时
		if _release_timer.is_stopped():
			_release_timer.start()
		# 如果已按下全部按键,则进行释放
		elif is_all_inputted():
			_release_timer.stop()
			release()
	
	
	## 是否全部按下
	func is_all_inputted() -> bool:
		return _inputted_count == _inputted.size()
	
	
	## 释放掉所有按键记录,重置状态
	func release() -> void:
		var list = get_inputed()
		clear()
		# 回调宿主的 callback 方法
		_host.callback({
			released_keys = list, 
			released_all = (list.size() == _inputted.size()), 
			map_name = _map_name,
		})
	
	
	## 获取已按下的键
	func get_inputed() -> Array:
		var list := []
		for key in _inputted.keys():
			if _inputted[key]:
				list.push_back(key)
		return list
	
	
	## 清除内容
	func clear():
		_release_timer.stop()
		_inputted_count = 0
		# 重置按下状态
		for key in _inputted.keys():
			_inputted[key] = false
	
	

示例文件:ComponseInput.rar

运行后,按下小键盘的方向键 + 空格键,查看编辑器底部中的输出内容

### Godot 引擎中按键按下和松开事件处理 在 Godot 引擎中,可以通过 `_input` 函数捕获用户的输入事件,并区分按键的按下和松开状态。以下是详细的实现方法以及相关代码示例。 #### 1. 捕获键盘输入事件 Godot 提供了 `_input` 方法来接收所有的输入事件。这些事件可以是键盘、鼠标或其他设备产生的交互数据。对于键盘输入,主要关注的是 `InputEventKey` 类型的事件。 ```gdscript extends Node func _input(event): if event is InputEventKey: if event.pressed: # 键盘按键被按下的逻辑 match event.scancode: KEY_SPACE: print("空格键按下了") KEY_A: print("A键按下了") else: # 键盘按键被释放的逻辑 match event.scancode: KEY_SPACE: print("空格键松开了") KEY_A: print("A键松开了") ``` 上述代码展示了如何分别处理按键的按下 (`pressed`) 和松开 (非 `pressed`) 状态[^2]。 --- #### 2. 区分不同类型的按键 除了基本的方向键和字母键外,还可以识别特殊功能键(如 Shift、Ctrl、Alt 等),并通过组合键实现复杂的操作逻辑。 ```gdscript if event.is_action_pressed("ui_accept"): print("UI 接受按钮被按下了") if event.is_action_released("ui_cancel"): print("UI 取消按钮被释放了") ``` 这里使用了 `is_action_pressed` 和 `is_action_released` 方法,它们允许绑定抽象的动作名称到具体的按键配置,从而提高项目的灵活性和可维护性[^5]。 --- #### 3. 应用于角色控制逻辑 假设我们需要开发一个简单的游戏角色控制系统,其中 W/S 控制上下移动,A/D 控制左右移动。可以结合按键状态实时更新角色的速度向量。 ```gdscript extends KinematicBody2D var velocity = Vector2.ZERO const SPEED = 200 func _process(delta): move_and_slide(velocity) func _input(event): if event is InputEventKey and event.pressed: match event.scancode: KEY_W: velocity.y -= SPEED KEY_S: velocity.y += SPEED KEY_A: velocity.x -= SPEED KEY_D: velocity.x += SPEED elif event is InputEventKey and not event.pressed: match event.scancode: KEY_W, KEY_S: velocity.y = 0 KEY_A, KEY_D: velocity.x = 0 ``` 在此示例中,当玩家按下某个方向键时,对应轴上的速度会被累加;而当松开该键时,则重置相应轴的速度为零[^2]。 --- #### 4. 高级应用:切换模式与持续触发 某些情况下,可能需要实现类似“开关”的功能,比如切换武器或进入瞄准模式。这可以通过设置布尔标志变量来管理。 ```gdscript var toggle_mode = false func _input(event): if event is InputEventKey: if event.scancode == KEY_E and event.pressed: toggle_mode = !toggle_mode print("Toggle Mode:", toggle_mode) ``` 这段代码演示了一个简单的切换机制,在每次按下 E 键时翻转 `toggle_mode` 的值[^4]。 --- ### 总结 通过合理运用 `_input` 方法及其内部的各种属性,开发者可以在 Godot 游戏项目中高效地捕捉并响应用户输入。无论是基础的角色移动还是高级的功能切换,都可以借助类似的思路去设计和实现
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值