Release v0.2: refine menus and JuggleBoard
This commit is contained in:
@@ -4,6 +4,7 @@ extends RefCounted
|
||||
|
||||
const DISPLAY_FONT := preload("res://shared/assets/fonts/NotoSerifDisplay-CondensedExtraBold.ttf")
|
||||
const MENU_SHADER := preload("res://menus/assets/shaders/ambient_drift.gdshader")
|
||||
const TENT_STAR_SHADER := preload("res://menus/assets/shaders/tent_star_glow.gdshader")
|
||||
|
||||
|
||||
static func set_normalized_rect(control: Control, center: Vector2, normalized_size: Vector2) -> void:
|
||||
@@ -33,6 +34,12 @@ static func ambient_material(strength: float, speed: float) -> ShaderMaterial:
|
||||
return material
|
||||
|
||||
|
||||
static func tent_star_material() -> ShaderMaterial:
|
||||
var material := ShaderMaterial.new()
|
||||
material.shader = TENT_STAR_SHADER
|
||||
return material
|
||||
|
||||
|
||||
static func add_image(parent: Control, texture: Texture2D, center: Vector2, normalized_size: Vector2, material: Material = null) -> TextureRect:
|
||||
var image := TextureRect.new()
|
||||
image.texture = texture
|
||||
|
||||
@@ -39,7 +39,8 @@ func _build_shell() -> void:
|
||||
fade.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
fade.color = Color("#1d1720")
|
||||
fade.modulate.a = 0.0
|
||||
fade.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
# Il fade è trasparente a riposo: non deve intercettare click o touch dei menu.
|
||||
fade.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
root.add_child(fade)
|
||||
|
||||
menu_audio = MenuAudio.new()
|
||||
@@ -74,6 +75,8 @@ func _navigate(scene: PackedScene, capture_label: String, focal: Control = null)
|
||||
if _transitioning:
|
||||
return
|
||||
_transitioning = true
|
||||
# Durante la transizione impedisce input duplicati; torna IGNORE al termine.
|
||||
fade.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
menu_audio.play_tone(660.0)
|
||||
var tween := create_tween()
|
||||
tween.set_pause_mode(Tween.TWEEN_PAUSE_PROCESS)
|
||||
@@ -85,6 +88,7 @@ func _navigate(scene: PackedScene, capture_label: String, focal: Control = null)
|
||||
tween.tween_property(fade, "modulate:a", 0.0, 0.30)
|
||||
tween.tween_callback(func():
|
||||
_transitioning = false
|
||||
fade.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_capture_after_frame(capture_label)
|
||||
)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ const BLUE_TENT := preload("res://menus/assets/p1/1_tendone_1.png")
|
||||
const RED_TENT := preload("res://menus/assets/p1/1_tendone_2.png")
|
||||
const BACK_BUTTON := preload("res://menus/assets/common/pulsante_indietro.png")
|
||||
const SETTINGS_BUTTON := preload("res://menus/assets/common/pulsante_rotellina.png")
|
||||
const CIRCUS_SIGN := preload("res://menus/assets/p1/upendi_circus_sign.svg")
|
||||
const CIRCUS_SIGN := preload("res://menus/assets/p1/upendi_circus_sign_mockup.png")
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -25,37 +25,46 @@ func _build() -> void:
|
||||
MenuUI.add_full_texture(self, CLOUDS, MenuUI.ambient_material(1.0, 0.16))
|
||||
_add_sign()
|
||||
|
||||
var blue := MenuUI.add_image_button(self, BLUE_TENT, Vector2(0.29, 0.64), Vector2(0.36, 0.59))
|
||||
blue.material = MenuUI.ambient_material(0.65, 0.20)
|
||||
var blue := _add_tent_button(BLUE_TENT, Vector2(0.29, 0.46))
|
||||
blue.pressed.connect(func(): juggle_requested.emit(blue))
|
||||
var red := MenuUI.add_image_button(self, RED_TENT, Vector2(0.71, 0.64), Vector2(0.36, 0.59))
|
||||
red.material = MenuUI.ambient_material(0.65, 0.20)
|
||||
var red := _add_tent_button(RED_TENT, Vector2(0.71, 0.46))
|
||||
red.pressed.connect(func(): gym_requested.emit(red))
|
||||
|
||||
_add_star(Vector2(0.28, 0.18), "1", func(): juggle_requested.emit(blue))
|
||||
_add_star(Vector2(0.72, 0.18), "2", func(): gym_requested.emit(red))
|
||||
MenuUI.add_label(self, "Tocca un tendone e scopri il gioco!", Vector2(0.50, 0.91), Vector2(0.55, 0.07), 24)
|
||||
_add_bottom_bar()
|
||||
MenuUI.add_image(self, SETTINGS_BUTTON, Vector2(0.91, 0.13), Vector2(0.09, 0.14))
|
||||
if not OS.has_feature("web"):
|
||||
var exit_button := MenuUI.add_image_button(self, BACK_BUTTON, Vector2(0.075, 0.13), Vector2(0.09, 0.14))
|
||||
exit_button.pressed.connect(func(): exit_requested.emit())
|
||||
|
||||
|
||||
func _add_tent_button(texture: Texture2D, center: Vector2) -> TextureButton:
|
||||
var button := MenuUI.add_image_button(self, texture, center, Vector2(0.36, 0.59))
|
||||
var star_material := MenuUI.tent_star_material()
|
||||
button.material = star_material
|
||||
button.tooltip_text = "Apri questo percorso"
|
||||
# L'hover non altera più geometria e hitbox del tendone: mette in risalto
|
||||
# esclusivamente la stella, tramite il parametro dello shader.
|
||||
button.mouse_entered.connect(func(): star_material.set_shader_parameter("hover_strength", 1.0))
|
||||
button.mouse_exited.connect(func(): star_material.set_shader_parameter("hover_strength", 0.0))
|
||||
return button
|
||||
|
||||
|
||||
func _add_bottom_bar() -> void:
|
||||
var bar := ColorRect.new()
|
||||
bar.color = Color("#f1dfbd")
|
||||
bar.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
add_child(bar)
|
||||
MenuUI.set_normalized_rect(bar, Vector2(0.50, 0.885), Vector2(1.0, 0.23))
|
||||
|
||||
for item in [[0.774, 3.0], [0.787, 2.0]]:
|
||||
var rule := ColorRect.new()
|
||||
rule.color = Color("#28201c")
|
||||
rule.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
add_child(rule)
|
||||
MenuUI.set_normalized_rect(rule, Vector2(0.50, item[0]), Vector2(1.0, item[1] / 720.0))
|
||||
|
||||
MenuUI.add_label(self, "Tocca un tendone e scopri il gioco!", Vector2(0.38, 0.89), Vector2(0.66, 0.10), 24)
|
||||
|
||||
|
||||
func _add_sign() -> void:
|
||||
MenuUI.add_image(self, CIRCUS_SIGN, Vector2(0.50, 0.14), Vector2(0.33, 0.22))
|
||||
var brand := MenuUI.add_label(self, "Upendi", Vector2(0.50, 0.125), Vector2(0.25, 0.08), 42)
|
||||
brand.add_theme_color_override("font_color", Color("#f8f0d3"))
|
||||
brand.add_theme_color_override("font_outline_color", Color("#283f49"))
|
||||
brand.add_theme_constant_override("outline_size", 3)
|
||||
var circus := MenuUI.add_label(self, "C I R C U S", Vector2(0.50, 0.175), Vector2(0.20, 0.05), 17)
|
||||
circus.add_theme_color_override("font_color", Color("#f8f0d3"))
|
||||
circus.add_theme_color_override("font_outline_color", Color("#283f49"))
|
||||
|
||||
|
||||
func _add_star(center: Vector2, number: String, action: Callable) -> void:
|
||||
var label := MenuUI.add_label(self, "★\n" + number, center, Vector2(0.08, 0.13), 27)
|
||||
label.add_theme_color_override("font_color", Color("#f6d45f"))
|
||||
label.add_theme_color_override("font_outline_color", Color("#4e3423"))
|
||||
label.add_theme_constant_override("outline_size", 5)
|
||||
var hotspot := MenuUI.add_hotspot(self, center, Vector2(0.10, 0.16))
|
||||
hotspot.pressed.connect(func(): action.call())
|
||||
MenuUI.add_image(self, CIRCUS_SIGN, Vector2(0.50, 0.17), Vector2(0.43, 0.34))
|
||||
|
||||
@@ -1,26 +1,17 @@
|
||||
class_name P2AJuggleMenuScreen
|
||||
extends Control
|
||||
## P2a: configurazione visuale del percorso JuggleBoard.
|
||||
## Il numero palline è deliberatamente locale al menu e non modifica il gioco.
|
||||
## P2a: schermata JuggleBoard composta dal mockup approvato.
|
||||
## I controlli trasparenti mantengono input mouse e touch senza alterare la grafica.
|
||||
|
||||
signal back_requested
|
||||
signal mode_requested
|
||||
signal feedback_requested(frequency: float)
|
||||
|
||||
const BG := preload("res://menus/assets/p2a/2a_sfondo.png")
|
||||
const CLOUDS := preload("res://menus/assets/common/1_nuvole.png")
|
||||
const TENT := preload("res://menus/assets/p2a/2a_tendone.png")
|
||||
const TITLE := preload("res://menus/assets/p2a/2a_titolo.png")
|
||||
const LEFT_ARROW := preload("res://menus/assets/common/freccina_sx.png")
|
||||
const RIGHT_ARROW := preload("res://menus/assets/common/freccina_dx.png")
|
||||
const BACK_BUTTON := preload("res://menus/assets/common/pulsante_indietro.png")
|
||||
const SETTINGS_BUTTON := preload("res://menus/assets/common/pulsante_rotellina.png")
|
||||
const PLAY_BUTTON := preload("res://menus/assets/common/pulsante_gioca.png")
|
||||
const MOCKUP := preload("res://menus/assets/p2a/p2a_menu_mockup.jpg")
|
||||
|
||||
var balls_count := 5
|
||||
var count_patch: ColorRect
|
||||
var count_label: Label
|
||||
var left_button: TextureButton
|
||||
var right_button: TextureButton
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -29,42 +20,52 @@ func _ready() -> void:
|
||||
|
||||
|
||||
func _build() -> void:
|
||||
MenuUI.add_full_texture(self, BG)
|
||||
MenuUI.add_full_texture(self, CLOUDS, MenuUI.ambient_material(1.0, 0.16))
|
||||
MenuUI.add_image(self, TENT, Vector2(0.28, 0.59), Vector2(0.56, 0.78), MenuUI.ambient_material(0.60, 0.20))
|
||||
MenuUI.add_image(self, TITLE, Vector2(0.68, 0.22), Vector2(0.34, 0.28))
|
||||
# Il mockup è la composizione grafica di riferimento: STRETCH_SCALE conserva
|
||||
# posizione reciproca e proporzioni di tendone, titolo, barra e controlli.
|
||||
var artwork := TextureRect.new()
|
||||
artwork.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
artwork.texture = MOCKUP
|
||||
artwork.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
artwork.stretch_mode = TextureRect.STRETCH_SCALE
|
||||
artwork.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
add_child(artwork)
|
||||
|
||||
var back := MenuUI.add_image_button(self, BACK_BUTTON, Vector2(0.075, 0.13), Vector2(0.09, 0.14))
|
||||
back.pressed.connect(func(): back_requested.emit())
|
||||
MenuUI.add_image(self, SETTINGS_BUTTON, Vector2(0.91, 0.13), Vector2(0.09, 0.14))
|
||||
_build_selector()
|
||||
|
||||
var play := MenuUI.add_image_button(self, PLAY_BUTTON, Vector2(0.79, 0.83), Vector2(0.30, 0.115))
|
||||
play.pressed.connect(func():
|
||||
feedback_requested.emit(784.0)
|
||||
mode_requested.emit()
|
||||
)
|
||||
_add_hotspot(Vector2(0.12, 0.14), Vector2(0.10, 0.14), func(): back_requested.emit())
|
||||
_add_hotspot(Vector2(0.775, 0.64), Vector2(0.07, 0.10), func(): _change_balls(-1))
|
||||
_add_hotspot(Vector2(0.895, 0.64), Vector2(0.07, 0.10), func(): _change_balls(1))
|
||||
_add_hotspot(Vector2(0.79, 0.88), Vector2(0.30, 0.14), _start_game)
|
||||
_build_dynamic_count()
|
||||
|
||||
|
||||
func _build_selector() -> void:
|
||||
MenuUI.add_label(self, "N° palline", Vector2(0.68, 0.57), Vector2(0.23, 0.06), 22)
|
||||
left_button = MenuUI.add_image_button(self, LEFT_ARROW, Vector2(0.68, 0.67), Vector2(0.055, 0.075))
|
||||
left_button.pressed.connect(func(): _change_balls(-1))
|
||||
right_button = MenuUI.add_image_button(self, RIGHT_ARROW, Vector2(0.87, 0.67), Vector2(0.055, 0.075))
|
||||
right_button.pressed.connect(func(): _change_balls(1))
|
||||
count_label = MenuUI.add_label(self, str(balls_count), Vector2(0.775, 0.67), Vector2(0.10, 0.09), 32)
|
||||
_update_arrow_state()
|
||||
func _add_hotspot(center: Vector2, normalized_size: Vector2, action: Callable) -> void:
|
||||
var hotspot := MenuUI.add_hotspot(self, center, normalized_size)
|
||||
hotspot.tooltip_text = ""
|
||||
hotspot.pressed.connect(func(): action.call())
|
||||
|
||||
|
||||
func _build_dynamic_count() -> void:
|
||||
count_patch = ColorRect.new()
|
||||
count_patch.color = Color(1.0, 1.0, 1.0, 0.96)
|
||||
count_patch.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
count_patch.visible = false
|
||||
add_child(count_patch)
|
||||
MenuUI.set_normalized_rect(count_patch, Vector2(0.835, 0.64), Vector2(0.055, 0.09))
|
||||
|
||||
count_label = MenuUI.add_label(self, str(balls_count), Vector2(0.835, 0.64), Vector2(0.055, 0.09), 32)
|
||||
count_label.visible = false
|
||||
|
||||
|
||||
func _change_balls(delta: int) -> void:
|
||||
balls_count = clampi(balls_count + delta, 1, 5)
|
||||
count_patch.visible = true
|
||||
count_label.visible = true
|
||||
count_label.text = str(balls_count)
|
||||
feedback_requested.emit(440.0 + 45.0 * balls_count)
|
||||
_update_arrow_state()
|
||||
|
||||
|
||||
func _update_arrow_state() -> void:
|
||||
left_button.disabled = balls_count <= 1
|
||||
right_button.disabled = balls_count >= 5
|
||||
left_button.modulate.a = 0.35 if left_button.disabled else 1.0
|
||||
right_button.modulate.a = 0.35 if right_button.disabled else 1.0
|
||||
func _start_game() -> void:
|
||||
# Senza selettore: il menu P2A apre sempre la partita Target standard.
|
||||
Settings.game_mode = 0
|
||||
Settings.save_settings()
|
||||
feedback_requested.emit(784.0)
|
||||
mode_requested.emit()
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
class_name P3AGymMenuScreen
|
||||
extends Control
|
||||
## P3a: anteprima della futura Palestra di Giocoleria.
|
||||
## P3A segue la stessa composizione mockup + hotspot trasparenti di P2A.
|
||||
|
||||
signal back_requested
|
||||
signal feedback_requested(frequency: float)
|
||||
|
||||
const BG := preload("res://menus/assets/common/1_sfondo.png")
|
||||
const CLOUDS := preload("res://menus/assets/common/1_nuvole.png")
|
||||
const TENT := preload("res://menus/assets/p3a/3a_tendone.png")
|
||||
const TITLE := preload("res://menus/assets/p3a/3a_titolo.png")
|
||||
const BACK_BUTTON := preload("res://menus/assets/common/pulsante_indietro.png")
|
||||
const SETTINGS_BUTTON := preload("res://menus/assets/common/pulsante_rotellina.png")
|
||||
const PLAY_BUTTON := preload("res://menus/assets/common/pulsante_gioca.png")
|
||||
const MOCKUP := preload("res://menus/assets/p3a/p3a_menu_mockup.jpg")
|
||||
|
||||
var players_count := 3
|
||||
var count_patch: ColorRect
|
||||
var count_label: Label
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -20,19 +18,45 @@ func _ready() -> void:
|
||||
|
||||
|
||||
func _build() -> void:
|
||||
MenuUI.add_full_texture(self, BG)
|
||||
MenuUI.add_full_texture(self, CLOUDS, MenuUI.ambient_material(1.0, 0.16))
|
||||
MenuUI.add_image(self, TENT, Vector2(0.28, 0.59), Vector2(0.56, 0.78), MenuUI.ambient_material(0.60, 0.20))
|
||||
MenuUI.add_image(self, TITLE, Vector2(0.68, 0.22), Vector2(0.34, 0.34))
|
||||
var artwork := TextureRect.new()
|
||||
artwork.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
artwork.texture = MOCKUP
|
||||
artwork.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
artwork.stretch_mode = TextureRect.STRETCH_SCALE
|
||||
artwork.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
add_child(artwork)
|
||||
|
||||
var back := MenuUI.add_image_button(self, BACK_BUTTON, Vector2(0.075, 0.13), Vector2(0.09, 0.14))
|
||||
back.pressed.connect(func(): back_requested.emit())
|
||||
MenuUI.add_image(self, SETTINGS_BUTTON, Vector2(0.91, 0.13), Vector2(0.09, 0.14))
|
||||
MenuUI.add_label(self, "N° giocolieri", Vector2(0.77, 0.57), Vector2(0.28, 0.06), 22)
|
||||
MenuUI.add_label(self, "3", Vector2(0.88, 0.57), Vector2(0.08, 0.08), 30)
|
||||
_add_hotspot(Vector2(0.12, 0.14), Vector2(0.10, 0.14), func(): back_requested.emit())
|
||||
_add_hotspot(Vector2(0.775, 0.64), Vector2(0.07, 0.10), func(): _change_players(-1))
|
||||
_add_hotspot(Vector2(0.895, 0.64), Vector2(0.07, 0.10), func(): _change_players(1))
|
||||
_add_hotspot(Vector2(0.79, 0.88), Vector2(0.30, 0.14), _show_coming_soon)
|
||||
_build_dynamic_count()
|
||||
|
||||
var play := MenuUI.add_image_button(self, PLAY_BUTTON, Vector2(0.79, 0.83), Vector2(0.30, 0.115))
|
||||
play.pressed.connect(_show_coming_soon)
|
||||
|
||||
func _add_hotspot(center: Vector2, normalized_size: Vector2, action: Callable) -> void:
|
||||
var hotspot := MenuUI.add_hotspot(self, center, normalized_size)
|
||||
hotspot.tooltip_text = ""
|
||||
hotspot.pressed.connect(func(): action.call())
|
||||
|
||||
|
||||
func _build_dynamic_count() -> void:
|
||||
count_patch = ColorRect.new()
|
||||
count_patch.color = Color(1.0, 1.0, 1.0, 0.96)
|
||||
count_patch.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
count_patch.visible = false
|
||||
add_child(count_patch)
|
||||
MenuUI.set_normalized_rect(count_patch, Vector2(0.835, 0.64), Vector2(0.055, 0.09))
|
||||
|
||||
count_label = MenuUI.add_label(self, str(players_count), Vector2(0.835, 0.64), Vector2(0.055, 0.09), 32)
|
||||
count_label.visible = false
|
||||
|
||||
|
||||
func _change_players(delta: int) -> void:
|
||||
players_count = clampi(players_count + delta, 1, 5)
|
||||
count_patch.visible = true
|
||||
count_label.visible = true
|
||||
count_label.text = str(players_count)
|
||||
feedback_requested.emit(440.0 + 45.0 * players_count)
|
||||
|
||||
|
||||
func _show_coming_soon() -> void:
|
||||
|
||||
Reference in New Issue
Block a user