135 lines
3.5 KiB
GDScript3
135 lines
3.5 KiB
GDScript3
|
# ReenterLock.gd
|
||
|
extends Node
|
||
|
class_name PlayerReenterLock
|
||
|
|
||
|
#### 目前无需全局,仅需跟随 ground
|
||
|
#### 因此无需在 exit 时重置锁,也无需推迟计数
|
||
|
#### 因为 PlayerReenterLock 生命周期与 ground 一致
|
||
|
|
||
|
####### PlayerReenterLock 系统提供了以下特性 #############
|
||
|
# 可重入性:每个事件可以多次锁定/解锁,通过计数器管理
|
||
|
# 全局状态追踪:使用静态变量追踪整体锁定状态 [无需启用]
|
||
|
# 生命周期管理:自动处理节点进入/退出场景树的情况 [无需启用]
|
||
|
# 错误保护:防止过度释放,并在出现问题时发出警告
|
||
|
# 调试支持:可选的调试模式输出详细信息
|
||
|
# 便捷方法:提供同时锁定/解锁两种状态的方法
|
||
|
#################################################
|
||
|
|
||
|
signal freeze_changed(count: int, is_add: bool)
|
||
|
signal hold_changed(count: int, is_add: bool)
|
||
|
|
||
|
# 实例级别的锁定请求追踪
|
||
|
var _freeze_requests: int = 0
|
||
|
var _hold_requests: int = 0
|
||
|
|
||
|
# 调试模式
|
||
|
var debug_mode := GlobalConfig.DEBUG
|
||
|
|
||
|
|
||
|
func _exit_tree() -> void:
|
||
|
if _freeze_requests > 0:
|
||
|
if debug_mode:
|
||
|
push_warning(
|
||
|
"[ReenterLock] Remains %d freeze requests on exit_tree. parent=" % _freeze_requests,
|
||
|
get_parent()
|
||
|
)
|
||
|
if _hold_requests > 0:
|
||
|
if debug_mode:
|
||
|
print(
|
||
|
"[ReenterLock] Remains %d hold requests on exit_tree. parent=" % _hold_requests,
|
||
|
get_parent()
|
||
|
)
|
||
|
|
||
|
|
||
|
func _create_timer(duration: float, callable: Callable):
|
||
|
if duration > 0 and callable:
|
||
|
get_tree().create_timer(duration).timeout.connect(callable)
|
||
|
|
||
|
|
||
|
# Freeze 相关方法
|
||
|
func freeze(duration := 0.0) -> void:
|
||
|
if duration > 0:
|
||
|
_create_timer(duration, release)
|
||
|
_freeze_requests += 1
|
||
|
if debug_mode:
|
||
|
print("[ReenterLock] Freeze applied: ", _freeze_requests)
|
||
|
freeze_changed.emit(_freeze_requests, true)
|
||
|
|
||
|
|
||
|
func release() -> void:
|
||
|
if _freeze_requests <= 0:
|
||
|
push_warning(
|
||
|
(
|
||
|
"[ReenterLock] Attempting to release more times than frozen! Current local count: %d"
|
||
|
% _freeze_requests
|
||
|
)
|
||
|
)
|
||
|
return
|
||
|
_freeze_requests -= 1
|
||
|
if debug_mode:
|
||
|
print("[ReenterLock] Release applied: ", _freeze_requests)
|
||
|
freeze_changed.emit(_freeze_requests, false)
|
||
|
|
||
|
|
||
|
# Hold 相关方法
|
||
|
func hold(duration := 0.0) -> void:
|
||
|
if duration > 0:
|
||
|
_create_timer(duration, unhold)
|
||
|
_hold_requests += 1
|
||
|
if debug_mode:
|
||
|
print("[ReenterLock] Hold applied: ", _hold_requests)
|
||
|
hold_changed.emit(_hold_requests, true)
|
||
|
|
||
|
|
||
|
func unhold() -> void:
|
||
|
if _hold_requests <= 0:
|
||
|
push_warning(
|
||
|
(
|
||
|
"[ReenterLock] Attempting to unhold more times than held! Current local count: %d"
|
||
|
% _hold_requests
|
||
|
)
|
||
|
)
|
||
|
return
|
||
|
_hold_requests -= 1
|
||
|
if debug_mode:
|
||
|
print("[ReenterLock] Unhold applied: ", _hold_requests)
|
||
|
hold_changed.emit(_hold_requests, false)
|
||
|
|
||
|
|
||
|
# 静态方法:查询当前状态
|
||
|
func is_frozen() -> bool:
|
||
|
return _freeze_requests > 0
|
||
|
|
||
|
|
||
|
func is_held() -> bool:
|
||
|
return _hold_requests > 0
|
||
|
|
||
|
|
||
|
func get_freeze_count() -> int:
|
||
|
return _freeze_requests
|
||
|
|
||
|
|
||
|
func get_hold_count() -> int:
|
||
|
return _hold_requests
|
||
|
|
||
|
|
||
|
# 便捷方法:同时锁定移动和输入
|
||
|
func lock_all(duration := 0.0) -> void:
|
||
|
if duration > 0:
|
||
|
_create_timer(duration, unlock_all)
|
||
|
_hold_requests += 1
|
||
|
_freeze_requests += 1
|
||
|
if debug_mode:
|
||
|
prints("[ReenterLock] LockAll applied (hold, freeze): ", _hold_requests, _freeze_requests)
|
||
|
hold_changed.emit(_hold_requests, true)
|
||
|
freeze_changed.emit(_freeze_requests, true)
|
||
|
|
||
|
|
||
|
func unlock_all() -> void:
|
||
|
release()
|
||
|
unhold()
|
||
|
|
||
|
|
||
|
func _to_string() -> String:
|
||
|
return "[ReenterLock] Freeze: %d, Hold: %d" % [_freeze_requests, _hold_requests]
|