godot-plateformer/addons/reedcamera/scripts/CameraPointer.gd

169 lines
3.4 KiB
GDScript

@tool
extends Node
class_name CameraPointer
const _CONSTANTS := preload("res://addons/reedcamera/_data/CameraSystemConst.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
_camera = _find_camera()
if not _camera:
return
_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
func get_camera() -> Camera2D:
return _camera