class_name JugglingGymGame extends Control ## Prototipo P3B: trascina un attrezzo sul giocoliere corretto. signal return_requested const MOCKUP := preload("res://games/juggling_gym/assets/p3b/p3b_mockup.jpg") const BALLS := preload("res://games/juggling_gym/assets/p3b/3b_palline.png") const ROLA_BOLA := preload("res://games/juggling_gym/assets/p3b/3b_rola_bola.png") const CLUBS := preload("res://games/juggling_gym/assets/p3b/3b_clave.png") const PLATES := preload("res://games/juggling_gym/assets/p3b/3b_piatti_cinesi.png") const SPHERE := preload("res://games/juggling_gym/assets/p3b/3b_sfera.png") const ACTIVE_TOOLS := ["palline", "piatti", "sfera"] const TOOL_DATA := { "palline": {"texture": BALLS, "target": "left", "center": Vector2(0.18, 0.80), "size": Vector2(0.14, 0.18), "available": true}, "rola_bola": {"texture": ROLA_BOLA, "target": "center", "center": Vector2(0.34, 0.80), "size": Vector2(0.15, 0.16), "available": false}, "clave": {"texture": CLUBS, "target": "left", "center": Vector2(0.50, 0.80), "size": Vector2(0.15, 0.18), "available": false}, "piatti": {"texture": PLATES, "target": "right", "center": Vector2(0.66, 0.80), "size": Vector2(0.16, 0.18), "available": true}, "sfera": {"texture": SPHERE, "target": "center", "center": Vector2(0.82, 0.80), "size": Vector2(0.14, 0.18), "available": true}, } var score := 0 var score_label: Label var message_label: Label var tool_controls: Dictionary = {} var drop_zones: Dictionary = {} func _ready() -> void: set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) _build() func _build() -> void: 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_hotspot(self, MenuUI.BACK_BUTTON_CENTER, MenuUI.BACK_BUTTON_SIZE) back.tooltip_text = "Torna alla palestra" back.pressed.connect(func(): return_requested.emit()) back.z_index = 20 _add_drop_zone("left", Vector2(0.27, 0.41), Vector2(0.20, 0.42)) _add_drop_zone("center", Vector2(0.50, 0.39), Vector2(0.20, 0.45)) _add_drop_zone("right", Vector2(0.73, 0.41), Vector2(0.20, 0.44)) _build_tools() _build_hud() func _add_drop_zone(id: String, center: Vector2, size: Vector2) -> void: var zone := GymDropZone.new() zone.configure(id) zone.tool_dropped.connect(_on_tool_dropped) zone.z_index = 5 add_child(zone) MenuUI.set_normalized_rect(zone, center, size) drop_zones[id] = zone func _build_tools() -> void: for tool_id in TOOL_DATA: var config: Dictionary = TOOL_DATA[tool_id] var tool := GymTool.new() tool.configure(tool_id, config["texture"], config["available"]) tool.tooltip_text = "Trascina sul giocoliere corretto" if config["available"] else "Disponibile in una prossima versione" tool.z_index = 10 add_child(tool) MenuUI.set_normalized_rect(tool, config["center"], config["size"]) tool_controls[tool_id] = tool func _build_hud() -> void: var instruction := MenuUI.add_label(self, "Trascina ogni attrezzo sul giocoliere", Vector2(0.50, 0.10), Vector2(0.34, 0.08), 22) instruction.add_theme_stylebox_override("normal", MenuUI.note_style()) instruction.z_index = 20 score_label = MenuUI.add_label(self, "0 / %d" % ACTIVE_TOOLS.size(), Vector2(0.91, 0.12), Vector2(0.12, 0.08), 24) score_label.add_theme_stylebox_override("normal", MenuUI.note_style()) score_label.z_index = 20 message_label = MenuUI.add_label(self, "", Vector2(0.50, 0.91), Vector2(0.28, 0.07), 22) message_label.add_theme_stylebox_override("normal", MenuUI.note_style()) message_label.modulate.a = 0.0 message_label.z_index = 20 func _on_tool_dropped(zone_id: String, data: Dictionary) -> void: var tool_id := str(data.get("tool_id", "")) if not TOOL_DATA.has(tool_id): return var config: Dictionary = TOOL_DATA[tool_id] var correct: bool = str(config["target"]) == zone_id var zone: GymDropZone = drop_zones[zone_id] zone.flash(correct) if not correct: _show_message("Prova con un altro giocoliere", false) return if tool_id in tool_controls and tool_controls[tool_id].disabled: return tool_controls[tool_id].disabled = true score += 1 score_label.text = "%d / %d" % [score, ACTIVE_TOOLS.size()] _show_message("Ben fatto!" if score < ACTIVE_TOOLS.size() else "Palestra completata!", true) func _show_message(text: String, success: bool) -> void: message_label.text = text message_label.add_theme_color_override("font_color", Color("#2c6e3f") if success else Color("#9b352b")) message_label.modulate.a = 1.0 var tween := create_tween() tween.tween_interval(1.25) tween.tween_property(message_label, "modulate:a", 0.0, 0.28)