class_name MainMenu extends CanvasLayer ## MainMenu - Title menu using pre-designed background image (title_menu.png) ## The window is sized to match the image (67% of 1024x1536). ## The image fills the entire window; buttons overlay the pre-drawn slots. signal quick_play signal play_game signal online_game signal open_settings signal quit_game # UI Components var bg_texture: TextureRect var buttons_container: Control var quick_play_button: Button var play_button: Button var online_button: Button var settings_button: Button var quit_button: Button var version_label: Label # Custom font var custom_font: Font = preload("res://JimNightshade-Regular.ttf") # Per-button pixel rects: Rect2(x, y, width, height) at 460x689 window size # Measured from the pre-drawn button slots in title_menu.png const BUTTON_RECTS := [ Rect2(130, 78, 200, 38), # Quick Play Rect2(130, 163, 200, 38), # Play Rect2(130, 229, 200, 38), # Online Rect2(130, 295, 200, 38), # Settings Rect2(130, 360, 200, 38), # Exit ] const DESIGN_SIZE := Vector2(460, 689) func _ready() -> void: # Center the window on screen var screen := DisplayServer.screen_get_size() var win_size := get_tree().root.size DisplayServer.window_set_position(Vector2i( (screen.x - win_size.x) / 2, (screen.y - win_size.y) / 2 )) _create_menu() func _create_menu() -> void: var win_size := get_tree().root.get_visible_rect().size # Background image fills the whole window bg_texture = TextureRect.new() add_child(bg_texture) bg_texture.texture = load("res://assets/ui/title_menu.png") bg_texture.expand_mode = TextureRect.EXPAND_IGNORE_SIZE bg_texture.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED bg_texture.position = Vector2.ZERO bg_texture.size = win_size bg_texture.mouse_filter = Control.MOUSE_FILTER_IGNORE # Container for buttons buttons_container = Control.new() add_child(buttons_container) buttons_container.mouse_filter = Control.MOUSE_FILTER_IGNORE # Create buttons overlaying the pre-drawn slots quick_play_button = _create_overlay_button("Quick Play", 0) quick_play_button.add_theme_color_override("font_color", Color(0.15, 0.13, 0.1)) quick_play_button.add_theme_color_override("font_hover_color", Color(0.3, 0.25, 0.2)) quick_play_button.add_theme_color_override("font_pressed_color", Color(0.05, 0.05, 0.05)) quick_play_button.pressed.connect(_on_quick_play_pressed) play_button = _create_overlay_button("Play", 1) play_button.pressed.connect(_on_play_pressed) online_button = _create_overlay_button("Online", 2) online_button.disabled = true settings_button = _create_overlay_button("Settings", 3) settings_button.disabled = true quit_button = _create_overlay_button("Exit", 4) quit_button.pressed.connect(_on_quit_pressed) # Version label version_label = Label.new() version_label.text = "v0.1.0" version_label.add_theme_font_override("font", custom_font) version_label.add_theme_font_size_override("font_size", 11) version_label.add_theme_color_override("font_color", Color(0.6, 0.6, 0.7, 0.5)) add_child(version_label) # Position everything _reposition_elements() func _create_overlay_button(text: String, slot_index: int) -> Button: var button = Button.new() button.text = text button.add_theme_font_override("font", custom_font) button.add_theme_font_size_override("font_size", 20) button.add_theme_color_override("font_color", Color(0.85, 0.82, 0.72)) button.add_theme_color_override("font_hover_color", Color(1.0, 0.95, 0.8)) button.add_theme_color_override("font_pressed_color", Color(0.7, 0.65, 0.55)) button.add_theme_color_override("font_disabled_color", Color(0.45, 0.42, 0.38)) # Transparent background so the pre-drawn button art shows through var transparent = StyleBoxFlat.new() transparent.bg_color = Color(0, 0, 0, 0) transparent.set_border_width_all(0) transparent.set_content_margin_all(0) button.add_theme_stylebox_override("normal", transparent) var hover_style = StyleBoxFlat.new() hover_style.bg_color = Color(1, 1, 1, 0.1) hover_style.set_border_width_all(0) hover_style.set_content_margin_all(0) button.add_theme_stylebox_override("hover", hover_style) var pressed_style = StyleBoxFlat.new() pressed_style.bg_color = Color(0, 0, 0, 0.2) pressed_style.set_border_width_all(0) pressed_style.set_content_margin_all(0) button.add_theme_stylebox_override("pressed", pressed_style) var disabled_style = StyleBoxFlat.new() disabled_style.bg_color = Color(0, 0, 0, 0.35) disabled_style.set_border_width_all(0) disabled_style.set_content_margin_all(0) button.add_theme_stylebox_override("disabled", disabled_style) button.set_meta("slot_index", slot_index) buttons_container.add_child(button) return button func _reposition_elements() -> void: var win_size := get_tree().root.get_visible_rect().size # Image fills window bg_texture.size = win_size # Scale factor from design size to actual window size var scale := Vector2(win_size.x / DESIGN_SIZE.x, win_size.y / DESIGN_SIZE.y) var base_font := int(22.0 * scale.y) # Position each button using its individual rect for child in buttons_container.get_children(): if child is Button: var slot: int = child.get_meta("slot_index", -1) if slot < 0 or slot >= BUTTON_RECTS.size(): continue var rect: Rect2 = BUTTON_RECTS[slot] child.position = Vector2(rect.position.x * scale.x, rect.position.y * scale.y) child.size = Vector2(rect.size.x * scale.x, rect.size.y * scale.y) child.add_theme_font_override("font", custom_font) child.add_theme_font_size_override("font_size", base_font) # Version label bottom-right version_label.position = Vector2(win_size.x - 80, win_size.y - 24) version_label.size = Vector2(72, 18) func _on_quick_play_pressed() -> void: quick_play.emit() func _on_play_pressed() -> void: play_game.emit() func _on_quit_pressed() -> void: quit_game.emit() get_tree().quit()