180 lines
4.3 KiB
GDScript
180 lines
4.3 KiB
GDScript
'''全局的相机管理器
|
||
|
||
======= 外部调用函数 =======
|
||
|
||
'''
|
||
extends Node
|
||
|
||
var _cached_player_camera: GlobalCamera
|
||
var _cached_anchors: Array[CameraAnchor] = []
|
||
var _current_anchor: CameraAnchor
|
||
var _switch_tween: Tween
|
||
|
||
##标记位,用来检测当前帧是否存在相机切换
|
||
var _switch_scheduled := false
|
||
var _dirty := false
|
||
|
||
## 玩家关卡内静态相机
|
||
const PLAYER_CAMERA_SCENE:= preload("res://_shared/camera/PlayerStaticCamera.tscn")
|
||
|
||
## 注册玩家相机
|
||
func register_player_camera(owner: Node) -> GlobalCamera:
|
||
if not _cached_player_camera:
|
||
_cached_player_camera = PLAYER_CAMERA_SCENE.instantiate() as GlobalCamera
|
||
|
||
if _cached_player_camera:
|
||
owner.add_child(_cached_player_camera)
|
||
|
||
return _cached_player_camera
|
||
|
||
## 外部获取玩家全局相机
|
||
func get_cached_camera() -> GlobalCamera:
|
||
return _cached_player_camera
|
||
|
||
func get_player_camera() -> GlobalCamera:
|
||
return _cached_player_camera
|
||
|
||
## 注册一个相机锚点
|
||
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()
|
||
|
||
#if anchor in _cached_anchors:
|
||
#return
|
||
#_cached_anchors.append(anchor)
|
||
#anchor.on_priority_change.connect(on_anchor_priority_changed)
|
||
#_sort_anchors()
|
||
#_try_auto_switch()
|
||
|
||
## 当相机锚点的权重改变时,向管理器触发事件
|
||
func on_anchor_priority_changed(priority:int, anchor: CameraAnchor) -> void:
|
||
_request_evaluate()
|
||
#if _current_anchor:
|
||
#if _current_anchor._priority < priority:
|
||
#_sort_anchors()
|
||
#_try_auto_switch()
|
||
|
||
## 注销一个相机锚点
|
||
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")
|
||
# call_deferred 会在当前调用栈/本帧末尾(idle)执行一次
|
||
|
||
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))
|
||
|
||
# 计算 winner(只算一次)
|
||
var winner: CameraAnchor = _pick_best_anchor()
|
||
|
||
# winner 为空就不动(或回默认)
|
||
if winner == null:
|
||
return
|
||
|
||
# 如果没变,不切
|
||
if winner == _current_anchor:
|
||
return
|
||
|
||
switch_anchor(winner)
|
||
|
||
#_cached_anchors.erase(anchor)
|
||
#if _current_anchor == anchor:
|
||
#_current_anchor = null
|
||
#_try_auto_switch()
|
||
|
||
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
|
||
|
||
## 重置所有的Camera的_priority
|
||
func reset_all_camera_priority() -> void:
|
||
for a in _cached_anchors:
|
||
a._priority = 0
|
||
|
||
## 切换相机
|
||
func switch_anchor(target_anchor: CameraAnchor) -> void:
|
||
if target_anchor == null:
|
||
return
|
||
if target_anchor == _current_anchor:
|
||
return
|
||
if not is_instance_valid(_cached_player_camera):
|
||
return
|
||
|
||
# 中断旧 Tween
|
||
if _switch_tween and _switch_tween.is_running():
|
||
_switch_tween.kill()
|
||
_switch_tween = null
|
||
|
||
var camera := _cached_player_camera
|
||
var p_camera : PhantomCamera2D = _cached_player_camera.phantom_camera_2d
|
||
var blend_time : float = max(target_anchor.blend_time, 0.001)
|
||
|
||
# 创建 Tween(关键:ignore time scale)
|
||
_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(
|
||
camera,
|
||
"global_position",
|
||
target_anchor.global_position,
|
||
blend_time
|
||
)
|
||
|
||
# ===== Zoom =====
|
||
_switch_tween.parallel().tween_property(
|
||
p_camera,
|
||
"zoom",
|
||
target_anchor.zoom,
|
||
blend_time * 1.5
|
||
)
|
||
|
||
# 完成回调
|
||
_switch_tween.finished.connect(func():
|
||
_current_anchor = target_anchor
|
||
)
|
||
|
||
_current_anchor = target_anchor
|