class_name ThrownBall extends Node3D #balle lancee : suit un arc entre deux points, puis emet "landed" et disparait. #autonome (pas lie a l'etat du joueur) : continue meme si le joueur change d'etat avant l'atterrissage. signal landed(position : Vector3) const SPIN_SPEED : float = 12.0 var _start : Vector3 var _end : Vector3 var _arc_height : float = 1.5 var _duration : float = 0.5 var _elapsed : float = 0.0 static func launch(parent : Node, from : Vector3, to : Vector3, duration : float, arc_height : float, visual_scene : PackedScene = null) -> ThrownBall: var ball := ThrownBall.new() ball._start = from ball._end = to ball._duration = maxf(duration, 0.05) ball._arc_height = arc_height parent.add_child(ball) ball.global_position = from ball._build_visual(visual_scene) return ball func _build_visual(visual_scene : PackedScene) -> void: if visual_scene: var visual : Node = visual_scene.instantiate() add_child(visual) return #balle par defaut (sphere rouge) en attendant ton modele var mesh_instance := MeshInstance3D.new() var sphere := SphereMesh.new() sphere.radius = 0.12 sphere.height = 0.24 mesh_instance.mesh = sphere var mat := StandardMaterial3D.new() mat.albedo_color = Color(0.9, 0.15, 0.15) mesh_instance.material_override = mat add_child(mesh_instance) func _process(delta : float) -> void: _elapsed += delta var t : float = clampf(_elapsed / _duration, 0.0, 1.0) global_position = _start.lerp(_end, t) + Vector3.UP * _arc_height * 4.0 * t * (1.0 - t) rotate_x(SPIN_SPEED * delta) if t >= 1.0: set_process(false) global_position = _end landed.emit(_end) queue_free()