Feat/9 adding main menu fundamentals #13

Merged
Dotts merged 4 commits from feat/9-adding-main-menu-fundamentals into main 2026-06-06 10:09:50 -07:00
2 changed files with 139 additions and 15 deletions
Showing only changes of commit 11adbc339a - Show all commits
+113 -15
View File
@@ -1,6 +1,11 @@
extends Control
var _ui_vbox: VBoxContainer
var _level_selector_panel: VBoxContainer
func _ready() -> void:
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
# ==========================================
# BACKGROUND: 3D DIORAMA (Sliding Player)
# ==========================================
@@ -19,13 +24,13 @@ func _ready() -> void:
# ==========================================
# FOREGROUND: UI (Title and Buttons)
# ==========================================
var ui_vbox = VBoxContainer.new()
ui_vbox.add_theme_constant_override("separation", 30)
ui_vbox.set_anchor_and_offset(SIDE_LEFT, 0.0, 50)
ui_vbox.set_anchor_and_offset(SIDE_TOP, 0.0, 50)
ui_vbox.set_anchor_and_offset(SIDE_RIGHT, 0.0, 600)
ui_vbox.set_anchor_and_offset(SIDE_BOTTOM, 1.0, -50)
add_child(ui_vbox)
_ui_vbox = VBoxContainer.new()
_ui_vbox.add_theme_constant_override("separation", 30)
_ui_vbox.set_anchor_and_offset(SIDE_LEFT, 0.0, 50)
_ui_vbox.set_anchor_and_offset(SIDE_TOP, 0.0, 50)
_ui_vbox.set_anchor_and_offset(SIDE_RIGHT, 0.0, 600)
_ui_vbox.set_anchor_and_offset(SIDE_BOTTOM, 1.0, -50)
add_child(_ui_vbox)
# Title
var title = Label.new()
@@ -34,20 +39,108 @@ func _ready() -> void:
title.add_theme_color_override("font_color", Color(1, 0.6, 0.2)) # Papaya orange
title.add_theme_color_override("font_outline_color", Color(0, 0, 0))
title.add_theme_constant_override("outline_size", 12)
ui_vbox.add_child(title)
_ui_vbox.add_child(title)
# Spacer
var spacer = Control.new()
spacer.custom_minimum_size = Vector2(0, 40)
ui_vbox.add_child(spacer)
_ui_vbox.add_child(spacer)
# Buttons
_add_button(ui_vbox, "Singleplayer", _on_singleplayer_pressed)
_add_button(ui_vbox, "Multiplayer", _on_multiplayer_pressed)
_add_button(ui_vbox, "Settings", _on_settings_pressed)
_add_button(ui_vbox, "Exit Game", _on_exit_pressed)
_add_button(_ui_vbox, "Singleplayer", _on_singleplayer_pressed)
_add_button(_ui_vbox, "Multiplayer", _on_multiplayer_pressed)
_add_button(_ui_vbox, "Settings", _on_settings_pressed)
_add_button(_ui_vbox, "Exit Game", _on_exit_pressed)
func _add_button(parent: VBoxContainer, text: String, callback: Callable) -> void:
# ==========================================
# LEVEL SELECTOR PANEL
# ==========================================
_level_selector_panel = VBoxContainer.new()
_level_selector_panel.add_theme_constant_override("separation", 20)
_level_selector_panel.set_anchor_and_offset(SIDE_LEFT, 0.0, 50)
_level_selector_panel.set_anchor_and_offset(SIDE_TOP, 0.0, 50)
_level_selector_panel.set_anchor_and_offset(SIDE_RIGHT, 0.0, 800)
_level_selector_panel.set_anchor_and_offset(SIDE_BOTTOM, 1.0, -50)
_level_selector_panel.hide()
add_child(_level_selector_panel)
var ls_title = Label.new()
ls_title.text = "Select Level"
ls_title.add_theme_font_size_override("font_size", 64)
ls_title.add_theme_color_override("font_color", Color(1, 1, 1))
ls_title.add_theme_color_override("font_outline_color", Color(0, 0, 0))
ls_title.add_theme_constant_override("outline_size", 8)
_level_selector_panel.add_child(ls_title)
# Cards Container
var cards_hbox = HBoxContainer.new()
cards_hbox.add_theme_constant_override("separation", 30)
cards_hbox.size_flags_vertical = Control.SIZE_EXPAND_FILL
_level_selector_panel.add_child(cards_hbox)
# Level 1: Dust 2
var d2_gradient = Gradient.new()
d2_gradient.add_point(0.0, Color(0.9, 0.8, 0.6)) # Sand
d2_gradient.add_point(1.0, Color(0.6, 0.5, 0.3)) # Dark sand
_build_level_card(cards_hbox, "Dust 2", "res://scenes/dust2_level/dust2_level.tscn", d2_gradient)
# Level 2: Test Level
var tl_gradient = Gradient.new()
tl_gradient.add_point(0.0, Color(0.2, 0.2, 0.25)) # Dark grey
tl_gradient.add_point(1.0, Color(0.3, 0.5, 0.6)) # Steel blue
_build_level_card(cards_hbox, "Test Level", "res://scenes/test_level/test_level.tscn", tl_gradient)
var ls_spacer = Control.new()
ls_spacer.custom_minimum_size = Vector2(0, 20)
_level_selector_panel.add_child(ls_spacer)
_add_button(_level_selector_panel, "Back", _on_back_pressed)
func _build_level_card(parent: Container, title: String, scene_path: String, gradient: Gradient) -> void:
var btn = TextureButton.new()
btn.custom_minimum_size = Vector2(300, 400)
var tex = GradientTexture2D.new()
tex.gradient = gradient
tex.width = 300
tex.height = 400
tex.fill_to = Vector2(1, 1)
btn.texture_normal = tex
var tex_hover = GradientTexture2D.new()
tex_hover.gradient = gradient
tex_hover.width = 300
tex_hover.height = 400
tex_hover.fill_to = Vector2(1, 1)
tex_hover.use_hdr = true # Slight bright effect on hover
btn.texture_hover = tex_hover
btn.modulate = Color(1, 1, 1)
# VBox to hold the label
var vbox = VBoxContainer.new()
vbox.set_anchors_preset(Control.PRESET_FULL_RECT)
vbox.alignment = BoxContainer.ALIGNMENT_END
btn.add_child(vbox)
# Dimming overlay at the bottom for text readability
var overlay = ColorRect.new()
overlay.color = Color(0, 0, 0, 0.6)
overlay.custom_minimum_size = Vector2(0, 60)
vbox.add_child(overlay)
var lbl = Label.new()
lbl.text = title
lbl.add_theme_font_size_override("font_size", 32)
lbl.add_theme_color_override("font_color", Color.WHITE)
lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
lbl.set_anchors_preset(Control.PRESET_FULL_RECT)
overlay.add_child(lbl)
btn.pressed.connect(func(): get_tree().change_scene_to_file(scene_path))
parent.add_child(btn)
func _add_button(parent: Container, text: String, callback: Callable) -> void:
var btn = Button.new()
btn.text = text
btn.add_theme_font_size_override("font_size", 32)
@@ -56,8 +149,13 @@ func _add_button(parent: VBoxContainer, text: String, callback: Callable) -> voi
btn.pressed.connect(callback)
parent.add_child(btn)
func _on_back_pressed() -> void:
_level_selector_panel.hide()
_ui_vbox.show()
func _on_singleplayer_pressed() -> void:
get_tree().change_scene_to_file("res://scenes/dust2_level/dust2_level.tscn")
_ui_vbox.hide()
_level_selector_panel.show()
func _on_multiplayer_pressed() -> void:
print("Multiplayer not implemented yet.")
+26
View File
@@ -6,6 +6,7 @@ var resume_btn: Button
var respawn_btn: Button
var loadouts_btn: Button
var settings_btn: Button
var return_btn: Button
var exit_btn: Button
# Loadout UI
@@ -48,6 +49,7 @@ var rebind_label: Label
var waiting_for_input_action: String = ""
var quit_dialog: ConfirmationDialog
var return_dialog: ConfirmationDialog
func _ready() -> void:
process_mode = Node.PROCESS_MODE_ALWAYS
@@ -70,6 +72,10 @@ func _input(event: InputEvent) -> void:
return
if event.is_action_pressed("ui_cancel"):
# Don't open the pause menu if we are already in the main menu
if get_tree().current_scene and get_tree().current_scene.name == "MainMenu":
return
if visible:
_resume()
else:
@@ -129,6 +135,11 @@ func _build_ui() -> void:
settings_btn.custom_minimum_size = Vector2(200, 50)
main_vbox.add_child(settings_btn)
return_btn = Button.new()
return_btn.text = "Main Menu"
return_btn.custom_minimum_size = Vector2(200, 50)
main_vbox.add_child(return_btn)
exit_btn = Button.new()
exit_btn.text = "Exit Game"
exit_btn.custom_minimum_size = Vector2(200, 50)
@@ -571,6 +582,12 @@ func _build_ui() -> void:
quit_dialog.title = "Quit Game"
quit_dialog.dialog_text = "Are you sure you want to close the game?"
add_child(quit_dialog)
# ── Return Dialog ──
return_dialog = ConfirmationDialog.new()
return_dialog.title = "Main Menu"
return_dialog.dialog_text = "Are you sure you want to return to the main menu?"
add_child(return_dialog)
func _build_vol_control(parent: Node, label_name: String) -> Array:
var hbox = HBoxContainer.new()
@@ -619,11 +636,20 @@ func _connect_signals() -> void:
respawn_btn.pressed.connect(_respawn)
loadouts_btn.pressed.connect(_show_loadouts)
settings_btn.pressed.connect(_show_settings)
return_btn.pressed.connect(_show_return_dialog)
exit_btn.pressed.connect(_show_exit_dialog)
back_to_main_btn.pressed.connect(_show_main_menu)
settings_back_btn.pressed.connect(_show_main_menu)
save_loadout_btn.pressed.connect(_save_current_loadout)
quit_dialog.confirmed.connect(_quit_game)
return_dialog.confirmed.connect(_return_to_main_menu)
func _show_return_dialog() -> void:
return_dialog.popup_centered()
func _return_to_main_menu() -> void:
_resume() # Reset pause state and cursor mode
get_tree().change_scene_to_file("res://ui/main_menu/main_menu.tscn")
func _show_main_menu() -> void:
main_vbox.visible = true