commit 8e7da96bfcd52b230feaf40fbc6d4a42b80c5723
Author: TheThomaas <thethomaas@protonmail.ch>
Date: Sat Oct 17 18:55:14 2026 +0200
Make state machine more reusable
commit 37da7248b8c33ce95cff7ef9332c5ccf6e3cd418
Author: TheThomaas <thethomaas@protonmail.ch>
Date: Sat Oct 17 18:44:34 2026 +0200
Change aim state into flag
commit fbb3a84a12e2cabff9b36390da7483b8de7e9379
Author: TheThomaas <thethomaas@protonmail.ch>
Date: Sat Oct 17 18:33:08 2026 +0200
Replace fixed references with ui references
commit 913955b13e9980780ac88761845d9e1f165f0d0e
Author: TheThomaas <thethomaas@protonmail.ch>
Date: Fri Oct 16 13:32:21 2026 +0200
Update camera action handling
commit 4ce0ac13ffea473cf62c2fefd1571e9df1fbbcaa
Author: TheThomaas <thethomaas@protonmail.ch>
Date: Fri Oct 16 13:04:39 2026 +0200
Update mounting system
commit e410eca38760955b2866eecd6ac0281e2041e76d
Author: TheThomaas <thethomaas@protonmail.ch>
Date: Fri Oct 16 12:57:25 2026 +0200
Update aiming system
commit 4c788df485ccbff5f91fd51d9f480e495f11da5f
Author: TheThomaas <thethomaas@protonmail.ch>
Date: Thu Oct 15 21:50:26 2026 +0200
Centralize states names into constants
commit 6059479c87d749e986a48adb520ef33121104da5
Author: TheThomaas <thethomaas@protonmail.ch>
Date: Thu Oct 15 21:25:32 2026 +0200
Refator Crouch state into flag
commit 08faec70e770042d36eed6f173a63f3aac1f67c6
Author: TheThomaas <thethomaas@protonmail.ch>
Date: Wed Oct 14 10:19:35 2026 +0200
Update player input management and state machine
commit 11a0aecc58c50c5862a03b4fd0b55e8db024031f
Author: TheThomaas <thethomaas@protonmail.ch>
Date: Wed Oct 14 10:17:06 2026 +0200
Delete charizard.tres
commit 399eac2b6c64f242a1c2e12360d811127f87681c
Author: TheThomaas <thethomaas@protonmail.ch>
Date: Tue Oct 13 18:20:45 2026 +0200
Remove unused MountedState
commit 42a3668c52fe96a7509a74290a94fc5a8084b713
Author: TheThomaas <thethomaas@protonmail.ch>
Date: Tue Oct 13 18:18:08 2026 +0200
Group grounded states under common class
104 lines
5 KiB
GDScript
104 lines
5 KiB
GDScript
extends PlayerComponent
|
|
|
|
class_name ThrowResolver
|
|
|
|
#resout un lancer : trajectoire de la balle, point d'atterrissage, envoi du pokemon et demande de combat.
|
|
#ThrowState ne gere plus que le deroule (charge, windup, recuperation) et appelle throw_ball().
|
|
#composant a ajouter sous le PlayerCharacter (le nom du node est libre, voir PlayerComponent).
|
|
#il vit aussi longtemps que le joueur : l'atterrissage est gere ici meme si le joueur a change d'etat entre-temps.
|
|
|
|
@export_group("Ball")
|
|
@export var ball_scene : PackedScene #modele de la balle (optionnel : sphere rouge par defaut)
|
|
@export var hand_height : float = 1.4
|
|
@export var ball_speed : float = 18.0
|
|
@export var min_flight_time : float = 0.25
|
|
@export var max_flight_time : float = 1.2
|
|
@export var arc_height : float = 1.5
|
|
|
|
@export_group("Landing")
|
|
@export_flags_3d_physics var ground_mask : int = 1
|
|
@export var land_distance_from_target : float = 1.5 #la balle s'arrete devant une cible de combat
|
|
@export var free_hit_radius : float = 2.0 #lancer sans cible verrouillee : rayon autour du point d'atterrissage pour trouver une cible de combat
|
|
|
|
func register_with_player() -> void:
|
|
player.throw_resolver = self
|
|
|
|
#---------- lancer ----------
|
|
|
|
func throw_ball(pokemon : PokemonInstance, target : Variant, free_aim_point : Vector3) -> void:
|
|
#target : AimTarget verrouille au moment du relachement (ou null), free_aim_point : point vise s'il n'y en a pas
|
|
var from : Vector3 = player.global_position + Vector3.UP * hand_height
|
|
var to : Vector3 = _get_landing_point(target, free_aim_point)
|
|
var flight_time : float = clampf(from.distance_to(to) / ball_speed, min_flight_time, max_flight_time)
|
|
|
|
var scene : Node = get_tree().current_scene
|
|
var ball : ThrownBall = ThrownBall.launch(scene, from, to, flight_time, arc_height, ball_scene)
|
|
ball.landed.connect(_on_ball_landed.bind(pokemon, target, from))
|
|
|
|
#---------- point vise ----------
|
|
|
|
func compute_free_aim_point() -> Vector3:
|
|
#point vise au centre de l'ecran : premier obstacle, sinon fin de portee ramenee au sol
|
|
var cam : Camera3D = player.cam_holder.cam
|
|
var origin : Vector3 = cam.global_position
|
|
var far : Vector3 = origin - cam.global_basis.z * player.aim_targeting.throw_range
|
|
var query := PhysicsRayQueryParameters3D.create(origin, far, ground_mask, [player.get_rid()])
|
|
var hit : Dictionary = player.get_world_3d().direct_space_state.intersect_ray(query)
|
|
if hit.is_empty(): return _snap_to_ground(far)
|
|
return _snap_to_ground(hit["position"] + hit["normal"] * 0.5)
|
|
|
|
func _get_landing_point(target : Variant, free_aim_point : Vector3) -> Vector3:
|
|
if !is_instance_valid(target): return free_aim_point
|
|
|
|
var target_pos : Vector3 = target.global_position
|
|
if _starts_battle(target):
|
|
#la balle s'arrete devant la cible, du cote du joueur
|
|
var to_player : Vector3 = player.global_position - target_pos
|
|
to_player.y = 0.0
|
|
if to_player.length() > land_distance_from_target:
|
|
target_pos += to_player.normalized() * land_distance_from_target
|
|
return _snap_to_ground(target_pos)
|
|
|
|
func _snap_to_ground(point : Vector3) -> Vector3:
|
|
var query := PhysicsRayQueryParameters3D.create(point + Vector3.UP * 2.0, point + Vector3.DOWN * 6.0, ground_mask, [player.get_rid()])
|
|
var hit : Dictionary = player.get_world_3d().direct_space_state.intersect_ray(query)
|
|
return hit["position"] if !hit.is_empty() else point
|
|
|
|
#---------- atterrissage ----------
|
|
|
|
func _on_ball_landed(landing_pos : Vector3, pokemon : PokemonInstance, target : Variant, thrower_pos : Vector3) -> void:
|
|
var scene : Node = get_tree().current_scene if is_inside_tree() else null
|
|
if scene == null: return
|
|
|
|
#lancer sans cible verrouillee : si la balle atterrit pres d'une cible de combat, c'est elle qui est visee
|
|
if !is_instance_valid(target):
|
|
target = _find_battle_target_near(landing_pos)
|
|
|
|
var target_valid : bool = is_instance_valid(target)
|
|
#le pokemon regarde la cible, ou dans la direction du lancer s'il n'y en a pas
|
|
var look_pos : Vector3 = target.global_position if target_valid else landing_pos + (landing_pos - thrower_pos)
|
|
var sent : SentPokemon = SentPokemon.send(scene, pokemon, landing_pos, look_pos)
|
|
|
|
if target_valid and _starts_battle(target):
|
|
GameData.battle_requested.emit(sent, target)
|
|
elif target_valid:
|
|
#diagnostic : retire ce message quand tout fonctionne
|
|
push_warning("ThrowResolver : la cible '%s' ne lance pas de combat (starts_battle faux : Encounter vide, ou aim_target.gd pas remplace)." % target.name)
|
|
|
|
func _find_battle_target_near(point : Vector3) -> AimTarget:
|
|
#cible de combat active la plus proche du point d'atterrissage, dans free_hit_radius
|
|
var best : AimTarget = null
|
|
var best_dist : float = free_hit_radius
|
|
for node in get_tree().get_nodes_in_group(AimTargeting.TARGET_GROUP):
|
|
var t := node as AimTarget
|
|
if t == null or !t.enabled or !_starts_battle(t): continue
|
|
var dist : float = point.distance_to(t.global_position)
|
|
if dist <= best_dist:
|
|
best_dist = dist
|
|
best = t
|
|
return best
|
|
|
|
func _starts_battle(target : Object) -> bool:
|
|
#AimTarget doit avoir : @export var starts_battle : bool = false (get() renvoie null si la propriete n'existe pas)
|
|
return target.get("starts_battle") == true
|