extends Node2D ## 2026-07-06 视差定案(策划:远景夕阳要时刻在画面内):背景是"远景天幕", ## 仅以 0.2 倍速随世界滚动(即 80% 跟随相机)——此前 0.92/0.8 的"近景层" ## 参数方向反了,背景几乎钉在世界上,所以一直"看不出视差"。 ## 锚点 1734.5 = 让夕阳(原画 x≈760,世界 x≈1656)在出生点镜头(可见中心 ## 1340.8)恰好居中;相机全程 [1340.8, 2753.2] 内夕阳屏幕位置从中心缓移到 ## 左 282px,始终在画面内(已验算含光晕不出屏)。两端背景覆盖也已验算: ## 极左窗 [880,1801.6]⊂[581.5,2882.5]、极右窗 [2292.4,3214]⊂[1711.5,4012.5]。 ## 已知取舍:步道砖烙在原画里会明显随镜头走(角色脚下滑动感),单张烙死图 ## 无解;美术把"近景步道"拆成独立 1:1 层后即可消除。勿用 Parallax2D ## (历史上因 CanvasModulate/wipe 兼容性移除过,见 decisions.md)。 const PARALLAX_SCROLL_SCALE := 0.2 const PARALLAX_ANCHOR_X := 1734.5 @onready var past_background: CanvasItem = $ArtLayer/PastBackground @onready var future_background: CanvasItem = $ArtLayer/FutureBackground @onready var _art_layer: Node2D = $ArtLayer var _art_base_x := 0.0 func _ready() -> void: _art_base_x = _art_layer.position.x _set_time_phase(_current_time_phase()) var bus := _event_bus_or_null() if bus != null and bus.has_signal("time_phase_changed") and not bus.is_connected("time_phase_changed", _on_time_phase_changed): bus.connect("time_phase_changed", _on_time_phase_changed) func _process(_delta: float) -> void: var camera := get_viewport().get_camera_2d() if camera == null: # headless 测试/无相机场景:背景保持原位。 _art_layer.position.x = _art_base_x return # get_screen_center_position 含 limit 夹取,玩家贴墙时背景不会继续滑。 var center_x := camera.get_screen_center_position().x _art_layer.position.x = _art_base_x + (center_x - PARALLAX_ANCHOR_X) * (1.0 - PARALLAX_SCROLL_SCALE) func _on_time_phase_changed(_previous: StringName, current: StringName, _reason: StringName) -> void: _set_time_phase(current) func _set_time_phase(time_phase: StringName) -> void: var use_future := time_phase == &"future" if past_background != null: past_background.visible = not use_future if future_background != null: future_background.visible = use_future func _current_time_phase() -> StringName: if not is_inside_tree(): return &"past" var manager := get_tree().root.get_node_or_null("TimePhaseManager") if manager != null: return StringName(str(manager.get("current_time_phase"))) return &"past" func _event_bus_or_null() -> Node: if not is_inside_tree(): return null return get_tree().root.get_node_or_null("EventBus")