Add in-game settings panel

This commit is contained in:
2026-06-19 23:43:44 +09:00
parent 46f8b10d53
commit 0e52fdd68f
4 changed files with 271 additions and 3 deletions

View File

@@ -134,6 +134,7 @@ const HUD_COMMAND_GRID_COLUMNS := 4
const TOP_TOOL_BUTTON_SIZE := Vector2(42, 42)
const BATTLE_UNIT_LIST_PANEL_SIZE := Vector2(420, 360)
const BATTLE_UNIT_LIST_ROW_SIZE := Vector2(372, 42)
const SETTINGS_PANEL_SIZE := Vector2(420, 286)
const LOCAL_COMMAND_BUTTON_SIZE := Vector2(92, 38)
const LOCAL_COMMAND_CANCEL_BUTTON_SIZE := Vector2(196, 30)
const POST_MOVE_MENU_SIZE := Vector2(240, 146)
@@ -478,6 +479,15 @@ var battle_unit_list_rows: VBoxContainer
var battle_unit_list_mode := "ally"
var top_save_button: Button
var top_load_button: Button
var top_settings_button: Button
var settings_panel: PanelContainer
var settings_bgm_toggle: CheckButton
var settings_sfx_toggle: CheckButton
var settings_edge_scroll_toggle: CheckButton
var settings_bgm_volume_slider: HSlider
var settings_sfx_volume_slider: HSlider
var settings_bgm_volume_value_label: Label
var settings_sfx_volume_value_label: Label
var restart_button: Button
var new_campaign_button: Button
var opening_prologue_root: Control
@@ -1293,6 +1303,21 @@ func _make_toolbar_icon(kind: String) -> Texture2D:
_icon_line(image, Vector2i(5, 25), Vector2i(27, 25), red, 3)
_icon_line(image, Vector2i(8, 18), Vector2i(14, 23), red, 2)
_icon_line(image, Vector2i(24, 18), Vector2i(18, 23), red, 2)
"settings":
_icon_circle_outline(image, Vector2i(16, 16), 9, shadow, 5)
_icon_circle_outline(image, Vector2i(16, 16), 9, ink, 3)
_icon_circle(image, Vector2i(16, 16), 3, red)
for point in [
Vector2i(16, 4),
Vector2i(16, 28),
Vector2i(4, 16),
Vector2i(28, 16),
Vector2i(8, 8),
Vector2i(24, 8),
Vector2i(8, 24),
Vector2i(24, 24)
]:
_icon_circle(image, point, 2, ink)
"terrain":
_icon_line(image, Vector2i(5, 22), Vector2i(13, 12), shadow, 5)
_icon_line(image, Vector2i(13, 12), Vector2i(18, 18), shadow, 5)
@@ -1946,7 +1971,7 @@ func _create_hud() -> void:
var top_tool_row := HBoxContainer.new()
top_tool_row.name = "TopToolBar"
top_tool_row.custom_minimum_size = Vector2(332, 48)
top_tool_row.custom_minimum_size = Vector2(378, 48)
top_tool_row.add_theme_constant_override("separation", 5)
top_row.add_child(top_tool_row)
@@ -1966,6 +1991,11 @@ func _create_hud() -> void:
battle_unit_list_button.pressed.connect(_on_battle_unit_list_pressed)
top_tool_row.add_child(battle_unit_list_button)
top_settings_button = Button.new()
_configure_top_tool_button(top_settings_button, "TopSettingsButton", "settings", "환경 설정\n배경음, 효과음, 가장자리 스크롤을 조절합니다.")
top_settings_button.pressed.connect(_on_settings_pressed)
top_tool_row.add_child(top_settings_button)
top_save_button = Button.new()
_configure_top_tool_button(top_save_button, "TopSaveButton", "save", "저장\n전투 전 군막에서 수동 전기를 봉인합니다.")
top_save_button.pressed.connect(_on_top_manual_save_pressed)
@@ -2058,6 +2088,120 @@ func _create_hud() -> void:
battle_unit_list_rows.add_theme_constant_override("separation", 5)
battle_unit_scroll.add_child(battle_unit_list_rows)
settings_panel = PanelContainer.new()
settings_panel.name = "SettingsPanel"
settings_panel.visible = false
settings_panel.mouse_filter = Control.MOUSE_FILTER_STOP
settings_panel.position = Vector2(824, 88)
settings_panel.size = SETTINGS_PANEL_SIZE
settings_panel.custom_minimum_size = SETTINGS_PANEL_SIZE
_apply_panel_style(settings_panel, "compact")
root.add_child(settings_panel)
var settings_column := VBoxContainer.new()
settings_column.add_theme_constant_override("separation", 8)
settings_panel.add_child(settings_column)
var settings_header_row := HBoxContainer.new()
settings_header_row.add_theme_constant_override("separation", 8)
settings_column.add_child(settings_header_row)
var settings_title_label := Label.new()
settings_title_label.text = "환경 설정"
settings_title_label.custom_minimum_size = Vector2(250, 28)
settings_title_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
_apply_label_style(settings_title_label, UI_OLD_BRONZE, 16)
settings_header_row.add_child(settings_title_label)
var settings_close_button := Button.new()
settings_close_button.text = "닫기"
settings_close_button.tooltip_text = "환경 설정을 닫습니다."
settings_close_button.custom_minimum_size = Vector2(76, 28)
_apply_button_style(settings_close_button)
settings_close_button.pressed.connect(_hide_settings_panel)
settings_header_row.add_child(settings_close_button)
settings_column.add_child(_make_seal_ribbon(374, 12))
settings_bgm_toggle = CheckButton.new()
settings_bgm_toggle.text = "배경음"
settings_bgm_toggle.custom_minimum_size = Vector2(374, 30)
settings_bgm_toggle.tooltip_text = "배경 음악을 켜거나 끕니다."
settings_bgm_toggle.toggled.connect(_on_settings_bgm_toggled)
settings_column.add_child(settings_bgm_toggle)
var settings_bgm_volume_row := HBoxContainer.new()
settings_bgm_volume_row.custom_minimum_size = Vector2(374, 34)
settings_bgm_volume_row.add_theme_constant_override("separation", 8)
settings_column.add_child(settings_bgm_volume_row)
var settings_bgm_volume_caption := Label.new()
settings_bgm_volume_caption.text = "배경음 크기"
settings_bgm_volume_caption.custom_minimum_size = Vector2(94, 30)
settings_bgm_volume_caption.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
_apply_label_style(settings_bgm_volume_caption, UI_PARCHMENT_TEXT, 13)
settings_bgm_volume_row.add_child(settings_bgm_volume_caption)
settings_bgm_volume_slider = HSlider.new()
settings_bgm_volume_slider.min_value = 0.0
settings_bgm_volume_slider.max_value = 100.0
settings_bgm_volume_slider.step = 5.0
settings_bgm_volume_slider.size_flags_horizontal = Control.SIZE_EXPAND_FILL
settings_bgm_volume_slider.custom_minimum_size = Vector2(194, 30)
settings_bgm_volume_slider.tooltip_text = "배경 음악의 크기를 조절합니다."
settings_bgm_volume_slider.value_changed.connect(_on_settings_bgm_volume_changed)
settings_bgm_volume_row.add_child(settings_bgm_volume_slider)
settings_bgm_volume_value_label = Label.new()
settings_bgm_volume_value_label.custom_minimum_size = Vector2(48, 30)
settings_bgm_volume_value_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
settings_bgm_volume_value_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
_apply_label_style(settings_bgm_volume_value_label, UI_PARCHMENT_TEXT, 13)
settings_bgm_volume_row.add_child(settings_bgm_volume_value_label)
settings_sfx_toggle = CheckButton.new()
settings_sfx_toggle.text = "효과음"
settings_sfx_toggle.custom_minimum_size = Vector2(374, 30)
settings_sfx_toggle.tooltip_text = "버튼과 전투 효과음을 켜거나 끕니다."
settings_sfx_toggle.toggled.connect(_on_settings_sfx_toggled)
settings_column.add_child(settings_sfx_toggle)
var settings_sfx_volume_row := HBoxContainer.new()
settings_sfx_volume_row.custom_minimum_size = Vector2(374, 34)
settings_sfx_volume_row.add_theme_constant_override("separation", 8)
settings_column.add_child(settings_sfx_volume_row)
var settings_sfx_volume_caption := Label.new()
settings_sfx_volume_caption.text = "효과음 크기"
settings_sfx_volume_caption.custom_minimum_size = Vector2(94, 30)
settings_sfx_volume_caption.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
_apply_label_style(settings_sfx_volume_caption, UI_PARCHMENT_TEXT, 13)
settings_sfx_volume_row.add_child(settings_sfx_volume_caption)
settings_sfx_volume_slider = HSlider.new()
settings_sfx_volume_slider.min_value = 0.0
settings_sfx_volume_slider.max_value = 100.0
settings_sfx_volume_slider.step = 5.0
settings_sfx_volume_slider.size_flags_horizontal = Control.SIZE_EXPAND_FILL
settings_sfx_volume_slider.custom_minimum_size = Vector2(194, 30)
settings_sfx_volume_slider.tooltip_text = "버튼과 전투 효과음의 크기를 조절합니다."
settings_sfx_volume_slider.value_changed.connect(_on_settings_sfx_volume_changed)
settings_sfx_volume_row.add_child(settings_sfx_volume_slider)
settings_sfx_volume_value_label = Label.new()
settings_sfx_volume_value_label.custom_minimum_size = Vector2(48, 30)
settings_sfx_volume_value_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
settings_sfx_volume_value_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
_apply_label_style(settings_sfx_volume_value_label, UI_PARCHMENT_TEXT, 13)
settings_sfx_volume_row.add_child(settings_sfx_volume_value_label)
settings_edge_scroll_toggle = CheckButton.new()
settings_edge_scroll_toggle.text = "가장자리 스크롤"
settings_edge_scroll_toggle.custom_minimum_size = Vector2(374, 30)
settings_edge_scroll_toggle.tooltip_text = "마우스를 전장 가장자리에 두면 화면을 움직입니다."
settings_edge_scroll_toggle.toggled.connect(_on_settings_edge_scroll_toggled)
settings_column.add_child(settings_edge_scroll_toggle)
objective_notice_panel = PanelContainer.new()
objective_notice_panel.visible = false
objective_notice_panel.position = Vector2(338, 88)
@@ -3424,6 +3568,7 @@ func _create_hud() -> void:
next_battle_button,
opening_prologue_skip_button,
opening_prologue_next_button,
top_settings_button,
title_start_button,
title_load_button,
title_settings_button,
@@ -3433,6 +3578,9 @@ func _create_hud() -> void:
_apply_button_style(title_bgm_toggle)
_apply_button_style(title_sfx_toggle)
_apply_button_style(title_edge_scroll_toggle)
_apply_button_style(settings_bgm_toggle)
_apply_button_style(settings_sfx_toggle)
_apply_button_style(settings_edge_scroll_toggle)
_apply_button_style(briefing_start_button, true)
@@ -3502,16 +3650,32 @@ func _volume_percent_to_db(base_volume_db: float, percent: int) -> float:
func _refresh_title_volume_controls() -> void:
if settings_bgm_toggle != null:
settings_bgm_toggle.set_pressed_no_signal(title_bgm_enabled)
if settings_sfx_toggle != null:
settings_sfx_toggle.set_pressed_no_signal(title_sfx_enabled)
if settings_edge_scroll_toggle != null:
settings_edge_scroll_toggle.set_pressed_no_signal(title_edge_scroll_enabled)
if title_bgm_volume_slider != null:
title_bgm_volume_slider.set_value_no_signal(float(title_bgm_volume_percent))
title_bgm_volume_slider.editable = title_bgm_enabled
if settings_bgm_volume_slider != null:
settings_bgm_volume_slider.set_value_no_signal(float(title_bgm_volume_percent))
settings_bgm_volume_slider.editable = title_bgm_enabled
if title_sfx_volume_slider != null:
title_sfx_volume_slider.set_value_no_signal(float(title_sfx_volume_percent))
title_sfx_volume_slider.editable = title_sfx_enabled
if settings_sfx_volume_slider != null:
settings_sfx_volume_slider.set_value_no_signal(float(title_sfx_volume_percent))
settings_sfx_volume_slider.editable = title_sfx_enabled
if title_bgm_volume_value_label != null:
title_bgm_volume_value_label.text = "%d%%" % title_bgm_volume_percent
if settings_bgm_volume_value_label != null:
settings_bgm_volume_value_label.text = "%d%%" % title_bgm_volume_percent
if title_sfx_volume_value_label != null:
title_sfx_volume_value_label.text = "%d%%" % title_sfx_volume_percent
if settings_sfx_volume_value_label != null:
settings_sfx_volume_value_label.text = "%d%%" % title_sfx_volume_percent
func _on_bgm_finished() -> void:
@@ -3851,6 +4015,12 @@ func _handle_cancel_input() -> bool:
_update_hud()
queue_redraw()
return true
if settings_panel != null and settings_panel.visible:
_play_ui_cancel()
_hide_settings_panel()
_update_hud()
queue_redraw()
return true
if not selected_skill_id.is_empty() or not selected_item_id.is_empty() or basic_attack_targeting:
_play_ui_cancel()
selected_skill_id = ""
@@ -3890,6 +4060,10 @@ func _handle_key(event: InputEventKey) -> void:
_hide_formation_menu()
elif save_menu != null and save_menu.visible:
_hide_save_menu()
elif settings_panel != null and settings_panel.visible:
_hide_settings_panel()
_update_hud()
queue_redraw()
elif briefing_panel != null and briefing_panel.visible:
if _set_briefing_objective_collapsed(true):
_play_ui_cancel()
@@ -7203,11 +7377,13 @@ func _update_hud() -> void:
restart_button.disabled = campaign_complete_screen
_update_threat_button()
_update_battle_unit_list_button()
_update_settings_button()
_update_top_archive_buttons()
_update_post_move_menu()
_update_post_move_picker()
_update_targeting_hint_panel()
_update_battle_unit_list_panel()
_update_settings_panel()
_update_auto_end_turn_prompt()
@@ -9987,6 +10163,76 @@ func _on_top_manual_load_pressed() -> void:
_on_manual_load_pressed()
func _on_settings_pressed() -> void:
if top_settings_button == null or top_settings_button.disabled:
return
_play_ui_click()
if _is_settings_panel_visible():
_hide_settings_panel()
else:
_show_settings_panel()
_update_hud()
func _show_settings_panel() -> void:
if settings_panel == null:
return
_hide_battle_unit_list_panel()
_refresh_title_volume_controls()
settings_panel.visible = true
settings_panel.move_to_front()
func _hide_settings_panel() -> void:
if settings_panel == null:
return
settings_panel.visible = false
func _is_settings_panel_visible() -> bool:
return settings_panel != null and settings_panel.visible
func _update_settings_button() -> void:
if top_settings_button == null:
return
var can_show := not _is_title_screen_visible() and not _is_opening_prologue_visible()
_set_action_button_state(
top_settings_button,
"환경 설정",
not can_show,
"배경음, 효과음, 가장자리 스크롤을 조절합니다." if can_show else "타이틀 화면에서는 왼쪽 메뉴의 환경 설정을 사용합니다."
)
if not can_show:
_hide_settings_panel()
func _update_settings_panel() -> void:
if not _is_settings_panel_visible():
return
_refresh_title_volume_controls()
func _on_settings_bgm_toggled(enabled: bool) -> void:
_on_title_bgm_toggled(enabled)
func _on_settings_sfx_toggled(enabled: bool) -> void:
_on_title_sfx_toggled(enabled)
func _on_settings_edge_scroll_toggled(enabled: bool) -> void:
_on_title_edge_scroll_toggled(enabled)
func _on_settings_bgm_volume_changed(value: float) -> void:
_on_title_bgm_volume_changed(value)
func _on_settings_sfx_volume_changed(value: float) -> void:
_on_title_sfx_volume_changed(value)
func _on_battle_unit_list_pressed() -> void:
if battle_unit_list_button == null or battle_unit_list_button.disabled:
return
@@ -9994,6 +10240,7 @@ func _on_battle_unit_list_pressed() -> void:
if battle_unit_list_panel != null and battle_unit_list_panel.visible:
_hide_battle_unit_list_panel()
else:
_hide_settings_panel()
_rebuild_battle_unit_list_rows()
if battle_unit_list_panel != null:
battle_unit_list_panel.visible = true
@@ -10195,6 +10442,7 @@ func _show_title_menu() -> void:
_hide_formation_menu()
_hide_save_menu()
_hide_battle_unit_list_panel()
_hide_settings_panel()
_clear_pending_move_state()
if briefing_panel != null:
briefing_panel.visible = false
@@ -11871,6 +12119,7 @@ func _show_campaign_complete() -> void:
_hide_roster_menu()
_hide_formation_menu()
_hide_save_menu()
_hide_settings_panel()
_clear_dialogue()
active_scenario_id = campaign_state.current_scenario_id
if briefing_panel != null: