2026-01-13 00:52:36 +08:00
|
|
|
extends CameraToolBasic
|
2026-01-12 17:51:15 +08:00
|
|
|
class_name ReedCameraAnchorController
|
|
|
|
|
|
|
|
|
|
const _CONSTANTS = preload("res://addons/reedcamera/_data/CameraSystemConst.gd")
|
|
|
|
|
## =========================
|
|
|
|
|
## Private
|
|
|
|
|
## =========================
|
|
|
|
|
var _anchors: Array[CameraAnchor] = []
|
|
|
|
|
var _current_anchor: CameraAnchor
|
|
|
|
|
var _current_position := Vector2.ZERO
|
2026-01-13 00:52:36 +08:00
|
|
|
var _current_zoom := Vector2.ONE
|
2026-01-12 17:51:15 +08:00
|
|
|
var _tween: Tween
|
|
|
|
|
|
|
|
|
|
## =========================
|
|
|
|
|
## Config
|
|
|
|
|
## =========================
|
|
|
|
|
@export var move_duration := 0.4
|
|
|
|
|
@export var ease_type := Tween.EASE_OUT
|
|
|
|
|
@export var trans_type := Tween.TRANS_CUBIC
|
|
|
|
|
|
2026-01-13 00:52:36 +08:00
|
|
|
var _evaluate_requested := false
|
|
|
|
|
var _evaluate_scheduled := false
|
|
|
|
|
|
|
|
|
|
var _sys : Object = null
|
2026-01-12 17:51:15 +08:00
|
|
|
|
2026-01-13 00:52:36 +08:00
|
|
|
enum AnchorState {
|
|
|
|
|
IDLE,
|
|
|
|
|
TRANSITIONING,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var _state := AnchorState.IDLE
|
2026-01-12 17:51:15 +08:00
|
|
|
|
|
|
|
|
## =========================
|
|
|
|
|
## Lifecycle
|
|
|
|
|
## =========================
|
|
|
|
|
|
|
|
|
|
func _ready() -> void:
|
2026-01-13 00:52:36 +08:00
|
|
|
_anchors = _get_camera_system().get_all_anchors()
|
2026-01-12 17:51:15 +08:00
|
|
|
|
2026-01-13 00:52:36 +08:00
|
|
|
_get_camera_system().anchors_changed.connect(_on_anchors_changed)
|
2026-01-12 17:51:15 +08:00
|
|
|
|
2026-01-13 00:52:36 +08:00
|
|
|
_request_evaluate()
|
2026-01-12 17:51:15 +08:00
|
|
|
|
2026-01-13 00:52:36 +08:00
|
|
|
func _on_anchors_changed() -> void:
|
|
|
|
|
_sync_anchors()
|
|
|
|
|
_request_evaluate()
|
2026-01-12 17:51:15 +08:00
|
|
|
|
2026-01-13 00:52:36 +08:00
|
|
|
func _sync_anchors() -> void:
|
|
|
|
|
_anchors = _get_camera_system().get_all_anchors()
|
2026-01-12 17:51:15 +08:00
|
|
|
|
2026-01-13 00:52:36 +08:00
|
|
|
func _request_evaluate() -> void:
|
|
|
|
|
_evaluate_requested = true
|
2026-01-12 17:51:15 +08:00
|
|
|
|
2026-01-13 00:52:36 +08:00
|
|
|
if _evaluate_scheduled:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
_evaluate_scheduled = true
|
|
|
|
|
call_deferred("_commit_evaluate")
|
|
|
|
|
|
|
|
|
|
func _commit_evaluate() -> void:
|
|
|
|
|
_evaluate_scheduled = false
|
|
|
|
|
|
|
|
|
|
if not _evaluate_requested:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
_evaluate_requested = false
|
|
|
|
|
_evaluate_impl()
|
|
|
|
|
|
|
|
|
|
func _evaluate_impl() -> void:
|
2026-01-12 17:51:15 +08:00
|
|
|
var winner := _pick_best_anchor()
|
|
|
|
|
if winner == _current_anchor:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
_switch_to(winner)
|
|
|
|
|
|
|
|
|
|
func _pick_best_anchor() -> CameraAnchor:
|
|
|
|
|
var best: CameraAnchor
|
|
|
|
|
var best_p := -INF
|
|
|
|
|
|
|
|
|
|
for a in _anchors:
|
|
|
|
|
if not a.enabled:
|
|
|
|
|
continue
|
|
|
|
|
if a.priority > best_p:
|
|
|
|
|
best = a
|
|
|
|
|
best_p = a.priority
|
|
|
|
|
|
|
|
|
|
return best
|
|
|
|
|
|
|
|
|
|
func _switch_to(anchor: CameraAnchor) -> void:
|
|
|
|
|
if not anchor:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
_current_anchor = anchor
|
2026-01-13 00:52:36 +08:00
|
|
|
_state = AnchorState.TRANSITIONING
|
|
|
|
|
|
2026-01-12 17:51:15 +08:00
|
|
|
var target := anchor.global_position
|
2026-01-13 00:52:36 +08:00
|
|
|
var target_zoom := anchor.zoom if (anchor.zoom.x > 0 and anchor.zoom.y > 0) else Vector2.ONE
|
2026-01-12 17:51:15 +08:00
|
|
|
|
|
|
|
|
if _tween and _tween.is_running():
|
|
|
|
|
_tween.kill()
|
|
|
|
|
|
|
|
|
|
if not anchor.use_blend or anchor.blend_time <= 0.0:
|
|
|
|
|
_current_position = target
|
2026-01-13 00:52:36 +08:00
|
|
|
_current_zoom = target_zoom
|
|
|
|
|
_state = AnchorState.IDLE
|
2026-01-12 17:51:15 +08:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
_tween = get_tree().create_tween()
|
2026-01-13 00:52:36 +08:00
|
|
|
_tween.set_ignore_time_scale(true)
|
|
|
|
|
_tween.set_trans(trans_type)
|
|
|
|
|
_tween.set_ease(ease_type)
|
|
|
|
|
|
2026-01-12 17:51:15 +08:00
|
|
|
_tween.tween_property(self, "_current_position", target, anchor.blend_time)
|
2026-01-13 00:52:36 +08:00
|
|
|
_tween.parallel().tween_property(self, "_current_zoom", target_zoom, anchor.blend_time)
|
|
|
|
|
|
|
|
|
|
_tween.finished.connect(func():
|
|
|
|
|
_state = AnchorState.IDLE
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func _get_camera_system() -> Object:
|
|
|
|
|
if _sys:
|
|
|
|
|
return _sys
|
|
|
|
|
|
|
|
|
|
if Engine.has_singleton(_CONSTANTS.CAMERA_SYSTEM_NAME):
|
|
|
|
|
_sys = Engine.get_singleton(_CONSTANTS.CAMERA_SYSTEM_NAME)
|
|
|
|
|
|
|
|
|
|
return _sys
|
2026-01-12 17:51:15 +08:00
|
|
|
|
|
|
|
|
## =========================
|
|
|
|
|
## CameraPointer Interface
|
|
|
|
|
## =========================
|
|
|
|
|
func get_base_position() -> Vector2:
|
2026-01-13 00:52:36 +08:00
|
|
|
if _state != AnchorState.TRANSITIONING:
|
|
|
|
|
return Vector2.ZERO
|
2026-01-12 17:51:15 +08:00
|
|
|
return _current_position
|
2026-01-13 00:52:36 +08:00
|
|
|
|
|
|
|
|
func has_base_position() -> bool:
|
|
|
|
|
return _state == AnchorState.TRANSITIONING
|
|
|
|
|
|
|
|
|
|
func get_camera_zoom() -> Vector2:
|
|
|
|
|
if _state != AnchorState.TRANSITIONING:
|
|
|
|
|
return Vector2.ONE
|
|
|
|
|
return _current_zoom
|
|
|
|
|
|
|
|
|
|
func has_camera_zoom() -> bool:
|
|
|
|
|
return _state == AnchorState.TRANSITIONING
|