'''全局的相机管理器 ======= 外部调用函数 ======= ''' extends Node @onready var camera_2d: Camera2D = %Camera2D @onready var camera_shake_player: CameraShakePlayer = %CameraShakePlayer var _cached_anchors: Array[CameraAnchor] = [] var _current_anchor: CameraAnchor var _switch_tween: Tween var _player_remote: RemoteTransform2D var _base_camera_pos := Vector2.ZERO ##标记位,用来检测当前帧是否存在相机切换 var _switch_scheduled := false var _dirty := false ## 玩家关卡内静态相机 const CAMERA_FOLLOWER:= preload("res://_shared/camera/camera_follower.tscn") func _ready() -> void: _base_camera_pos = camera_2d.global_position func _process(delta): if not camera_2d: return var shake_offset := camera_shake_player.update(delta) camera_2d.global_position = _base_camera_pos + shake_offset ## 外部获取玩家全局相机 func get_cached_camera() -> Camera2D: return camera_2d ## 注册一个相机锚点 func register_anchor(anchor: CameraAnchor) -> void: if anchor in _cached_anchors: return _cached_anchors.append(anchor) anchor.on_priority_change.connect(on_anchor_priority_changed) _request_evaluate() ## 当相机锚点的权重改变时,向管理器触发事件 func on_anchor_priority_changed(priority:int, anchor: CameraAnchor) -> void: _request_evaluate() ## 注销一个相机锚点 func unregister_anchor(anchor: CameraAnchor) -> void: _cached_anchors.erase(anchor) if _current_anchor == anchor: _current_anchor = null _request_evaluate() func _request_evaluate() -> void: _dirty = true if _switch_scheduled: return _switch_scheduled = true call_deferred("_commit_camera_anchor") func _commit_camera_anchor() -> void: _switch_scheduled = false if not _dirty: return _dirty = false # 清理无效 _cached_anchors = _cached_anchors.filter(func(a): return is_instance_valid(a)) var winner: CameraAnchor = _pick_best_anchor() if winner == null: return if winner == _current_anchor: return switch_anchor(winner) func _pick_best_anchor() -> CameraAnchor: var best: CameraAnchor = null var best_p := -INF for a in _cached_anchors: if not a.enabled: continue if a._priority > best_p: best_p = a._priority best = a return best ## 排序已有的锚点 func _sort_anchors() -> void: _cached_anchors.sort_custom(func(a, b): return a._priority > b._priority ) ## 尝试自切换 func _try_auto_switch() -> void: for a in _cached_anchors: if a.enabled: switch_anchor(a) _current_anchor = a return ## 重置所有的Camera的_priority func reset_all_camera_priority() -> void: for a in _cached_anchors: a._priority = 0 ##应用Anchor的Limit func _apply_anchor_limits(anchor: CameraAnchor) -> void: if not camera_2d: return camera_2d.limit_left = anchor.global_position.x + anchor.limit_left camera_2d.limit_right = anchor.global_position.x + anchor.limit_right camera_2d.limit_top = anchor.global_position.y + anchor.limit_top camera_2d.limit_bottom = anchor.global_position.y + anchor.limit_bottom func _clear_camera_limits() -> void: if not camera_2d: return camera_2d.limit_left = -10000000 camera_2d.limit_right = 10000000 camera_2d.limit_top = -10000000 camera_2d.limit_bottom = 10000000 ## 切换相机 func switch_anchor(target_anchor: CameraAnchor) -> void: if target_anchor == null: return if target_anchor == _current_anchor: return if not is_instance_valid(camera_2d): return #优先清除已有的remote if _player_remote: _player_remote.queue_free() _player_remote = null # 中断旧 Tween if _switch_tween and _switch_tween.is_running(): _switch_tween.kill() _switch_tween = null var camera := camera_2d var blend_time : float = max(target_anchor.blend_time, 0.001) _clear_camera_limits() _switch_tween = get_tree().create_tween() _switch_tween.set_ignore_time_scale(true) _switch_tween.set_trans(Tween.TRANS_CUBIC) _switch_tween.set_ease(Tween.EASE_OUT) # ===== 位置 ===== _switch_tween.tween_property( self, "_base_camera_pos", target_anchor.global_position, blend_time ) # ===== Zoom ===== _switch_tween.parallel().tween_property( camera, "zoom", target_anchor.zoom, blend_time * 1.5 ) # 完成回调 _switch_tween.finished.connect(func(): _current_anchor = target_anchor _update_anchor_follow_state(target_anchor) _apply_anchor_limits(target_anchor) ) _current_anchor = target_anchor func _update_anchor_follow_state(anchor: CameraAnchor) -> void: # 先清理旧的 RemoteTransform if _player_remote and is_instance_valid(_player_remote): _player_remote.queue_free() _player_remote = null if not anchor.follow_player: return var p := GlobalEvent.get_player() if not p or not is_instance_valid(p): push_warning("CameraAnchor wants to follow player, but player is not registered.") return # 创建 RemoteTransform2D var rt := RemoteTransform2D.new() rt.name = "__CameraAnchorFollow" rt.remote_path = camera_2d.get_path() p.add_child(rt) _player_remote = rt