#'''全局的相机管理器 # #======= 外部调用函数 ======= # #''' #@tool 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 #var _screen_size : Vector2i # ### 玩家关卡内静态相机 #const CAMERA_FOLLOWER:= preload("res://camera/camera_follower.tscn") # #func _ready() -> void: ## Setting default screensize #_screen_size = Vector2i( #ProjectSettings.get_setting("display/window/size/viewport_width"), #ProjectSettings.get_setting("display/window/size/viewport_height") #) # ## For editor #if Engine.is_editor_hint(): #ProjectSettings.settings_changed.connect(func(): #_screen_size = Vector2i( #ProjectSettings.get_setting("display/window/size/viewport_width"), #ProjectSettings.get_setting("display/window/size/viewport_height") #) #) ## For runtime #else: #get_tree().get_root().size_changed.connect(func(): #_screen_size = get_viewport().get_visible_rect().size #) # #func _editor_ready() -> void: #ProjectSettings.settings_changed.connect(func(): #_screen_size = Vector2i( #ProjectSettings.get_setting("display/window/size/viewport_width"), #ProjectSettings.get_setting("display/window/size/viewport_height") #) #) # #func _runtime_ready() -> void: #get_tree().get_root().size_changed.connect(func(): #_screen_size = get_viewport().get_visible_rect().size #) # ##func _process(delta): ##if not Engine.is_editor_hint(): ##_runtime_process(delta) # # #func _runtime_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 _on_player_spawned(new_player: Player) -> void: #if _current_anchor and _current_anchor.follow_player: #_bind_camera_follow_to_player(new_player) # #func _on_player_dead() -> void: #return # ### 绑定camera 到 player #func _bind_camera_follow_to_player(player: Player) -> void: #if _player_remote and is_instance_valid(_player_remote): #_player_remote.queue_free() #_player_remote = null # #if not is_instance_valid(player): #return # #var rt := RemoteTransform2D.new() #rt.name = "__CameraAnchorFollow" #rt.remote_path = camera_2d.get_path() #rt.update_position = true #rt.update_rotation = false #rt.update_scale = false # #player.add_child(rt) #_player_remote = rt # ### 外部获取玩家全局相机 #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 # # # ###应用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: #if not anchor.follow_player: #return # #var player := GlobalEvent.get_player() #if player: #_bind_camera_follow_to_player(player) # ## ========================== ## External API ## ========================== ### 重置所有的Camera的_priority #func reset_all_camera_priority() -> void: #for a in _cached_anchors: #a._priority = 0 # ### 返回屏幕比例 #func get_screen_size() -> Vector2i: #return _screen_size