266 lines
6.6 KiB
GDScript
266 lines
6.6 KiB
GDScript
#'''全局的相机管理器
|
|
#
|
|
#======= 外部调用函数 =======
|
|
#
|
|
#'''
|
|
#@tool
|
|
extends Node
|
|
#
|
|
#@onready var camera_2d: Camera2D = %Camera2D
|
|
#@onready var camera_shake_player: CameraShakePlayer = %CameraShakePlayer
|
|
#
|
|
#var _cached_anchors: Array[CameraAnchor] = []
|
|
#var _current_anchor: CameraAnchor
|
|
#var _switch_tween: Tween
|
|
#var _player_remote: RemoteTransform2D
|
|
#var _base_camera_pos := Vector2.ZERO
|
|
#
|
|
###标记位,用来检测当前帧是否存在相机切换
|
|
#var _switch_scheduled := false
|
|
#var _dirty := false
|
|
#var _screen_size : Vector2i
|
|
#
|
|
### 玩家关卡内静态相机
|
|
#const CAMERA_FOLLOWER:= preload("res://camera/camera_follower.tscn")
|
|
#
|
|
#func _ready() -> void:
|
|
## Setting default screensize
|
|
#_screen_size = Vector2i(
|
|
#ProjectSettings.get_setting("display/window/size/viewport_width"),
|
|
#ProjectSettings.get_setting("display/window/size/viewport_height")
|
|
#)
|
|
#
|
|
## For editor
|
|
#if Engine.is_editor_hint():
|
|
#ProjectSettings.settings_changed.connect(func():
|
|
#_screen_size = Vector2i(
|
|
#ProjectSettings.get_setting("display/window/size/viewport_width"),
|
|
#ProjectSettings.get_setting("display/window/size/viewport_height")
|
|
#)
|
|
#)
|
|
## For runtime
|
|
#else:
|
|
#get_tree().get_root().size_changed.connect(func():
|
|
#_screen_size = get_viewport().get_visible_rect().size
|
|
#)
|
|
#
|
|
#func _editor_ready() -> void:
|
|
#ProjectSettings.settings_changed.connect(func():
|
|
#_screen_size = Vector2i(
|
|
#ProjectSettings.get_setting("display/window/size/viewport_width"),
|
|
#ProjectSettings.get_setting("display/window/size/viewport_height")
|
|
#)
|
|
#)
|
|
#
|
|
#func _runtime_ready() -> void:
|
|
#get_tree().get_root().size_changed.connect(func():
|
|
#_screen_size = get_viewport().get_visible_rect().size
|
|
#)
|
|
#
|
|
##func _process(delta):
|
|
##if not Engine.is_editor_hint():
|
|
##_runtime_process(delta)
|
|
#
|
|
#
|
|
#func _runtime_process(delta):
|
|
#if not camera_2d:
|
|
#return
|
|
#
|
|
#var shake_offset := camera_shake_player.update(delta)
|
|
#camera_2d.global_position = _base_camera_pos + shake_offset
|
|
#
|
|
#func _on_player_spawned(new_player: Player) -> void:
|
|
#if _current_anchor and _current_anchor.follow_player:
|
|
#_bind_camera_follow_to_player(new_player)
|
|
#
|
|
#func _on_player_dead() -> void:
|
|
#return
|
|
#
|
|
### 绑定camera 到 player
|
|
#func _bind_camera_follow_to_player(player: Player) -> void:
|
|
#if _player_remote and is_instance_valid(_player_remote):
|
|
#_player_remote.queue_free()
|
|
#_player_remote = null
|
|
#
|
|
#if not is_instance_valid(player):
|
|
#return
|
|
#
|
|
#var rt := RemoteTransform2D.new()
|
|
#rt.name = "__CameraAnchorFollow"
|
|
#rt.remote_path = camera_2d.get_path()
|
|
#rt.update_position = true
|
|
#rt.update_rotation = false
|
|
#rt.update_scale = false
|
|
#
|
|
#player.add_child(rt)
|
|
#_player_remote = rt
|
|
#
|
|
### 外部获取玩家全局相机
|
|
#func get_cached_camera() -> Camera2D:
|
|
#return camera_2d
|
|
#
|
|
### 注册一个相机锚点
|
|
#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()
|
|
#
|
|
### 当相机锚点的权重改变时,向管理器触发事件
|
|
#func on_anchor_priority_changed(priority:int, anchor: CameraAnchor) -> void:
|
|
#_request_evaluate()
|
|
#
|
|
### 注销一个相机锚点
|
|
#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")
|
|
#
|
|
#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))
|
|
#
|
|
#var winner: CameraAnchor = _pick_best_anchor()
|
|
#
|
|
#if winner == null:
|
|
#return
|
|
#
|
|
#if winner == _current_anchor:
|
|
#return
|
|
#
|
|
#switch_anchor(winner)
|
|
#
|
|
#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
|
|
#
|
|
#
|
|
#
|
|
###应用Anchor的Limit
|
|
#func _apply_anchor_limits(anchor: CameraAnchor) -> void:
|
|
#if not camera_2d:
|
|
#return
|
|
#camera_2d.limit_left = anchor.global_position.x + anchor.limit_left
|
|
#camera_2d.limit_right = anchor.global_position.x + anchor.limit_right
|
|
#camera_2d.limit_top = anchor.global_position.y + anchor.limit_top
|
|
#camera_2d.limit_bottom = anchor.global_position.y + anchor.limit_bottom
|
|
#
|
|
#func _clear_camera_limits() -> void:
|
|
#if not camera_2d:
|
|
#return
|
|
#camera_2d.limit_left = -10000000
|
|
#camera_2d.limit_right = 10000000
|
|
#camera_2d.limit_top = -10000000
|
|
#camera_2d.limit_bottom = 10000000
|
|
#
|
|
### 切换相机
|
|
#func switch_anchor(target_anchor: CameraAnchor) -> void:
|
|
#if target_anchor == null:
|
|
#return
|
|
#if target_anchor == _current_anchor:
|
|
#return
|
|
#if not is_instance_valid(camera_2d):
|
|
#return
|
|
#
|
|
##优先清除已有的remote
|
|
#if _player_remote:
|
|
#_player_remote.queue_free()
|
|
#_player_remote = null
|
|
#
|
|
## 中断旧 Tween
|
|
#if _switch_tween and _switch_tween.is_running():
|
|
#_switch_tween.kill()
|
|
#_switch_tween = null
|
|
#
|
|
#var camera := camera_2d
|
|
#var blend_time : float = max(target_anchor.blend_time, 0.001)
|
|
#
|
|
#_clear_camera_limits()
|
|
#
|
|
#_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(
|
|
#self,
|
|
#"_base_camera_pos",
|
|
#target_anchor.global_position,
|
|
#blend_time
|
|
#)
|
|
#
|
|
## ===== Zoom =====
|
|
#_switch_tween.parallel().tween_property(
|
|
#camera,
|
|
#"zoom",
|
|
#target_anchor.zoom,
|
|
#blend_time * 1.5
|
|
#)
|
|
#
|
|
## 完成回调
|
|
#_switch_tween.finished.connect(func():
|
|
#_current_anchor = target_anchor
|
|
#_update_anchor_follow_state(target_anchor)
|
|
#_apply_anchor_limits(target_anchor)
|
|
#)
|
|
#
|
|
#_current_anchor = target_anchor
|
|
#
|
|
#func _update_anchor_follow_state(anchor: CameraAnchor) -> void:
|
|
#if not anchor.follow_player:
|
|
#return
|
|
#
|
|
#var player := GlobalEvent.get_player()
|
|
#if player:
|
|
#_bind_camera_follow_to_player(player)
|
|
#
|
|
## ==========================
|
|
## External API
|
|
## ==========================
|
|
### 重置所有的Camera的_priority
|
|
#func reset_all_camera_priority() -> void:
|
|
#for a in _cached_anchors:
|
|
#a._priority = 0
|
|
#
|
|
### 返回屏幕比例
|
|
#func get_screen_size() -> Vector2i:
|
|
#return _screen_size
|