extends Area2D ## Una singola pallina nella sua corsia. Partendo da destra, se lanciata ## scivola verso il bordo sinistro e poi torna alla posizione di partenza. ## Il rilevamento del tocco/click è gestito centralmente da main.gd tramite ## distanza: qui NON ci sono handler di input dedicati. signal returned # emesso quando la pallina torna a casa var color_name := "" var ball_color := Color.WHITE var radius := 40.0 var home_pos := Vector2.ZERO var left_pos := Vector2.ZERO var in_motion := false var roll_angle := 0.0 # rotazione della biglia durante il rotolamento var _tween: Tween func _draw() -> void: # ombra a terra draw_circle(Vector2(0, 6), radius, Color(0, 0, 0, 0.25)) # corpo base draw_circle(Vector2.ZERO, radius, ball_color) # ombreggiatura inferiore-destra (profondità 3D) draw_circle(Vector2(radius * 0.18, radius * 0.22), radius * 0.92, Color(0, 0, 0, 0.16)) # luce superiore-sinistra draw_circle(Vector2(-radius * 0.18, -radius * 0.22), radius * 0.92, Color(1, 1, 1, 0.2)) # bordo nero spesso (stile china) draw_arc(Vector2.ZERO, radius, 0.0, TAU, 48, Color(0.1, 0.1, 0.1, 0.9), 4.0) # riflesso speculare draw_circle(Vector2(-radius * 0.3, -radius * 0.34), radius * 0.16, Color(1, 1, 1, 0.85)) # segno che ruota mentre la biglia rotola var spot := Vector2(cos(roll_angle), sin(roll_angle)) * radius * 0.55 draw_circle(spot, radius * 0.12, Color(0, 0, 0, 0.28)) func setup(cn: String, c: Color, home: Vector2, left: Vector2, r: float) -> void: color_name = cn ball_color = c radius = r home_pos = home left_pos = left position = home var shape := CollisionShape2D.new() var cs := CircleShape2D.new() cs.radius = r * 1.35 # area di tocco ampliata (ma l'input è via distanza in main) shape.shape = cs add_child(shape) queue_redraw() func is_home() -> bool: return not in_motion func reset() -> void: if _tween and _tween.is_valid(): _tween.kill() in_motion = false position = home_pos ## Lancia la pallina verso sinistra e la fa tornare a casa. `mt` è il tempo ## totale (andata + ritorno) in secondi. func launch(mt: float) -> void: in_motion = true if _tween and _tween.is_valid(): _tween.kill() var half := maxf(mt * 0.5, 0.01) # rotazione proporzionale alla distanza percorsa (rotolamento) var dist := home_pos.x - left_pos.x var total_angle := dist / radius _tween = create_tween() _tween.tween_property(self, "position", left_pos, half) \ .set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN_OUT) _tween.parallel().tween_property(self, "roll_angle", total_angle, half) \ .set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN_OUT) _tween.tween_property(self, "position", home_pos, half) \ .set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN_OUT) _tween.parallel().tween_property(self, "roll_angle", 0.0, half) \ .set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN_OUT) _tween.finished.connect(_on_motion_done) func _on_motion_done() -> void: in_motion = false returned.emit()