Godot组合键的实现

Posted 张学徒

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Godot组合键的实现相关的知识,希望对你有一定的参考价值。

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在Godot中模仿实现接口功能

godot新手教程2[godot常用代码用法]

delphi 中 实现 ctrl + A~Z 和 Alt + A~Z 组合键的拦截

Hibernate 组合主键的使用

如何在VB中用PostMessage向指定窗口发送带有修饰键的组合键?

Godot实用代码1000例