相机功能迭代

This commit is contained in:
Reed 2026-01-08 15:53:30 +08:00
parent c5c7248c0f
commit fa055dfdc7
15 changed files with 160 additions and 58 deletions

Binary file not shown.

View File

@ -3,4 +3,6 @@ extends Node2D
func _ready() -> void:
CameraSystem.register_player_camera(self)
$L1_S1.switch_act_by_id(1)
get_tree().call_group(&"PLAYER_RESPAWN",&"respawn_avatar")

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=5 format=3 uid="uid://mi4omkkocmc0"]
[gd_scene load_steps=5 format=3 uid="uid://b0xmcb5i4jey"]
[ext_resource type="Script" uid="uid://bhexx6mj1xv3q" path="res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_2d.gd" id="1_p2s6f"]
[ext_resource type="Script" uid="uid://8umksf8e80fw" path="res://addons/phantom_camera/scripts/resources/tween_resource.gd" id="2_77rrp"]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,13 +0,0 @@
extends Node
var _cached_respawn : Array[PlayerRespawnPoint]
## 外部向管理器注冊自己
func register_player_respawn(prp: PlayerRespawnPoint) -> void:
if not _cached_respawn.has(prp):
_cached_respawn.append(prp)
## 清除其他管理器的Respawn
func reset_all_respawn() -> void:
for i in _cached_respawn:
i._can_respawn = false

View File

@ -1 +0,0 @@
uid://dwee6n1jgif8b

View File

@ -6,8 +6,23 @@ class_name CameraAnchor extends Node2D
@export var enabled: bool = true
@export var blend_time: float = 0.3
@export var zoom: Vector2 = Vector2.ONE
@export var offset: Vector2 = Vector2.ZERO
@export_group("Phantom Camera Config")
@export var zoom: Vector2 = Vector2.ONE:
set(value):
zoom = value
if Engine.is_editor_hint():
queue_redraw()
var _pcam_manager: Node = null
# =====================================================
# ================ Editor Preview =====================
# =====================================================
## 编辑器预览面板设置
@export_group("Editor Preview")
@export var show_frame_preview: bool = true
@export var preview_color: Color = Color(0.2, 0.9, 0.4, 0.8)
@export var preview_line_width: float = 2.0
var _priority: int :
set(value):
@ -21,6 +36,50 @@ func _ready() -> void:
if not Engine.is_editor_hint():
_runtime_ready()
func _enter_tree() -> void:
if Engine.is_editor_hint():
_pcam_manager = Engine.get_singleton("PhantomCameraManager")
return
CameraSystem.register_anchor(self)
func _exit_tree() -> void:
if Engine.is_editor_hint():
_pcam_manager = null
return
CameraSystem.unregister_anchor(self)
func _draw() -> void:
if not Engine.is_editor_hint():
return
if not show_frame_preview:
return
if not is_instance_valid(_pcam_manager):
return
draw_rect(
_camera_frame_rect_like_phantom(),
preview_color,
false,
preview_line_width
)
func _camera_frame_rect_like_phantom() -> Rect2:
# PhantomCamera 使用的是 manager.screen_size
var screen_size: Vector2 = _pcam_manager.screen_size
var z := zoom
z.x = maxf(z.x, 0.001)
z.y = maxf(z.y, 0.001)
var size := Vector2(
screen_size.x / z.x,
screen_size.y / z.y
)
# PhantomCamera以自身为中心
return Rect2(-size * 0.5, size)
func _runtime_ready() -> void:
_priority = priority
@ -30,13 +89,3 @@ func push_camera() -> void:
func pop_camera() -> void:
_priority = 0
func _enter_tree() -> void:
if Engine.is_editor_hint():
return
CameraSystem.register_anchor(self)
func _exit_tree() -> void:
if Engine.is_editor_hint():
return
CameraSystem.unregister_anchor(self)

View File

@ -10,6 +10,10 @@ 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")
@ -36,22 +40,77 @@ func register_anchor(anchor: CameraAnchor) -> void:
return
_cached_anchors.append(anchor)
anchor.on_priority_change.connect(on_anchor_priority_changed)
_sort_anchors()
_try_auto_switch()
_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:
if _current_anchor:
if _current_anchor._priority < priority:
_sort_anchors()
_try_auto_switch()
_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
_try_auto_switch()
_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:
@ -87,12 +146,13 @@ func switch_anchor(target_anchor: CameraAnchor) -> void:
_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_SINE)
_switch_tween.set_trans(Tween.TRANS_CUBIC)
_switch_tween.set_ease(Tween.EASE_OUT)
# ===== 位置 =====
@ -104,19 +164,11 @@ func switch_anchor(target_anchor: CameraAnchor) -> void:
)
# ===== Zoom =====
_switch_tween.tween_property(
camera,
_switch_tween.parallel().tween_property(
p_camera,
"zoom",
target_anchor.zoom,
blend_time
)
# ===== Offset =====
_switch_tween.tween_property(
camera,
"offset",
target_anchor.offset,
blend_time
blend_time * 1.5
)
# 完成回调

View File

@ -13,6 +13,8 @@ texture = ExtResource("1_26tvm")
0:2/0 = 0
1:2/0 = 0
2:0/0 = 0
2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, -3.0719662, -8, -2.9728708)
2:0/0/physics_layer_0/polygon_0/one_way = true
2:0/0/physics_layer_2/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, -3.0719662, -8, -3.0719662)
2:0/0/physics_layer_2/polygon_0/one_way = true
2:1/0 = 0

View File

@ -54,7 +54,7 @@ func _switch_act_internal(act: Act, act_id: int, trans_overwrite: int = 0) -> vo
_current_act_id = act_id
for pid in act.prop_state_map.keys():
var single := act.prop_state_map[pid]
var single : SingleAct = act.prop_state_map[pid]
if single == null:
continue

View File

@ -9,6 +9,7 @@ extends Node
## FLAG
const IS_PROP_STATES_ROOT := true
##当节点更新时,是否要自动重置
@export var auto_refresh: bool = true
func _enter_tree() -> void:

View File

@ -22,7 +22,6 @@ CameraSystem="*res://_shared/camera/CameraSystem.tscn"
GlobalEvent="*res://_shared/global_event.gd"
ReedVFX="*res://addons/reedfx/vfx/ReedVFXSystem.tscn"
ReedSceneRegistry="*res://addons/reedscene/scene/SceneRegistry.gd"
RespawnManager="*res://_shared/RespawnManager.gd"
[display]