按 code-conventions §1.4.1 第三轮定稿执行:core 22+schemas 18+presentation 根 14+views 28,全部头注 #→##、删日期/变更叙事/GDD 与架构反向链接/字段与域清单/机制描述,保留职责摘要+真实使用约束(防事故禁令/单一入口/信号契约每信号一行)。main.gd 31→5 行、save_manager 45→5 行、adventure_runner 37→5 行为最大单件。子代理分模块执行(波一 core+schemas、波二 presentation+views,并发≤2)。验收=tools/verify_comment_only_change.py 逐字节校验(82 文件头注区外逐行一致=零行为变更)+audit_file_headers 全绿;纯注释批免冒烟(先例 5843270)
146 lines
6.3 KiB
GDScript
146 lines
6.3 KiB
GDScript
## VERTICAL SLICE - NOT FOR PRODUCTION
|
||
## 设置覆盖层:音量/全屏/减动效三件+返回;生效与持久化全经构造注入的 SettingsStore——本类零落盘。
|
||
## 减动效开关唯一入口在设置面;探针/冒烟经 retarget(store) 换注隔离存档,禁碰真实 user://settings.cfg。
|
||
class_name SettingsOverlay
|
||
extends Control
|
||
|
||
signal closed
|
||
|
||
var _store
|
||
var _volume: HSlider
|
||
var _volume_val: Label
|
||
var _fs_btn: Button # M4 换 SwitchToggle 拨杆(仍 Button 子类——探针接缝保持)
|
||
var _motion_btn: Button # M4 同上
|
||
var _fs_st: Label # M4 状态字随行(开/关)
|
||
var _motion_st: Label # M4 状态字(完整/快速)
|
||
|
||
|
||
func _init(store) -> void:
|
||
_store = store
|
||
_build()
|
||
_sync()
|
||
visible = false
|
||
|
||
|
||
# 探针隔离换注(冒烟/探针禁碰真实 user://settings.cfg——换注后按新 store 重挂控件态)
|
||
func retarget(store: SettingsStore) -> void:
|
||
_store = store
|
||
_sync()
|
||
|
||
|
||
func _build() -> void:
|
||
# M4(UI 落码批):石板面板化(demo ③)+行牌化(标签+拨杆+状态字+后果说明行);
|
||
# 设置项零增减(P-C6:只有主音量——demo 音效音量行系原型发明已撤);
|
||
# 减动效与结算演出动画=同一设置(语义命名批合并),一行承载。
|
||
# T8(UI 设计对齐批 2026-10-06):两列对齐(label 列定宽 140——demo .setrow label/控制两列)+
|
||
# 后果说明内联随行(demo .why 同排)+返回钮紧凑化(demo .btn9 紧凑——原 216 宽砖)。
|
||
var shell: Dictionary[Variant, Variant] = UiKit.modal_shell(self, UiKit.BG_BRIGHT, Vector2(560, 0), 8, true,
|
||
UiKit.panel_skinned(Vector4(20, 16, 20, 16)))
|
||
var box: VBoxContainer = shell.box
|
||
|
||
var title := UiKit.label("设置",UiKit.FS_TITLE, true, UiKit.INK_TITLE)
|
||
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||
box.add_child(title)
|
||
var hint := UiKit.label("系统级设置——独立存储不随存档(一安装一份,删游戏才消失)",UiKit.FS_HINT, false, UiKit.INK_HINT)
|
||
hint.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||
box.add_child(hint)
|
||
box.add_child(HSeparator.new())
|
||
|
||
# 音量(master bus 实时生效——入口归设置、生效口径归 音频.md)
|
||
var vol_row := HBoxContainer.new()
|
||
vol_row.add_theme_constant_override("separation", 14)
|
||
box.add_child(vol_row)
|
||
var vol_lab := UiKit.label("主音量",UiKit.FS_BODY, false, UiKit.INK_LABEL)
|
||
vol_lab.custom_minimum_size = Vector2(140, 0) # T8 label 列定宽(两列对齐)
|
||
vol_row.add_child(vol_lab)
|
||
_volume = HSlider.new()
|
||
_volume.min_value = 0.0
|
||
_volume.max_value = 100.0
|
||
_volume.value = 100.0
|
||
_volume.custom_minimum_size = Vector2(200, 24) # 几何/量程内联(迭代 25:样式滑杆工厂退役,皮肤走全局主题)
|
||
_volume.step = 1
|
||
_volume.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
_volume.value_changed.connect(_on_volume_changed)
|
||
vol_row.add_child(_volume)
|
||
_volume_val = UiKit.label("100%",UiKit.FS_BODY, true, UiKit.INK_TITLE)
|
||
_volume_val.custom_minimum_size = Vector2(60, 0)
|
||
vol_row.add_child(_volume_val)
|
||
|
||
# 全屏(拨杆形——M10 SwitchToggle;状态字随行)
|
||
var fs_row := HBoxContainer.new()
|
||
fs_row.add_theme_constant_override("separation", 14)
|
||
box.add_child(fs_row)
|
||
var fs_lab := UiKit.label("全屏",UiKit.FS_BODY, false, UiKit.INK_LABEL)
|
||
fs_lab.custom_minimum_size = Vector2(140, 0) # T8 同上
|
||
fs_row.add_child(fs_lab)
|
||
_fs_btn = UiKit.switch_toggle(false)
|
||
_fs_btn.toggled.connect(_on_fullscreen_toggled)
|
||
fs_row.add_child(_fs_btn)
|
||
_fs_st = UiKit.label("关",UiKit.FS_HINT, true, UiKit.INK_LABEL)
|
||
fs_row.add_child(_fs_st)
|
||
|
||
# 结算演出动画(=减动效实称——语义命名批 T17;拨杆 on=完整,off=快速时长减半。
|
||
# T8 核证:reduced_motion 单设置同驱 UiKit.motion_scale 与结算演播——demo「减动效」行与
|
||
# 本行系同一设置,不另立行(拆两行=一设置双行重复,违语义命名批裁决)
|
||
var motion_row := HBoxContainer.new()
|
||
motion_row.add_theme_constant_override("separation", 14)
|
||
box.add_child(motion_row)
|
||
var motion_lab := UiKit.label("结算演出动画",UiKit.FS_BODY, false, UiKit.INK_LABEL)
|
||
motion_lab.custom_minimum_size = Vector2(140, 0) # T8 同上
|
||
motion_row.add_child(motion_lab)
|
||
_motion_btn = UiKit.switch_toggle(true)
|
||
_motion_btn.toggled.connect(_on_motion_toggled)
|
||
motion_row.add_child(_motion_btn)
|
||
_motion_st = UiKit.label("完整",UiKit.FS_HINT, true, UiKit.INK_LABEL)
|
||
motion_row.add_child(_motion_st)
|
||
var why := UiKit.label("快速 = 时长减半(运动敏感 / 演示用)",UiKit.FS_CAPTION, false, UiKit.INK_HINT)
|
||
motion_row.add_child(why) # T8 内联随行(demo .why 同排;原独立行换排)
|
||
|
||
box.add_child(HSeparator.new())
|
||
# 退出游戏已提级开始菜单(D1——设置面不再承载,用户裁决「退出只在一级菜单出现」)
|
||
var close_row := HBoxContainer.new()
|
||
close_row.alignment = BoxContainer.ALIGNMENT_CENTER
|
||
box.add_child(close_row)
|
||
var close_btn := UiKit.button("返回", 90.0) # T8 紧凑返回钮(demo 紧凑形;原 216 宽砖)
|
||
close_btn.pressed.connect(_emit_closed)
|
||
close_row.add_child(close_btn)
|
||
|
||
|
||
func _sync() -> void:
|
||
_volume.set_value_no_signal(roundf(_store.volume_linear * 100.0))
|
||
_volume_val.text = "%d%%" % roundi(_store.volume_linear * 100.0)
|
||
_fs_btn.set_pressed_no_signal(_store.fullscreen)
|
||
_fs_st.text = "开" if _store.fullscreen else "关"
|
||
_motion_btn.set_pressed_no_signal(not _store.reduced_motion) # 拨杆 on=完整
|
||
_sync_motion_text()
|
||
|
||
|
||
# T17 修复:文案随状态即时刷新(旧 bug=切换后文案恒「开」,玩家无法得知当前态)+语义命名
|
||
# (「减动效」玩家读不懂——实称「结算演出动画」速度档)+操作提示内联(所见即所得)。
|
||
func _sync_motion_text() -> void:
|
||
_motion_st.text = "快速" if _store.reduced_motion else "完整"
|
||
|
||
|
||
func _on_volume_changed(v: float) -> void:
|
||
_store.volume_linear = v / 100.0
|
||
_store.apply()
|
||
_store.save_settings()
|
||
_volume_val.text = "%d%%" % int(v)
|
||
|
||
|
||
func _on_fullscreen_toggled(on: bool) -> void:
|
||
_store.fullscreen = on
|
||
_store.apply()
|
||
_store.save_settings()
|
||
|
||
|
||
func _on_motion_toggled(on: bool) -> void:
|
||
_store.reduced_motion = not on # M4 拨杆语义翻转:on=完整(off=快速)
|
||
_store.apply()
|
||
_store.save_settings()
|
||
_sync_motion_text() # T17 修复:切换即时刷新文案(旧版漏刷新=状态文字恒「开」)
|
||
|
||
|
||
func _emit_closed() -> void:
|
||
closed.emit()
|