Mode select dialog at startup (Target/Zen/Infinite), Zen only for Target, refined circus-wood look (codex)

This commit is contained in:
enne2
2026-08-19 00:17:35 +02:00
parent 725183290b
commit de7dfdf9f7
2 changed files with 292 additions and 0 deletions
+11
View File
@@ -67,6 +67,7 @@ var sound_defeat: AudioStreamWAV
var sound_lose_heart: AudioStreamWAV
var hearts: Node2D
var victory_layer: CanvasLayer
var mode_select: CanvasLayer
var victory_shown := false
var ball_sounds := {} # color_name -> AudioStreamWAV (tono pentatonico)
var bgm: AudioStreamPlayer
@@ -88,7 +89,12 @@ func _ready() -> void:
victory_layer = load("res://scripts/victory_overlay.gd").new()
victory_layer.reset_requested.connect(_reset_after_victory)
add_child(victory_layer)
mode_select = load("res://scripts/mode_select.gd").new()
mode_select.mode_chosen.connect(_start_with_mode)
add_child(mode_select)
_new_game()
# primo avvio: mostra il dialog di scelta modalità
mode_select.show_menu()
func _process(delta: float) -> void:
@@ -373,6 +379,11 @@ func _new_game() -> void:
_update_hud()
func _start_with_mode() -> void:
# chiamato dal dialog di scelta modalità: avvia la partita con la modalità scelta
_new_game()
func _handle_click(pos: Vector2) -> void:
var clicked: Area2D = null
var best := HIT_RADIUS
+281
View File
@@ -0,0 +1,281 @@
extends CanvasLayer
## Dialog di scelta modalità mostrato all'apertura del gioco:
## - Target (a punteggio) con opzione Zen (senza tempo)
## - Infinita (a vite / endless, ignora il punteggio)
signal mode_chosen # emesso quando si preme GIOCA
const DISPLAY_FONT := preload("res://assets/fonts/NotoSerifDisplay-CondensedExtraBold.ttf")
const WOOD_TEXTURE := preload("res://assets/wood_board_rounded.png")
const INK := Color("#482615")
const BRASS := Color("#d5a83f")
const BRASS_LIGHT := Color("#f6d77a")
var target_btn: Button
var infinite_btn: Button
var zen_cb: CheckButton
var play_btn: Button
var _card: Control
var _group := ButtonGroup.new()
class CircusTrim extends Control:
func _ready() -> void:
mouse_filter = Control.MOUSE_FILTER_IGNORE
queue_redraw()
func _draw() -> void:
var colors := [Color("#a9403e"), Color("#d5a83f"), Color("#397b76")]
var count := 11
var span := 440.0
var start_x := (size.x - span) * 0.5
draw_line(Vector2(start_x - 10, 8), Vector2(start_x + span + 10, 8), Color("#63361f"), 3.0, true)
for i in count:
var x := start_x + i * (span / float(count - 1)) - 16.0
var points := PackedVector2Array([Vector2(x, 7), Vector2(x + 32, 7), Vector2(x + 16, 31)])
draw_colored_polygon(points, colors[i % colors.size()])
draw_polyline(PackedVector2Array([points[0], points[1], points[2], points[0]]), Color("#6b341c"), 1.5, true)
class BrassStuds extends Control:
func _ready() -> void:
mouse_filter = Control.MOUSE_FILTER_IGNORE
queue_redraw()
func _draw() -> void:
for p in [Vector2(22, 22), Vector2(size.x - 22, 22), Vector2(22, size.y - 22), Vector2(size.x - 22, size.y - 22)]:
draw_circle(p + Vector2(1.5, 2.5), 8.0, Color(0.12, 0.05, 0.02, 0.45))
draw_circle(p, 8.0, Color("#b17b24"))
draw_circle(p - Vector2(2, 2), 4.5, BRASS_LIGHT)
draw_line(p - Vector2(3, 0), p + Vector2(3, 0), Color("#765018"), 1.5, true)
func _ready() -> void:
process_mode = Node.PROCESS_MODE_ALWAYS
visible = false
_build()
func _flat_style(color: Color, border: Color, width: int, radius: int) -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = color
style.border_color = border
style.set_border_width_all(width)
style.set_corner_radius_all(radius)
return style
func _wood_style() -> StyleBoxTexture:
var style := StyleBoxTexture.new()
style.texture = WOOD_TEXTURE
style.texture_margin_left = 35.0
style.texture_margin_right = 35.0
style.texture_margin_top = 35.0
style.texture_margin_bottom = 35.0
return style
func _build() -> void:
var dim := ColorRect.new()
dim.color = Color(0.045, 0.018, 0.012, 0.77)
dim.set_anchors_preset(Control.PRESET_FULL_RECT)
dim.mouse_filter = Control.MOUSE_FILTER_STOP
add_child(dim)
var center := CenterContainer.new()
center.set_anchors_preset(Control.PRESET_FULL_RECT)
add_child(center)
_card = PanelContainer.new()
_card.custom_minimum_size = Vector2(750, 550)
var frame := _flat_style(Color("#70411f"), Color("#edca69"), 6, 31)
frame.shadow_color = Color(0, 0, 0, 0.58)
frame.shadow_size = 22
frame.shadow_offset = Vector2(0, 9)
frame.content_margin_left = 10
frame.content_margin_right = 10
frame.content_margin_top = 10
frame.content_margin_bottom = 10
_card.add_theme_stylebox_override("panel", frame)
center.add_child(_card)
var wood := PanelContainer.new()
wood.add_theme_stylebox_override("panel", _wood_style())
_card.add_child(wood)
var studs := BrassStuds.new()
studs.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
wood.add_child(studs)
var margin := MarginContainer.new()
margin.add_theme_constant_override("margin_left", 50)
margin.add_theme_constant_override("margin_right", 50)
margin.add_theme_constant_override("margin_top", 28)
margin.add_theme_constant_override("margin_bottom", 32)
wood.add_child(margin)
var vb := VBoxContainer.new()
vb.add_theme_constant_override("separation", 12)
vb.alignment = BoxContainer.ALIGNMENT_CENTER
margin.add_child(vb)
var bunting := CircusTrim.new()
bunting.custom_minimum_size = Vector2(0, 34)
vb.add_child(bunting)
var title := Label.new()
title.text = "Scegli la modalità"
title.add_theme_font_override("font", DISPLAY_FONT)
title.add_theme_font_size_override("font_size", 45)
title.add_theme_color_override("font_color", Color("#6d3419"))
title.add_theme_color_override("font_outline_color", Color("#f5d985"))
title.add_theme_constant_override("outline_size", 3)
title.add_theme_color_override("font_shadow_color", Color(0.25, 0.09, 0.02, 0.3))
title.add_theme_constant_override("shadow_offset_x", 0)
title.add_theme_constant_override("shadow_offset_y", 3)
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
vb.add_child(title)
var sub := Label.new()
sub.text = "Come vuoi giocare?"
sub.add_theme_font_size_override("font_size", 18)
sub.add_theme_color_override("font_color", INK)
sub.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
vb.add_child(sub)
# Pulsanti modalità (comportamento radio).
var hb := HBoxContainer.new()
hb.add_theme_constant_override("separation", 18)
hb.alignment = BoxContainer.ALIGNMENT_CENTER
vb.add_child(hb)
target_btn = _make_mode_button("🎯 TARGET", "Raggiungi il punteggio stabilito")
infinite_btn = _make_mode_button("♾ INFINITA", "A vite, senza limite di punteggio")
target_btn.button_group = _group
infinite_btn.button_group = _group
_group.pressed.connect(_on_mode_changed)
hb.add_child(target_btn)
hb.add_child(infinite_btn)
# Checkbox Zen (solo per la modalità Target).
var zen_center := CenterContainer.new()
zen_center.custom_minimum_size = Vector2(0, 52)
vb.add_child(zen_center)
zen_cb = CheckButton.new()
zen_cb.text = " ZEN · senza countdown né decadimento"
zen_cb.custom_minimum_size = Vector2(420, 46)
zen_cb.add_theme_font_size_override("font_size", 17)
zen_cb.add_theme_color_override("font_color", INK)
zen_cb.add_theme_color_override("font_hover_color", Color("#67391d"))
zen_cb.add_theme_stylebox_override("normal", _flat_style(Color("#ead6a8"), Color("#a77835"), 2, 12))
zen_cb.add_theme_stylebox_override("hover", _flat_style(Color("#f2dfb2"), BRASS, 3, 12))
zen_cb.add_theme_stylebox_override("pressed", _flat_style(Color("#dfc58c"), Color("#966324"), 3, 12))
zen_cb.button_pressed = false
zen_cb.alignment = HORIZONTAL_ALIGNMENT_CENTER
zen_cb.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
zen_center.add_child(zen_cb)
var play_center := CenterContainer.new()
vb.add_child(play_center)
play_btn = Button.new()
play_btn.text = "◆ GIOCA ◆"
play_btn.custom_minimum_size = Vector2(380, 66)
play_btn.add_theme_font_override("font", DISPLAY_FONT)
play_btn.add_theme_font_size_override("font_size", 29)
play_btn.add_theme_color_override("font_color", Color("#fff1c7"))
play_btn.add_theme_color_override("font_hover_color", Color.WHITE)
play_btn.add_theme_color_override("font_pressed_color", Color("#f8dc91"))
play_btn.add_theme_stylebox_override("normal", _button_style(Color("#824720"), Color("#d9a947"), 5))
play_btn.add_theme_stylebox_override("hover", _button_style(Color("#98562a"), BRASS_LIGHT, 5))
play_btn.add_theme_stylebox_override("pressed", _button_style(Color("#653318"), Color("#b7832e"), 4))
play_btn.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
play_btn.pressed.connect(_on_play)
play_center.add_child(play_btn)
func _button_style(color: Color, border: Color, width: int) -> StyleBoxFlat:
var style := _flat_style(color, border, width, 14)
style.shadow_color = Color(0.14, 0.05, 0.02, 0.5)
style.shadow_size = 6
style.shadow_offset = Vector2(0, 4)
return style
func _make_mode_button(title_text: String, hint_text: String) -> Button:
var btn := Button.new()
btn.text = title_text + "\n" + hint_text
btn.custom_minimum_size = Vector2(305, 100)
btn.add_theme_font_override("font", DISPLAY_FONT)
btn.add_theme_font_size_override("font_size", 20)
btn.add_theme_color_override("font_color", INK)
btn.add_theme_color_override("font_hover_color", Color("#572b16"))
btn.add_theme_color_override("font_pressed_color", Color("#fff5d6"))
btn.add_theme_color_override("font_focus_color", Color("#fff5d6"))
btn.add_theme_constant_override("outline_size", 1)
btn.toggle_mode = true
btn.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
var normal := _flat_style(Color("#ead7ac"), Color("#9b6b30"), 3, 14)
normal.shadow_color = Color(0.18, 0.07, 0.02, 0.35)
normal.shadow_size = 5
normal.shadow_offset = Vector2(0, 3)
var hover := _flat_style(Color("#f3dfad"), BRASS_LIGHT, 4, 14)
hover.shadow_color = Color(0.72, 0.43, 0.08, 0.3)
hover.shadow_size = 8
var selected := _flat_style(Color("#a85b2c"), Color("#f4cf67"), 5, 14)
selected.shadow_color = Color(0.95, 0.65, 0.18, 0.42)
selected.shadow_size = 10
selected.shadow_offset = Vector2(0, 2)
btn.add_theme_stylebox_override("normal", normal)
btn.add_theme_stylebox_override("hover", hover)
btn.add_theme_stylebox_override("pressed", selected)
btn.add_theme_stylebox_override("hover_pressed", selected)
btn.add_theme_stylebox_override("focus", selected)
return btn
func show_menu() -> void:
# preseleziona dall'ultima scelta salvata
var mode: int = Settings.game_mode
if mode == 2:
infinite_btn.button_pressed = true
target_btn.button_pressed = false
else:
target_btn.button_pressed = true
infinite_btn.button_pressed = false
zen_cb.button_pressed = (mode == 1)
_on_mode_changed()
visible = true
get_tree().paused = true
_card.modulate.a = 0.0
_card.scale = Vector2(0.93, 0.93)
_card.pivot_offset = _card.size * 0.5
play_btn.modulate.a = 0.0
var tw := create_tween()
tw.set_pause_mode(Tween.TWEEN_PAUSE_PROCESS)
tw.set_parallel(true)
tw.tween_property(_card, "modulate:a", 1.0, 0.22)
tw.tween_property(_card, "scale", Vector2.ONE, 0.38).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
tw.tween_property(play_btn, "modulate:a", 1.0, 0.3).set_delay(0.24)
func _on_mode_changed(_btn: BaseButton = null) -> void:
# lo Zen è disponibile SOLO per la modalità Target
zen_cb.visible = target_btn.button_pressed
func hide_menu() -> void:
visible = false
get_tree().paused = false
func _on_play() -> void:
# applica la scelta e salva (per ricordarla al prossimo avvio)
if infinite_btn.button_pressed:
Settings.game_mode = 2
elif zen_cb.button_pressed:
Settings.game_mode = 1
else:
Settings.game_mode = 0
Settings.save_settings()
hide_menu()
mode_chosen.emit()