2026-01-12 17:51:15 +08:00
|
|
|
@tool
|
|
|
|
|
extends Node
|
|
|
|
|
class_name CameraPointer
|
|
|
|
|
|
|
|
|
|
const _CONSTANTS := preload("res://addons/reedcamera/_data/CameraSystemConst.gd")
|
|
|
|
|
|
2026-01-13 16:52:45 +08:00
|
|
|
## 相机指针所能持有的工具种类
|
|
|
|
|
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")
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-12 17:51:15 +08:00
|
|
|
var _camera: Camera2D
|
|
|
|
|
var _editor_valid := false
|
|
|
|
|
var _runtime_registered := false
|
|
|
|
|
var _warned := false
|
|
|
|
|
|
|
|
|
|
var _final_offset := Vector2.ZERO
|
2026-01-13 00:52:36 +08:00
|
|
|
var _final_position: Vector2
|
|
|
|
|
var _final_zoom := Vector2.ONE
|
|
|
|
|
|
|
|
|
|
var _pos_dirty := false
|
|
|
|
|
var _offset_dirty := false
|
|
|
|
|
var _zoom_dirty := false
|
2026-01-12 17:51:15 +08:00
|
|
|
|
2026-01-13 16:52:45 +08:00
|
|
|
|
2026-01-12 17:51:15 +08:00
|
|
|
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
|
|
|
|
|
|
2026-01-13 00:52:36 +08:00
|
|
|
_reset_dirty_flags()
|
|
|
|
|
|
|
|
|
|
_update_final_position()
|
2026-01-12 17:51:15 +08:00
|
|
|
_update_camera_offset()
|
2026-01-13 00:52:36 +08:00
|
|
|
_update_camera_zoom()
|
|
|
|
|
|
|
|
|
|
_apply_camera_config()
|
2026-01-12 17:51:15 +08:00
|
|
|
|
2026-01-13 00:52:36 +08:00
|
|
|
func _reset_dirty_flags() -> void:
|
|
|
|
|
_pos_dirty = false
|
|
|
|
|
_offset_dirty = false
|
|
|
|
|
_zoom_dirty = false
|
|
|
|
|
|
|
|
|
|
func _update_final_position():
|
2026-01-12 17:51:15 +08:00
|
|
|
for child in get_children():
|
2026-01-13 00:52:36 +08:00
|
|
|
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
|
2026-01-12 17:51:15 +08:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# fallback
|
2026-01-13 00:52:36 +08:00
|
|
|
_final_position = _camera.global_position
|
2026-01-12 17:51:15 +08:00
|
|
|
|
|
|
|
|
func _update_camera_offset():
|
|
|
|
|
var offset := Vector2.ZERO
|
2026-01-13 00:52:36 +08:00
|
|
|
var used := false
|
2026-01-12 17:51:15 +08:00
|
|
|
|
|
|
|
|
for child in get_children():
|
2026-01-13 00:52:36 +08:00
|
|
|
if child is CameraToolBasic \
|
|
|
|
|
and child.enabled \
|
|
|
|
|
and child.affect_offset \
|
|
|
|
|
and child.has_camera_offset():
|
2026-01-12 17:51:15 +08:00
|
|
|
offset += child.get_camera_offset()
|
2026-01-13 00:52:36 +08:00
|
|
|
used = true
|
2026-01-12 17:51:15 +08:00
|
|
|
|
|
|
|
|
_final_offset = offset
|
2026-01-13 00:52:36 +08:00
|
|
|
_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
|
2026-01-12 17:51:15 +08:00
|
|
|
|
2026-01-13 00:52:36 +08:00
|
|
|
if _zoom_dirty:
|
|
|
|
|
_camera.zoom = _final_zoom
|
2026-01-12 17:51:15 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
2026-01-13 16:52:45 +08:00
|
|
|
|
2026-01-12 17:51:15 +08:00
|
|
|
if not _camera:
|
2026-01-13 16:52:45 +08:00
|
|
|
_camera = _find_camera()
|
2026-01-12 17:51:15 +08:00
|
|
|
|
|
|
|
|
_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
|
|
|
|
|
|
2026-01-13 10:32:36 +08:00
|
|
|
## =========================
|
|
|
|
|
## Public API
|
|
|
|
|
## =========================
|
|
|
|
|
##获取相机
|
2026-01-12 17:51:15 +08:00
|
|
|
func get_camera() -> Camera2D:
|
2026-01-13 16:52:45 +08:00
|
|
|
if not _camera:
|
|
|
|
|
_camera = _find_camera()
|
2026-01-12 17:51:15 +08:00
|
|
|
return _camera
|
2026-01-13 10:32:36 +08:00
|
|
|
|
|
|
|
|
##获取特定工具
|
|
|
|
|
func get_tool(tool_class: Script) -> Node:
|
|
|
|
|
for c in get_children():
|
|
|
|
|
if c.get_script() == tool_class:
|
|
|
|
|
return c
|
|
|
|
|
return null
|
|
|
|
|
|
2026-01-13 16:52:45 +08:00
|
|
|
##通过类型返回工具
|
|
|
|
|
func get_tool_by_type(type:ToolType) -> Node:
|
|
|
|
|
return get_tool(type_script_map.get(type))
|
|
|
|
|
|
2026-01-13 10:32:36 +08:00
|
|
|
##获取所有工具
|
|
|
|
|
func get_tools() -> Array[CameraToolBasic]:
|
|
|
|
|
var out: Array[CameraToolBasic] = []
|
|
|
|
|
for c in get_children():
|
|
|
|
|
if c is CameraToolBasic:
|
|
|
|
|
out.append(c)
|
|
|
|
|
return out
|