Fix "à la collision" qui ne se déclenchait jamais
Build and deploy / test-python (push) Successful in 6m27s
Build and deploy / test-js (push) Successful in 54s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped

Cause réelle : un objet portant une règle de collision est presque
toujours AUSSI un obstacle solide (collision activée par défaut, voir
forgeWouldCollide, personnage-controller.js) — le déplacement du joueur
est donc bloqué PILE au contact, sans jamais laisser les deux boîtes se
chevaucher réellement. Le déclencheur "collision" testait un
chevauchement STRICT (forgeShapesOverlap nu), qui n'était donc jamais
atteint : la règle ne se déclenchait jamais en jeu réel, malgré un
contact visible à l'écran.

Le déclencheur teste maintenant la boîte de l'objet élargie d'une
petite marge (3px) — assez pour détecter un simple contact — SANS
toucher au blocage physique du déplacement (resté strict, inchangé).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-09-03 12:33:59 +02:00
co-authored by Claude Sonnet 5
parent 5e17e42dfa
commit 3a67ba622b
2 changed files with 42 additions and 8 deletions
@@ -49,7 +49,7 @@ function rect(left, top, width, height) {
return { left, top, width, height, right: left + width, bottom: top + height, shape: 'rectangle' }; return { left, top, width, height, right: left + width, bottom: top + height, shape: 'rectangle' };
} }
test('forgeCollisionRuleTriggerActive — trigger "collision" : vrai seulement si les boîtes se chevauchent', () => { test('forgeCollisionRuleTriggerActive — trigger "collision" : vrai si les boîtes se chevauchent, faux si loin', () => {
const objRect = rect(0, 0, 20, 20); const objRect = rect(0, 0, 20, 20);
const overlapping = rect(10, 10, 20, 20); const overlapping = rect(10, 10, 20, 20);
const far = rect(200, 200, 20, 20); const far = rect(200, 200, 20, 20);
@@ -57,6 +57,18 @@ test('forgeCollisionRuleTriggerActive — trigger "collision" : vrai seulement s
assert.equal(forgeCollisionRuleTriggerActive({ trigger: 'collision' }, objRect, far), false); assert.equal(forgeCollisionRuleTriggerActive({ trigger: 'collision' }, objRect, far), false);
}); });
test('forgeCollisionRuleTriggerActive — trigger "collision" : vrai aussi pour un simple CONTACT (bords qui se touchent sans se chevaucher)', () => {
// Bug corrigé : cet objet est presque toujours aussi un obstacle
// SOLIDE (forgeWouldCollide, personnage-controller.js) — le joueur ne
// peut donc jamais dépasser un contact tangent, et un chevauchement
// STRICT n'était donc jamais atteint : "à la collision" ne se
// déclenchait jamais en jeu réel. objRect va de x=[20,40], playerRect
// juste à côté en x=[0,20] : bord à bord, AUCUN chevauchement géométrique.
const objRect = rect(20, 0, 20, 20);
const touchingPlayer = rect(0, 0, 20, 20);
assert.equal(forgeCollisionRuleTriggerActive({ trigger: 'collision' }, objRect, touchingPlayer), true);
});
test('forgeCollisionRuleTriggerActive — trigger "perimetre" : distance entre centres <= perimetre_px', () => { test('forgeCollisionRuleTriggerActive — trigger "perimetre" : distance entre centres <= perimetre_px', () => {
const objRect = rect(0, 0, 10, 10); // centre (5,5) const objRect = rect(0, 0, 10, 10); // centre (5,5)
const near = rect(10, 0, 10, 10); // centre (15,5) -> distance 10 const near = rect(10, 0, 10, 10); // centre (15,5) -> distance 10
+29 -7
View File
@@ -32,13 +32,35 @@ function forgeElementBoxRect(el, collision) {
return forgeCollisionRectFromBox({ left: left, top: top, width: width, height: height }, collision); return forgeCollisionRectFromBox({ left: left, top: top, width: width, height: height }, collision);
} }
// "collision" : même chevauchement de boîtes que forgeWouldCollide // Une petite marge (px) appliquée SEULEMENT à la détection du
// (personnage-controller.js). "perimetre" : distance entre les CENTRES // déclencheur "collision" ci-dessous — jamais au blocage physique du
// des deux boîtes <= rule.perimetre_px (pas entre les bords — plus simple // déplacement (forgeWouldCollide, personnage-controller.js, qui reste
// et suffisant pour une portée approximative, cohérent avec le reste du // strict). Bug corrigé : un objet est presque toujours aussi un
// moteur qui ne vise pas une physique précise). // OBSTACLE SOLIDE (collision activée par défaut) — le joueur ne peut
// donc jamais aller au-delà d'un contact tangent (bords qui se touchent
// SANS se chevaucher), et un chevauchement STRICT (forgeShapesOverlap
// nu) n'était donc jamais atteint : la règle "à la collision" ne se
// déclenchait jamais. Cette marge élargit la boîte testée pour que ce
// simple contact compte comme une collision.
var FORGE_COLLISION_RULE_TOUCH_MARGIN = 3;
function forgeExpandRect(rect, margin) {
return {
left: rect.left - margin, top: rect.top - margin,
right: rect.right + margin, bottom: rect.bottom + margin,
width: rect.width + margin * 2, height: rect.height + margin * 2,
shape: rect.shape,
};
}
// "collision" : chevauchement des boîtes, ÉLARGI d'une petite marge pour
// détecter un simple contact (voir FORGE_COLLISION_RULE_TOUCH_MARGIN
// ci-dessus). "perimetre" : distance entre les CENTRES des deux boîtes
// <= rule.perimetre_px (pas entre les bords — plus simple et suffisant
// pour une portée approximative, cohérent avec le reste du moteur qui ne
// vise pas une physique précise).
function forgeCollisionRuleTriggerActive(rule, objRect, playerRect) { function forgeCollisionRuleTriggerActive(rule, objRect, playerRect) {
if (rule.trigger === 'collision') return forgeShapesOverlap(objRect, playerRect); if (rule.trigger === 'collision') return forgeShapesOverlap(forgeExpandRect(objRect, FORGE_COLLISION_RULE_TOUCH_MARGIN), playerRect);
var ocx = objRect.left + objRect.width / 2, ocy = objRect.top + objRect.height / 2; var ocx = objRect.left + objRect.width / 2, ocy = objRect.top + objRect.height / 2;
var pcx = playerRect.left + playerRect.width / 2, pcy = playerRect.top + playerRect.height / 2; var pcx = playerRect.left + playerRect.width / 2, pcy = playerRect.top + playerRect.height / 2;
var dist = Math.hypot(ocx - pcx, ocy - pcy); var dist = Math.hypot(ocx - pcx, ocy - pcy);
@@ -179,7 +201,7 @@ if (typeof module !== 'undefined' && module.exports) {
module.exports = { module.exports = {
forgeCollisionRuleTriggerActive, forgeRunCollisionRuleAction, forgeCollisionRuleTick, forgeCollisionRuleTriggerActive, forgeRunCollisionRuleAction, forgeCollisionRuleTick,
forgeStartCollisionRuleControllers, forgeStopCollisionRuleControllers, forgeStartCollisionRuleControllers, forgeStopCollisionRuleControllers,
forgeCollisionRuleStateKey, forgeElementBoxRect, forgeCollisionRuleStateKey, forgeElementBoxRect, forgeExpandRect,
}; };
const conditionsMod = require('./conditions.js'); const conditionsMod = require('./conditions.js');
global.forgeCollisionRectFromBox = global.forgeCollisionRectFromBox || conditionsMod.forgeCollisionRectFromBox; global.forgeCollisionRectFromBox = global.forgeCollisionRectFromBox || conditionsMod.forgeCollisionRectFromBox;