CréerGuidePour auteursS'applique de 4.2.5
Un mini-jeu sur mesure
This page in EnglishCette page sur le wiki GitHub
Quand aucun des mini-jeux intégrés ne convient, un jeu écrit le sien en TypeScript et le lance
avec la même commande minigame. Cette page en déroule un, du contrat jusqu’aux vérifications.
Vue d’ensemble : les mini-jeux comme greffons
Le moteur fournit pipes, cables, pick, hide, runner, stroke, scratch et la roue de codes. Un jeu ajoute les siens dans
les minigames qu’exporte son module (index.ts) : un objet { run(ctx): Promise<void>; required?: string[] } où
ctx donne l’élément de superposition, l’échelle, les images, les sons, les params de la commande et un signal
d’annulation ; required nomme les params que le validateur vérifie. { minigame: 'duel', params: { … }, then: [ … ] }
le joue ensuite comme un mini-jeu intégré. C’est le format des greffons : le même contrat que les mini-jeux intégrés.
Le module public quest-n-click/minigames donne ce qu’il faut à un greffon :
| Nom | Quoi |
|---|---|
Minigame | le contrat : run(ctx), et ce que le validateur lit (required, textParams, bindings) |
MinigameCtx | ce qu’un mini-jeu reçoit : sa zone, images, sons, paramètres, libellés, un signal d’abandon |
minigames | ceux du moteur (pipes, stroke, pick, hide, runner, scratch, cables, code-wheel), chacun chargé quand il démarre |
MINIGAME_CSS | leur style commun |
Les signatures complètes sont dans l’API publique et dans
src/engine/minigames/types.ts.
Ce que vous obtenez
Un mini-jeu à vous, enregistré sous un id, qu’un script ou une règle lance avec
{ minigame: '<id>', params: { … }, then: [ … ] } ; le validateur vérifie ses paramètres, ses images et ses sons
comme ceux d’un mini-jeu intégré, et le lecteur l’affiche par-dessus la scène avec le cadre de la voix des indices.
Contexte et versions
Un projet créé (le module est game/index.ts) ou un jeu du dépôt du moteur (games/<id>/index.ts). Le contrat est
public depuis la 4.0 ; le module s’appelle quest-n-click/minigames depuis la 4.2.5 (web-scumm/minigames avant,
retiré en 4.3.0 : quest-n-click migrate le renomme). MinigameCtx.random existe depuis la 4.1.15, le résultat
qu’un mini-jeu peut signaler depuis la 4.1.16.
Prérequis
- Un jeu qui tourne : Votre premier jeu.
- Des bases de TypeScript et de DOM : le mini-jeu se dessine avec le DOM du navigateur (ou un canvas).
- Les images et les sons qu’il emploie, préparés comme les autres (Images, Bruitages).
Où lancer les commandes
Sur votre machine, dans le dossier du projet créé (npx quest-n-click …) ou dans le dépôt du moteur
(GAME=<id> npm run …). Le code va dans le module du jeu : game/index.ts dans un projet créé, games/<id>/index.ts
dans le dépôt du moteur.
Étapes
-
Écrire
run(ctx). Il remplitctx.root(un élément par-dessus la scène, en 16:10 ;ctx.uest le nombre de pixels par unité logique, la largeur de la racine / 640), et renvoie une promesse qui se résout quand le joueur a gagné ou passé. Un mini-jeu n’échoue jamais de lui-même : la promesse se résout, etthens’exécute. Nettoyez quandctx.signalest annulé (l’hôte ferme le mini-jeu). Les images viennent desparamsparctx.img(id)etctx.size(id); les sons parctx.sfx(id);ctx.instruct(texte)affiche une réplique dans le cadre de la voix des indices ;ctx.labels.skipest le libellé « Passer » du jeu.// game/index.ts dans un projet créé (games/<id>/index.ts dans le dépôt du moteur) import type { Minigame } from 'quest-n-click/minigames'; const swordFight: Minigame = { required: ['foe'], textParams: ['intro', 'win'], bindings: { images: ['foe'], sfx: ['hit'] }, run(ctx) { return new Promise<void>((resolve) => { const box = document.createElement('div'); ctx.root.append(box); const done = () => { box.remove(); resolve(); }; ctx.signal.addEventListener('abort', done, { once: true }); if (typeof ctx.params.intro === 'string') ctx.instruct(ctx.params.intro); const foe = document.createElement('img'); foe.src = ctx.img(String(ctx.params.foe)); foe.style.height = `${120 * ctx.u}px`; let hits = 0; foe.addEventListener('click', () => { if (typeof ctx.params.hit === 'string') ctx.sfx(ctx.params.hit); hits += 1; if (hits === 3) { if (typeof ctx.params.win === 'string') ctx.instruct(ctx.params.win); setTimeout(done, 1200); } }); const skip = document.createElement('button'); skip.textContent = ctx.labels.skip; skip.addEventListener('click', () => { box.dispatchEvent(new CustomEvent('mg-skip', { bubbles: true })); done(); }); box.append(foe, skip); }); }, };
- Déclarer ce que lisent les outils.
required: les params qu’un{ minigame }doit donner, sinon le validateur le refuse.textParams: les chemins pointés des chaînes visibles par le joueur dansparams(*parcourt chaque élément d’un tableau ou valeur d’un objet, comme dansrounds.*.prompt).bindings: les params qui nomment une image (images) ou un son deaudio.sfx(sfx), dont le validateur vérifie l’existence. Tout param texte qui a la forme d’un id d’image (dossier/nom) est aussi vérifié comme image.
-
L’enregistrer dans les
minigamesdu module, que le modèle exporte déjà vide :export const minigames: Record<string, Minigame> = { sword_fight: swordFight };Le lecteur, le Studio et le validateur lisent tous cet export, fusionné par-dessus les mini-jeux intégrés. Un id qui est déjà celui d’un mini-jeu intégré le remplace pour ce jeu.
-
Le jouer depuis une règle, un sujet ou un script :
{ minigame: 'sword_fight', params: { foe: 'pirate/r1c1', hit: 'clang', intro: 'Trois touches !', win: 'Touché.' }, then: [{ set: 'pirate_beaten' }] }
- Dire comment il s’est terminé (facultatif). Le lecteur écrit le résultat dans le drapeau réservé
minigame.<id>:skippedquand un événementmg-skipremonté est sorti de la zone du mini-jeu (comme l’envoie le bouton Passer ci-dessus),wonsinon. Pour donner un autre résultat (passed,failed,disabled), émettez depuisctx.rootunnew CustomEvent('mg-record', { bubbles: true, detail: { result: 'failed' } })remonté avant de résoudre. L’histoire le lit avec{ flag: 'minigame.sword_fight', eq: 'failed' }.
-
Vérifier.
# dans le projet créé npx quest-n-click validate npx quest-n-click dev# dans le dépôt du moteur GAME=mygame npm run validate GAME=mygame npm run dev
Résultat attendu, et comment le vérifier
validate ne dit rien sur la commande. Dans le jeu, la règle ouvre le mini-jeu par-dessus la scène, la voix des
indices affiche intro, trois touches affichent win et le ferment, et pirate_beaten est posé ; Passer le ferme
tout de suite et then s’exécute aussi. Le journal de développement (?dev) montre le changement du drapeau
minigame.sword_fight.
Erreurs fréquentes
| Symptôme | Cause | Correction |
|---|---|---|
unknown minigame: "sword_fight" (known: …) | Absent des minigames du module, ou une faute dans l’id | L’enregistrer sous cet id exact |
minigame "sword_fight": missing required param "foe" | La commande ne donne pas un param listé dans required | Ajouter le param, ou le retirer de required |
minigame "sword_fight": "foe" must be an image id | Un param de bindings.images n’est pas une chaîne | Donner un id d’image, dossier/nom |
minigame "sword_fight": unknown sound "clang" (audio.sfx) | Un param de bindings.sfx ne nomme aucun son de audio.sfx | Déclarer le son (Bruitages) |
… image not found: "pirate/r1c1" | L’image n’est pas découpée ou pas préparée | npm run assets (npx quest-n-click assets) |
| Le mini-jeu ne se ferme jamais | La promesse de run ne se résout jamais | La résoudre à la victoire, au passage et à l’annulation de ctx.signal |
Fichiers ou données modifiés
Le module du jeu (game/index.ts, ou games/<id>/index.ts) et le contenu qui le lance. Les sauvegardes d’un joueur
gagnent le drapeau minigame.<id> une fois le mini-jeu joué.
Revenir en arrière
Retirez la commande, puis l’entrée de minigames : le validateur refuse une commande dont le mini-jeu n’est plus
enregistré, il montre donc chaque endroit oublié. Un drapeau minigame.<id> dans d’anciennes sauvegardes y reste, sans
effet tant que l’histoire ne le lit pas.
Références
src/engine/minigames/types.ts: le contrat ; les mini-jeux intégrés à côté sont des exemples qui marchent (src/engine/minigames/util.tscontient leurs aides, hors de l’API publique).src/engine/dom/presenter.ts: comment le lecteur lance un mini-jeu et lit son résultat.- Mini-jeux intégrés, API publique, Code sur mesure pour les commandes sur mesure.