@tool class_name EventBinder extends Node @export_tool_button("auto memo") var auto_memo = _auto_memo @export_multiline var memo := "" @export_group("Updater", "updater") @export var updater_event := &"": set(val): if updater_event != val: updater_event = val if is_node_ready() and Engine.is_editor_hint(): _auto_memo() @export_enum("enabler", "shower") var updater_mode := "enabler": set(val): if updater_mode != val: updater_mode = val if is_node_ready() and Engine.is_editor_hint(): _auto_memo() # 仅对 canvas item 生效; <=0 时无 ease @export var updater_ease_duration := 1.0: set(val): if updater_ease_duration != val: updater_ease_duration = val if is_node_ready() and Engine.is_editor_hint(): _auto_memo() @export_enum("include", "exclude") var updater_stage_mode := "include": set(val): if updater_stage_mode != val: updater_stage_mode = val if is_node_ready() and Engine.is_editor_hint(): _auto_memo() @export var updater_stages: Array[int] = [1]: set(val): if updater_stages != val: updater_stages = val if is_node_ready() and Engine.is_editor_hint(): _auto_memo() @export_group("Trigger", "trigger") @export var trigger_event := &"": set(val): if trigger_event != val: trigger_event = val if is_node_ready() and Engine.is_editor_hint(): _auto_memo() @export_tool_button("AutoDetectMode") var trigger_auto_detect_mode := _auto_detect_mode @export_enum("none", "interacted", "triggered", "played") var trigger_mode := "none": set(val): if trigger_mode != val: trigger_mode = val if is_node_ready() and Engine.is_editor_hint(): _auto_memo() @export_range(0, 10000, 1) var trigger_stage := 1: set(val): if trigger_stage != val: trigger_stage = val if is_node_ready() and Engine.is_editor_hint(): _auto_memo() @export var trigger_set_stage_if_greater := true: set(val): if trigger_set_stage_if_greater != val: trigger_set_stage_if_greater = val if is_node_ready() and Engine.is_editor_hint(): _auto_memo() var _local_enable_event_stage := 0 func _ready() -> void: if Engine.is_editor_hint(): _auto_memo() return var parent = get_parent() if not updater_event.is_empty(): if not parent: printerr("[EventBinder] bind_enable is true but parent is null. path: %s" % get_path()) return _local_enable_event_stage = EventManager.get_stage(updater_event) _update_binding_state(_local_enable_event_stage) EventManager.stage_updated.connect(_on_global_stage_updated) if not trigger_event.is_empty(): # connect trigger_mode signal if trigger_mode == "interacted": parent.interacted.connect(_on_happened) elif trigger_mode == "triggered": parent.triggered.connect(_on_happened) elif trigger_mode == "played": parent.played.connect(_on_happened) func _on_happened() -> void: if trigger_set_stage_if_greater: var updated = EventManager.set_stage_if_greater(trigger_event, trigger_stage) if not updated: print( ( "[EventBinder] _on_happened not updated, event: %s, stage: %s" % [trigger_event, EventManager.get_stage(trigger_event)] ) ) else: EventManager.set_stage(trigger_event, trigger_stage) func _on_global_stage_updated(e: StringName, s: int): if e == updater_event: _local_enable_event_stage = s _update_binding_state(s) func _update_binding_state(stage: int): var parent = get_parent() if not parent: printerr("[EventBinder] _update_updater_visibility parent is null. path: %s" % get_path()) return # check stage in updater_stages var updater_status = false if updater_stage_mode == "exclude": updater_status = not stage in updater_stages elif updater_stage_mode == "include": updater_status = stage in updater_stages # check updater_mode if updater_mode == "enabler": parent.enabled = updater_status elif updater_mode == "shower": _toggle_parent_visibility_with_ease(parent, updater_status) func _toggle_parent_visibility_with_ease(parent, show: bool): if parent is CanvasItem: parent.visible = true parent.modulate.a = 0.0 if show else 1.0 var target_a = 1.0 if show else 0.0 var tween = create_tween() tween.tween_property(parent, "modulate:a", target_a, updater_ease_duration) if not show: tween.tween_callback(parent.hide) func _auto_detect_mode(): # TODO 统一interacted played picked var parent = get_parent() if not parent: printerr("[EventBinder] _auto_detect_mode parent is null. path: %s" % get_path()) if parent.has_signal("interacted"): trigger_mode = "interacted" elif parent.has_signal("triggered"): trigger_mode = "triggered" elif parent.has_signal("played"): trigger_mode = "played" else: printerr("[EventBinder] _auto_detect_mode cannot detect trigger mode. path:", get_path()) #### TOOL BUTTON func _auto_memo() -> void: # updater release_stage[(!)=0|1] 时[显示|启用][parent.name.replace("Closeup", "")] # trigger [parent] [picked|played...] 时 release_stage=1(greater|any) var parent_name = get_parent().name.to_lower() # replace english letters var matcher = RegEx.create_from_string("^[a-z]*(.*)$") var parent_name_match = matcher.search(parent_name).get_string(1) if parent_name_match != "": parent_name = parent_name_match var memo_str = "" if updater_event != "": memo_str = updater_event memo_str += "=" if updater_stage_mode == "include" else "!=" memo_str += "|".join(updater_stages) + " 时" memo_str += "显示" if updater_mode == "shower" else "启用" memo_str += " [" + parent_name + "]\n" if trigger_event != "" and trigger_mode != "none": memo_str += "[" + parent_name + "] " + trigger_mode + "时" memo_str += trigger_event + "=" + str(trigger_stage) memo_str += "(greater)" if trigger_set_stage_if_greater else "(any)" var existing_lines = memo.split("\n") # 保留 # 开头的 line var kept_lines = [] for line in existing_lines: if line.begins_with("#"): kept_lines.append(line) memo = "\n".join(kept_lines) memo += "\n" if kept_lines else "" memo += memo_str