Remplace le système de quêtes par des déclencheurs, ajoute l'action variable et le chaînage
Supprime le concept de "quête" au profit d'un onglet unique "Déclencheurs"
portant toute la logique (dialogue, condition, marquage terminé) directement
sur l'objet de scène. Ajoute une nouvelle action "Modifier une variable"
(réutilisant le vocabulaire du graphe de flow) utilisable après une
collision, une interaction ou une branche de condition, ainsi qu'un
chaînage d'actions ("then") permettant d'enchaîner plusieurs actions à la
suite et d'étendre un déclencheur déjà posé sans le recréer.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
c504ace167
commit
d664ed5637
@@ -1,13 +1,13 @@
|
||||
// ---------- Éditeur de collision — moteur d'exécution en jeu ----------
|
||||
// Chaque objet de scène AUTRE que le joueur (jamais un "fond", jamais le
|
||||
// personnage "joueur" — voir screens/rendering/collision_rules.py) peut
|
||||
// porter des règles "déclencheur -> action" posées dans l'onglet
|
||||
// "🧩 Collision" (static/js/scenes/collision-rules-editor.js). Ce fichier
|
||||
// les FAIT VIVRE pendant le jeu : à chaque tick, teste chaque règle contre
|
||||
// la position du joueur, déclenche l'action une seule fois par entrée
|
||||
// (pas en continu tant que la condition reste vraie), même cadence que
|
||||
// personnage-controller.js (50ms) et réutilise ses mêmes briques
|
||||
// (forgeCollisionRectFromBox/forgeShapesOverlap de conditions.js).
|
||||
// porter des règles "déclencheur -> action", posées depuis l'onglet
|
||||
// "Déclencheurs" (static/js/triggers/trigger-editor.js::openTriggerWizard).
|
||||
// Ce fichier les FAIT VIVRE pendant le jeu : à chaque tick, teste chaque
|
||||
// règle contre la position du joueur, déclenche l'action une seule fois
|
||||
// par entrée (pas en continu tant que la condition reste vraie), même
|
||||
// cadence que personnage-controller.js (50ms) et réutilise ses mêmes
|
||||
// briques (forgeCollisionRectFromBox/forgeShapesOverlap de conditions.js).
|
||||
// Pur JS client, sans le moindre appel serveur — fonctionne à l'identique
|
||||
// en ligne et dans un export SCORM (voir static/js/play/offline/), aucun
|
||||
// branchement FORGE_OFFLINE nécessaire ici.
|
||||
@@ -62,16 +62,10 @@ function forgeExpandRect(rect, margin) {
|
||||
|
||||
// "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).
|
||||
// ci-dessus) — seul déclencheur encore proposé ("perimetre" retiré, ne
|
||||
// servait à rien pour l'instant, demande explicite).
|
||||
function forgeCollisionRuleTriggerActive(rule, 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 pcx = playerRect.left + playerRect.width / 2, pcy = playerRect.top + playerRect.height / 2;
|
||||
var dist = Math.hypot(ocx - pcx, ocy - pcy);
|
||||
return dist <= (rule.perimetre_px || 0);
|
||||
return forgeShapesOverlap(forgeExpandRect(objRect, FORGE_COLLISION_RULE_TOUCH_MARGIN), playerRect);
|
||||
}
|
||||
|
||||
// La bulle "Appuie sur X" ne peut PAS être un enfant de objectEl : un
|
||||
@@ -118,27 +112,50 @@ function forgeHideCollisionInteractBubble(objectId, objectEl) {
|
||||
if (bubble) bubble.style.display = 'none';
|
||||
}
|
||||
|
||||
// Exécute une action (top-level ou sub_action d'un "interagir") — jamais
|
||||
// appelée pour un "interagir" lui-même à ce niveau, voir forgeCollisionRuleTick
|
||||
// qui gère "interagir" à part (affichage de bulle + attente de touche).
|
||||
// Exécute une action (top-level, sub_action d'un "interagir", ou branche
|
||||
// si_vrai/si_faux d'une "condition") — jamais appelée pour un "interagir"
|
||||
// lui-même à ce niveau, voir forgeCollisionRuleTick qui le gère à part
|
||||
// (affichage de bulle + attente de touche).
|
||||
function forgeRunCollisionRuleAction(action, targetEl, obj) {
|
||||
if (action.type === 'evenement') {
|
||||
window.dispatchGameEvent(action.evenement_id);
|
||||
return;
|
||||
}
|
||||
if (action.type === 'attaque') {
|
||||
var attackAnim = forgePersonnageAnimExists(obj.id, 'attaque') ? 'attaque' : null;
|
||||
if (attackAnim) runSpriteAnimation(targetEl, resolveSpriteFrames(obj.id, { animation: attackAnim, fps: FORGE_PERSONNAGE_FPS, loop: false }));
|
||||
return;
|
||||
}
|
||||
if (action.type === 'quete') {
|
||||
// Affiche la réplique en cours du dialogue de cette quête, selon son
|
||||
// statut actuel, dans le widget "💬 Boîte de dialogue" posé sur
|
||||
// l'écran (voir static/js/play/dialogue-box-controller.js) — sans
|
||||
// effet si aucun widget n'est posé ou si la quête n'a aucune
|
||||
// réplique pour son statut, comme le reste de ce moteur.
|
||||
forgeShowDialogueBox(action.quete_id);
|
||||
return;
|
||||
if (action.type === 'dialogue') {
|
||||
// Affiche LE DIALOGUE DE CETTE ACTION PRÉCISE (action.dialogue.lines
|
||||
// — chaque occurrence de "Déclencher ce dialogue" porte le sien,
|
||||
// voir screens/rendering/collision_rules.py) dans le widget "💬 Boîte
|
||||
// de dialogue" posé sur l'écran (voir static/js/play/
|
||||
// dialogue-box-controller.js) — sans effet si aucun widget n'est
|
||||
// posé, comme le reste de ce moteur. Le nom affiché (en-tête du
|
||||
// quiz, xAPI) est celui de l'objet déclencheur (voir "ℹ️
|
||||
// Informations") — plus de "quête" pour le porter. mark_completed
|
||||
// (optionnel) : marque ce dialogue terminé une fois épuisé.
|
||||
// `action.then` (chaînage, voir maquette validée : "pouvoir modifier
|
||||
// un déclencheur pour lui ajouter des actions") NE PEUT PAS
|
||||
// s'exécuter immédiatement — un dialogue attend des clics du joueur
|
||||
// — transmis à forgeShowDialogueBox, exécuté par dialogue-box-
|
||||
// controller.js une fois le dialogue épuisé.
|
||||
var lines = (action.dialogue && action.dialogue.lines) || [];
|
||||
var dialogueId = action.dialogue && action.dialogue.id;
|
||||
forgeShowDialogueBox(dialogueId, obj.name || 'PNJ', lines, action.mark_completed, action.then);
|
||||
} else if (action.type === 'variable') {
|
||||
// Modifie une variable globale — même vocabulaire/calcul que l'action
|
||||
// "Modifier une variable" du graphe de logique document (voir
|
||||
// screens/data_actions/apply_variable_action.py), portée ici par
|
||||
// forgeApplyVariableActionOffline (static/js/play/offline/apply-actions.js,
|
||||
// TOUJOURS chargée — voir templates/play.html — pas seulement en
|
||||
// export, donc aucun branchement FORGE_OFFLINE nécessaire, même
|
||||
// philosophie que le reste de ce fichier). Instantané : `then`
|
||||
// s'exécute tout de suite, contrairement à un dialogue.
|
||||
forgeApplyVariableActionOffline(gameData, action);
|
||||
if (action.then) forgeRunCollisionRuleAction(action.then, targetEl, obj);
|
||||
} else if (action.type === 'condition') {
|
||||
// Réutilise evaluateConditionClause (static/js/play/conditions.js),
|
||||
// même comparaison qu'un nœud Condition de l'éditeur de logique, sur
|
||||
// une VARIABLE GLOBALE (gameData.variables) — jamais un champ d'objet
|
||||
// ici (voir maquette validée : le losange ne teste qu'une variable).
|
||||
var isTrue = evaluateConditionClause({
|
||||
source: 'variable', variable: action.variable, operator: action.operateur, value: action.valeur,
|
||||
});
|
||||
var branch = isTrue ? action.si_vrai : action.si_faux;
|
||||
if (branch) forgeRunCollisionRuleAction(branch, targetEl, obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,6 +253,7 @@ if (typeof module !== 'undefined' && module.exports) {
|
||||
const conditionsMod = require('./conditions.js');
|
||||
global.forgeCollisionRectFromBox = global.forgeCollisionRectFromBox || conditionsMod.forgeCollisionRectFromBox;
|
||||
global.forgeShapesOverlap = global.forgeShapesOverlap || conditionsMod.forgeShapesOverlap;
|
||||
global.evaluateConditionClause = global.evaluateConditionClause || conditionsMod.evaluateConditionClause;
|
||||
const personnageMod = require('./personnage-controller.js');
|
||||
global.forgePersonnageAnimExists = global.forgePersonnageAnimExists || personnageMod.forgePersonnageAnimExists;
|
||||
global.FORGE_PERSONNAGE_FPS = global.FORGE_PERSONNAGE_FPS || 8;
|
||||
|
||||
Reference in New Issue
Block a user