Files
autgame/menus/scripts/screens/p1_home_screen.gd
T

246 lines
9.3 KiB
GDScript

class_name P1HomeScreen
extends Control
## P1: home con i due tendoni/percorsi.
signal juggle_requested(focal: Control)
signal gym_requested(focal: Control)
signal exit_requested
signal sign_drop_started
signal sign_landed
signal sign_bounced
const HOME_BG := preload("res://menus/assets/common/1_sfondo.png")
const CLOUDS := preload("res://menus/assets/common/1_nuvole.png")
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_PANEL := preload("res://menus/assets/p1/upendi_circus_sign_panel.png")
const CIRCUS_SIGN_ROPES := preload("res://menus/assets/p1/upendi_circus_sign_ropes.png")
const CURTAIN_FRAMES := [
preload("res://menus/assets/p1/curtain_anim/curtain_00.png"),
preload("res://menus/assets/p1/curtain_anim/curtain_01.png"),
preload("res://menus/assets/p1/curtain_anim/curtain_02.png"),
preload("res://menus/assets/p1/curtain_anim/curtain_03.png"),
preload("res://menus/assets/p1/curtain_anim/curtain_04.png"),
preload("res://menus/assets/p1/curtain_anim/curtain_05.png"),
preload("res://menus/assets/p1/curtain_anim/curtain_06.png"),
]
const GARLAND_FRAMES := [
preload("res://menus/assets/p1/garland_anim/lights_00.png"),
preload("res://menus/assets/p1/garland_anim/lights_01.png"),
preload("res://menus/assets/p1/garland_anim/lights_02.png"),
preload("res://menus/assets/p1/garland_anim/lights_03.png"),
preload("res://menus/assets/p1/garland_anim/lights_04.png"),
preload("res://menus/assets/p1/garland_anim/lights_05.png"),
]
func _ready() -> void:
set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
_build()
func _build() -> void:
MenuUI.add_full_texture(self, HOME_BG)
MenuUI.add_full_texture(self, CLOUDS, MenuUI.ambient_material(1.0, 0.16))
_add_sign()
# Solo il tendone blu di riferimento attiva lo shader delle lucine in hover.
var blue := _add_tent_button(BLUE_TENT, Vector2(0.29, 0.46), true)
blue.pressed.connect(func(): juggle_requested.emit(blue))
var red := _add_tent_button(RED_TENT, Vector2(0.71, 0.46), false)
red.pressed.connect(func(): gym_requested.emit(red))
_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, MenuUI.BACK_BUTTON_CENTER, MenuUI.BACK_BUTTON_SIZE)
exit_button.pressed.connect(func(): exit_requested.emit())
func _add_tent_button(texture: Texture2D, center: Vector2, has_lights := false) -> TextureButton:
var button := MenuUI.add_image_button(self, texture, center, Vector2(0.36, 0.59))
var mat := MenuUI.tent_material(0.0) if has_lights else MenuUI.tent_star_material()
button.material = mat
button.tooltip_text = "Apri questo percorso"
# Glow stella su entrambi i tendoni al passaggio del mouse
button.mouse_entered.connect(func():
mat.set_shader_parameter("hover_strength", 1.0)
if has_lights:
mat.set_shader_parameter("garland_strength", 1.0)
)
button.mouse_exited.connect(func():
mat.set_shader_parameter("hover_strength", 0.0)
if has_lights:
mat.set_shader_parameter("garland_strength", 0.0)
)
# Animazione apertura sipario e lucine in hover
if has_lights:
_setup_hover_curtain_and_garland(button, center)
return button
func _setup_hover_curtain_and_garland(parent_button: TextureButton, center: Vector2) -> void:
# Sipario: parte chiuso (frame 0). All'hover-in si apre (0 -> 6).
# All'hover-out si richiude al contrario (6 -> 0).
var curtain := TextureRect.new()
curtain.name = "Curtain"
curtain.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
curtain.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
curtain.mouse_filter = Control.MOUSE_FILTER_IGNORE
curtain.texture = CURTAIN_FRAMES[0]
add_child(curtain)
MenuUI.set_normalized_rect(curtain, center, Vector2(0.36, 0.59))
var curtain_idx := [0]
var curtain_dir := [0] # 0 = fermo, 1 = apre, -1 = chiude
var curtain_timer := Timer.new()
curtain_timer.wait_time = 1.0 / 12.5
curtain_timer.process_mode = Node.PROCESS_MODE_ALWAYS
curtain_timer.timeout.connect(func():
if curtain_dir[0] == 1:
if curtain_idx[0] < CURTAIN_FRAMES.size() - 1:
curtain_idx[0] += 1
curtain.texture = CURTAIN_FRAMES[curtain_idx[0]]
curtain.visible = true
else:
# Completamente aperto: frame 06 è vuoto/trasparente
curtain.texture = CURTAIN_FRAMES[curtain_idx[0]]
curtain_dir[0] = 0
curtain_timer.stop()
elif curtain_dir[0] == -1:
if curtain_idx[0] > 0:
curtain_idx[0] -= 1
curtain.texture = CURTAIN_FRAMES[curtain_idx[0]]
curtain.visible = true
else:
# Completamente chiuso: resta fermo su frame 00
curtain.texture = CURTAIN_FRAMES[0]
curtain_dir[0] = 0
curtain_timer.stop()
)
add_child(curtain_timer)
# Lucine a inseguimento
var lights := TextureRect.new()
lights.name = "HoverGarland"
lights.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
lights.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
lights.mouse_filter = Control.MOUSE_FILTER_IGNORE
lights.texture = GARLAND_FRAMES[0]
lights.visible = false
add_child(lights)
MenuUI.set_normalized_rect(lights, center, Vector2(0.36, 0.59))
var lights_idx := [0]
var lights_timer := Timer.new()
lights_timer.wait_time = 1.0 / 12.5
lights_timer.process_mode = Node.PROCESS_MODE_ALWAYS
lights_timer.timeout.connect(func():
lights_idx[0] = (lights_idx[0] + 1) % GARLAND_FRAMES.size()
if lights.visible:
lights.texture = GARLAND_FRAMES[lights_idx[0]]
)
add_child(lights_timer)
lights_timer.start()
parent_button.mouse_entered.connect(func():
# Avvia apertura sipario (hover in)
curtain_dir[0] = 1
curtain_timer.start()
# Avvia lucine
lights_idx[0] = 0
lights.texture = GARLAND_FRAMES[0]
lights.visible = true
)
parent_button.mouse_exited.connect(func():
# Avvia chiusura sipario al contrario (hover out)
curtain_dir[0] = -1
curtain_timer.start()
# Spegne lucine
lights.visible = false
)
func _add_bottom_bar() -> void:
# Il piedone entra dal basso come un unico blocco; la scritta resta
# invisibile fino a quando il rimbalzo della barra non è terminato.
var piedone := Control.new()
piedone.name = "Piedone"
piedone.mouse_filter = Control.MOUSE_FILTER_IGNORE
piedone.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
add_child(piedone)
var bar := ColorRect.new()
bar.color = Color("#f1dfbd")
bar.mouse_filter = Control.MOUSE_FILTER_IGNORE
piedone.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
piedone.add_child(rule)
MenuUI.set_normalized_rect(rule, Vector2(0.50, item[0]), Vector2(1.0, item[1] / 720.0))
var label := MenuUI.add_label(piedone, "Tocca un tendone e scopri il gioco!", Vector2(0.38, 0.89), Vector2(0.66, 0.10), 24)
label.modulate.a = 0.0
var viewport_height := get_viewport_rect().size.y
piedone.position.y = viewport_height * 0.29
var tween := create_tween()
# Il menu viene messo in pausa dalla shell: l'ingresso deve continuare comunque.
tween.set_pause_mode(Tween.TWEEN_PAUSE_PROCESS)
tween.tween_property(piedone, "position:y", viewport_height * 0.025, 0.85).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
tween.tween_property(piedone, "position:y", 0.0, 0.42).set_trans(Tween.TRANS_BOUNCE).set_ease(Tween.EASE_OUT)
tween.tween_property(label, "modulate:a", 1.0, 0.32).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT)
func _add_sign() -> void:
# Il pannello si muove, mentre le funi restano ancorate al bordo superiore.
# Separare i due livelli conserva la texture disegnata originale senza lasciare
# un vuoto quando il pannello supera verso il basso il punto di riposo.
var rig := Control.new()
rig.mouse_filter = Control.MOUSE_FILTER_IGNORE
add_child(rig)
MenuUI.set_normalized_rect(rig, Vector2(0.50, 0.17), Vector2(0.43, 0.34))
_add_sign_layer(rig, CIRCUS_SIGN_ROPES)
var panel := _add_sign_layer(rig, CIRCUS_SIGN_PANEL)
var final_y := panel.position.y
panel.position.y = final_y - panel.size.y * 1.15
var tween := create_tween()
# Il menu viene messo in pausa dalla shell: l'ingresso deve continuare comunque.
tween.set_pause_mode(Tween.TWEEN_PAUSE_PROCESS)
# Discesa rapida, atterraggio evidente e rimbalzo elastico.
call_deferred("_emit_sign_drop_started")
tween.tween_property(panel, "position:y", final_y + panel.size.y * 0.11, 1.10).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN)
# L'impatto è sincronizzato con la massima estensione, prima del ritorno elastico.
tween.tween_callback(func(): sign_landed.emit())
tween.tween_property(panel, "position:y", final_y, 0.50).set_trans(Tween.TRANS_BOUNCE).set_ease(Tween.EASE_OUT)
tween.tween_callback(func(): sign_bounced.emit())
func _add_sign_layer(parent: Control, texture: Texture2D) -> TextureRect:
var layer := TextureRect.new()
layer.texture = texture
layer.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
layer.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
layer.mouse_filter = Control.MOUSE_FILTER_IGNORE
parent.add_child(layer)
layer.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
return layer
func _emit_sign_drop_started() -> void:
if is_inside_tree():
sign_drop_started.emit()