feat: déclencher les rencontres depuis la perception réelle dans World (#26) #33

Merged
Reliodas merged 1 commit from feature/26-perception-world into develop 2026-06-20 10:39:39 +00:00
Owner

Closes #26

La couche Perception (portée + ligne de vue) existait et était testée isolément, mais World ne la consultait jamais : les rencontres ne démarraient qu'au contact (Player._try_move). Cette MR connecte la perception à World pour tenir la promesse du jalon — une détection hostile lance initiative et combat en place.

Changements

  • World.evaluate_perception() : pour chaque WorldEntity hostile, engage le combat (start_encounter) si Perception.should_engage(_grid, ent.cell, player.grid_pos, ent.data.sight_range_m, ent.is_hostile()). Renvoie vrai si une rencontre a démarré. Les entités neutres sont ignorées (déjà géré par is_hostile/should_engage).
  • Déclenchement à la fin du tween de déplacement du joueur (Player._try_move, position visuelle et grid_pos à nouveau cohérentes) et une fois après l'initialisation de la scène (call_deferred("evaluate_perception")), plutôt que dans une boucle _process permanente.
  • Garde conservée : start_encounter ne fait rien hors accepts_exploration_input() — aucun réengagement pendant une rencontre active.
  • Verrou de désengagement transitoire _disengaged (par identité d'entité, hors sauvegarde) : un hostile ayant fui ne relance pas immédiatement la rencontre par perception tant qu'il perçoit le héros ; le verrou tombe dès que la portée ou la ligne de vue est rompue, autorisant une nouvelle acquisition. Posé dans _persist_fleeing_enemy.
  • Le déclenchement au contact reste un filet de sécurité indépendant et fonctionne même quand une entité est verrouillée.

Critères d'acceptation

  • World évalue les entités hostiles pendant l'exploration avec leur sight_range_m ;
  • une cible visible et à portée déclenche la rencontre sans contact préalable ;
  • un mur ou une portée insuffisante empêche l'engagement ;
  • une entité neutre détectée ne déclenche pas de combat ;
  • le déclenchement ne se répète pas pendant une rencontre active ;
  • un test World couvre le déclenchement réel à distance, et non un appel manuel à start_encounter.

Tests

  • tests/unit/test_world_encounter.gd : test_perception_starts_encounter_without_contact (engagement à vue, non adjacent), test_perception_does_not_engage_through_wall (mur interposé), test_perception_ignores_engagement_during_combat, test_flee_then_no_immediate_reengage_then_break_then_reacquire (régression verrou de désengagement), test_contact_still_engages_locked_fleeing_enemy (filet de sécurité).
  • L'ignorance des entités neutres et le hors-portée restent couverts par tests/unit/test_perception.gd.
  • Suite GUT complète verte : 157 tests, 479 assertions.
Closes #26 La couche `Perception` (portée + ligne de vue) existait et était testée isolément, mais `World` ne la consultait jamais : les rencontres ne démarraient qu'au contact (`Player._try_move`). Cette MR connecte la perception à `World` pour tenir la promesse du jalon — une détection hostile lance initiative et combat **en place**. ## Changements - `World.evaluate_perception()` : pour chaque `WorldEntity` hostile, engage le combat (`start_encounter`) si `Perception.should_engage(_grid, ent.cell, player.grid_pos, ent.data.sight_range_m, ent.is_hostile())`. Renvoie vrai si une rencontre a démarré. Les entités neutres sont ignorées (déjà géré par `is_hostile`/`should_engage`). - Déclenchement **à la fin du tween de déplacement** du joueur (`Player._try_move`, position visuelle et `grid_pos` à nouveau cohérentes) et **une fois après l'initialisation** de la scène (`call_deferred("evaluate_perception")`), plutôt que dans une boucle `_process` permanente. - Garde conservée : `start_encounter` ne fait rien hors `accepts_exploration_input()` — aucun réengagement pendant une rencontre active. - Verrou de désengagement transitoire `_disengaged` (par identité d'entité, **hors sauvegarde**) : un hostile ayant fui ne relance pas immédiatement la rencontre par perception tant qu'il perçoit le héros ; le verrou tombe dès que la portée ou la ligne de vue est rompue, autorisant une nouvelle acquisition. Posé dans `_persist_fleeing_enemy`. - Le déclenchement au contact reste un **filet de sécurité** indépendant et fonctionne même quand une entité est verrouillée. ## Critères d'acceptation - [x] World évalue les entités hostiles pendant l'exploration avec leur `sight_range_m` ; - [x] une cible visible et à portée déclenche la rencontre sans contact préalable ; - [x] un mur ou une portée insuffisante empêche l'engagement ; - [x] une entité neutre détectée ne déclenche pas de combat ; - [x] le déclenchement ne se répète pas pendant une rencontre active ; - [x] un test World couvre le déclenchement réel à distance, et non un appel manuel à `start_encounter`. ## Tests - `tests/unit/test_world_encounter.gd` : `test_perception_starts_encounter_without_contact` (engagement à vue, non adjacent), `test_perception_does_not_engage_through_wall` (mur interposé), `test_perception_ignores_engagement_during_combat`, `test_flee_then_no_immediate_reengage_then_break_then_reacquire` (régression verrou de désengagement), `test_contact_still_engages_locked_fleeing_enemy` (filet de sécurité). - L'ignorance des entités neutres et le hors-portée restent couverts par `tests/unit/test_perception.gd`. - Suite GUT complète verte : **157 tests, 479 assertions**.
feat: déclencher les rencontres depuis la perception réelle dans World (#26)
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful
ci/woodpecker/pull_request_closed/woodpecker Pipeline was successful
6bc6b28957
World ne consultait jamais la couche Perception : la rencontre ne démarrait
qu'au contact. Nouvelle méthode World.evaluate_perception() qui engage tout
hostile percevant le héros (portée + ligne de vue), appelée à la fin du tween
de déplacement du joueur et une fois après l'initialisation (appel différé,
pas de boucle _process). Verrou de désengagement transitoire (_disengaged,
hors sauvegarde) contre la boucle de réengagement après une fuite : levé dès
que la perception est rompue. Le contact reste un filet de sécurité.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reliodas merged commit 548eab82ff into develop 2026-06-20 10:39:39 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: jeux/beaulieu-sur-brume#33
No description provided.