@tool extends Node class_name CameraPointer const _CONSTANTS := preload("res://addons/reedcamera/_data/CameraSystemConst.gd") ## 相机指针所能持有的工具种类 enum ToolType{ SHAKER, ANCHOR, FOLLOWER } ## 相机工具和脚本的映射 const type_script_map:Dictionary = { ToolType.SHAKER : preload("res://addons/reedcamera/scripts/camera_tools/CameraShakeController.gd"), ToolType.ANCHOR : preload("res://addons/reedcamera/scripts/camera_tools/CameraAnchorController.gd"), ToolType.FOLLOWER : preload("res://addons/reedcamera/scripts/camera_tools/CameraFollowController.gd") } var _camera: Camera2D var _editor_valid := false var _runtime_registered := false var _warned := false var _final_offset := Vector2.ZERO var _final_position: Vector2 var _final_zoom := Vector2.ONE var _pos_dirty := false var _offset_dirty := false var _zoom_dirty := false func _enter_tree() -> void: if Engine.is_editor_hint(): call_deferred("_editor_verify") func _exit_tree() -> void: if Engine.is_editor_hint(): return _request_unregister() func _process(delta: float) -> void: if Engine.is_editor_hint(): return if not _camera: return _reset_dirty_flags() _update_final_position() _update_camera_offset() _update_camera_zoom() _apply_camera_config() func _reset_dirty_flags() -> void: _pos_dirty = false _offset_dirty = false _zoom_dirty = false func _update_final_position(): for child in get_children(): if child is CameraToolBasic \ and child.enabled \ and child.affect_position \ and child.has_base_position(): _final_position = child.get_base_position() _pos_dirty = true return # fallback _final_position = _camera.global_position func _update_camera_offset(): var offset := Vector2.ZERO var used := false for child in get_children(): if child is CameraToolBasic \ and child.enabled \ and child.affect_offset \ and child.has_camera_offset(): offset += child.get_camera_offset() used = true _final_offset = offset _offset_dirty = used func _update_camera_zoom(): for child in get_children(): if child is CameraToolBasic \ and child.enabled \ and child.affect_zoom \ and child.has_camera_zoom(): _final_zoom = child.get_camera_zoom() _zoom_dirty = true return # fallback _final_zoom = _camera.zoom func _apply_camera_config(): if _pos_dirty: _camera.global_position = _final_position if _offset_dirty: _camera.offset = _final_offset if _zoom_dirty: _camera.zoom = _final_zoom func _notification(what: int) -> void: if not Engine.is_editor_hint(): return match what: NOTIFICATION_PARENTED, NOTIFICATION_UNPARENTED: #print("重設parent") call_deferred("_editor_verify") ## 編輯器層面的通過性驗證 func _editor_verify() -> void: _camera = _find_camera() _editor_valid = _camera != null #print(_editor_valid) if not _editor_valid: _emit_config_warning() else: _warned = false func _ready() -> void: if Engine.is_editor_hint(): return if not _camera: _camera = _find_camera() _request_register() func _find_camera() -> Camera2D: var p := get_parent() return p as Camera2D if p is Camera2D else null func _request_register() -> void: var sys := Engine.get_singleton(_CONSTANTS.CAMERA_SYSTEM_NAME) if not sys: return _runtime_registered = sys.request_register_pointer(self) func _request_unregister() -> void: if not _runtime_registered: return var sys := Engine.get_singleton(_CONSTANTS.CAMERA_SYSTEM_NAME) if sys: sys.request_unregister_pointer(self) _runtime_registered = false func _emit_config_warning() -> void: if not Engine.is_editor_hint(): return if _warned: return push_warning( "[CameraPointer] Invalid configuration: parent node must be Camera2D. " + "Current parent: %s" % (get_parent() if get_parent() else "null") ) _warned = true ## ========================= ## Public API ## ========================= ##获取相机 func get_camera() -> Camera2D: if not _camera: _camera = _find_camera() return _camera ##获取特定工具 func get_tool(tool_class: Script) -> Node: for c in get_children(): if c.get_script() == tool_class: return c return null ##通过类型返回工具 func get_tool_by_type(type:ToolType) -> Node: return get_tool(type_script_map.get(type)) ##获取所有工具 func get_tools() -> Array[CameraToolBasic]: var out: Array[CameraToolBasic] = [] for c in get_children(): if c is CameraToolBasic: out.append(c) return out