【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】组合键的实现》有1条评论

发表评论