Frameworks de code
Faites grandir Lantern jusqu'à un vrai jeu
Ajoutez un choix, une valeur dérivée, un Framework enfant et une liste au jeu du démarrage rapide, et prouvez chaque étape avec un scénario.
Avant de commencer
Partez du projet que vous avez construit dans le démarrage rapide. Chaque étape nomme chaque fichier à créer ou à modifier. Un extrait montre la partie qui change, et vous pouvez le déplier pour voir le fichier entier. Après chaque étape, choisissez Vérifier et prévisualiser.
Quatre étapes
- Ajouter un choix
Ajoutez une entrée Calling avec deux options.
schemas/keeper.json"calling": { "label": "Calling", "options": ["Guard", "Scout"], "defaultValue": "Guard" }- Ligne 11 Une liste fixe de choix. La valeur par défaut doit en faire partie.
Le constructeur reçoit la nouvelle entrée et la renvoie comme champ stocké.
rules/keeper.tsexport function construct( name: string, max_hp: number, calling: string, ): { name: string; max_hp: number; hp: number; calling: string } { return { name: name, max_hp: max_hp, hp: max_hp, calling: calling }; }- Ligne 4 La nouvelle entrée.
- Lignes 5-6 calling est maintenant un champ stocké.
Les deux scénarios ont besoin de la nouvelle valeur, dans parameters et dans expectedValues. Commencez par new-keeper.json.
scenarios/new-keeper.json{ "id": "new-keeper", "framework": "keeper", "parameters": { "name": "Mira", "max_hp": 10, "calling": "Guard" }, "expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10, "calling": "Guard" } }- Ligne 4 L'entrée que vous donnez.
- Ligne 9 La valeur stockée que vous attendez.
Faites ensuite les deux mêmes changements dans heal.json.
scenarios/heal.json"parameters": { "name": "Mira", "max_hp": 10, "calling": "Guard" }, "expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10, "calling": "Guard" },- Ligne 4 La même entrée.
- Ligne 9 La même valeur stockée.
Choisissez Vérifier et prévisualiser. La vérification doit réussir avant de continuer.
Le projet contient maintenant ces fichiers. Dépliez n'importe quel extrait ci-dessus pour voir son fichier entier.
manifest/project.json schemas/keeper.json rules/heal.ts rules/hurt.ts rules/keeper.ts layouts/keeper.json scenarios/heal.json scenarios/new-keeper.json - Dériver une valeur
Une fonction de registre dérive Guard à partir de calling. Déclarez-la dans le schéma.
schemas/keeper.json"ledgerFunctions": [ { "id": "guard", "name": "Guard", "field": "guard", "source": "rules/guard.ts" } ]- Lignes 24-27 id et name identifient la fonction, field est la valeur stockée qu'elle remplit, et source est son fichier de règles.
Créez rules/guard.ts.
rules/guard.tsfunction base_guard(calling: string): number { return calling === "Guard" ? 3 : 1; } export function guard(currentValue: number, self: ElementRef): number { const calling: string = element.var(self, "calling") as string; return base_guard(calling); }- Lignes 1-3 Une fonction d'aide sans export.
- Lignes 5-7 La fonction de registre lit calling et renvoie la valeur dérivée.
Le constructeur renvoie aussi un champ guard, avec une valeur de départ de 0. La fonction de registre remplit la vraie valeur.
rules/keeper.tsexport function construct( name: string, max_hp: number, calling: string, ): { name: string; max_hp: number; hp: number; calling: string; guard: number } { return { name: name, max_hp: max_hp, hp: max_hp, calling: calling, guard: 0 }; }- Lignes 5-6 guard fait partie de la valeur renvoyée, à partir de 0.
Un scénario vérifie la fonction. Ajoutez guard aux valeurs attendues de new-keeper.json, et une ligne de registre qui appelle la fonction.
scenarios/new-keeper.json{ "id": "new-keeper", "framework": "keeper", "parameters": { "name": "Mira", "max_hp": 10, "calling": "Guard" }, "expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10, "calling": "Guard", "guard": 3 }, "ledger": [{ "function": "guard", "currentValue": 0, "expected": 3 }] }- Ligne 10 La valeur dérivée, après l'exécution de la fonction de registre.
- Ligne 12 Appelle la fonction guard avec la valeur actuelle 0 et attend 3.
Ajoutez la même valeur attendue à heal.json.
scenarios/heal.json"parameters": { "name": "Mira", "max_hp": 10, "calling": "Guard" }, "expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10, "calling": "Guard", "guard": 3 },- Ligne 10 La valeur dérivée reste 3 dans ce scénario aussi.
Pour afficher Guard sur la fiche, listez-le dans requiredBindings et ajoutez un nœud de texte qui l'utilise.
layouts/keeper.json{ "binding": "element.attributes.guard", "expectedType": "number" }- Ligne 15 La liaison pour le nouveau champ.
layouts/keeper.json{ "kind": "text", "text": "Guard: {{element.attributes.guard}}" },- Ligne 32 Un nœud de texte qui affiche la valeur.
Choisissez Vérifier et prévisualiser. La vérification doit réussir avant de continuer.
Le projet contient maintenant ces fichiers. Dépliez n'importe quel extrait ci-dessus pour voir son fichier entier.
manifest/project.json schemas/keeper.json rules/guard.ts rules/heal.ts rules/hurt.ts rules/keeper.ts layouts/keeper.json scenarios/heal.json scenarios/new-keeper.json - Ajouter un Framework enfant
Un Keeper porte un Lamp. Le Lamp est un second Framework avec son propre schéma, son constructeur, son Cadre et son scénario. Listez son schéma et son scénario dans le manifeste.
manifest/project.json{ "formatVersion": "fabled.game-project/v1", "projectId": "game-your-game-id", "projectKind": "GAME", "compilerProfile": "native-game-v1", "name": "Lantern Keepers", "entryFramework": "keeper", "frameworks": ["schemas/keeper.json", "schemas/lamp.json"], "scenarios": [ "scenarios/new-keeper.json", "scenarios/heal.json", "scenarios/new-lamp.json" ] }- Ligne 8 Le schéma du Lamp rejoint le schéma du Keeper.
- Lignes 9-13 Le scénario du Lamp rejoint les scénarios du Keeper.
Créez le schéma du Lamp.
schemas/lamp.json{ "id": "lamp", "name": "Lamp", "elementType": "item", "constructor": "rules/lamp.ts", "inputs": { "name": { "label": "Name" }, "oil": { "label": "Oil", "defaultValue": 5 } }, "frames": [{ "id": "card", "source": "layouts/lamp.json", "default": true }] }- Lignes 6-9 Les entrées de l'enfant. Un enfant a aussi besoin d'un nom.
- Ligne 10 L'enfant a son propre Cadre.
Créez son constructeur, son Cadre et son scénario.
rules/lamp.tsexport function construct(name: string, oil: number): { name: string; oil: number } { return { name: name, oil: oil }; }- Ligne 1 Le constructeur renvoie les entrées comme valeurs stockées.
layouts/lamp.json{ "version": "1.0", "metadata": { "name": "Lamp card", "bindingMode": "bound", "frameworkRef": "lamp", "context": "BLADE", "template": "standard-blade" }, "dataContract": { "requiredBindings": [ { "binding": "element.attributes.name", "expectedType": "string" }, { "binding": "element.attributes.oil", "expectedType": "number" } ], "optionalBindings": [], "actions": [], "regions": [] }, "layout": { "kind": "container", "children": [ { "kind": "text", "text": "{{element.attributes.name}}" }, { "kind": "text", "text": "Oil: {{element.attributes.oil}}" } ] } }- Lignes 11-14 Chaque champ que le Cadre affiche est listé comme liaison.
scenarios/new-lamp.json{ "id": "new-lamp", "framework": "lamp", "parameters": { "name": "Lantern", "oil": 5 }, "expectedValues": { "name": "Lantern", "oil": 5 } }- Ligne 4 Construit un Lamp seul et vérifie ses valeurs.
Dans le Keeper, une entrée cachée contient la référence au Framework, et childFrameworks relie l'emplacement au Framework.
schemas/keeper.json"lamp": { "label": "Lamp", "defaultValue": "lamp", "hidden": true }- Ligne 14 Une entrée cachée n'apparaît jamais dans l'assistant.
schemas/keeper.json"childFrameworks": { "lamp": "lamp" }- Ligne 31 Relie l'emplacement lamp au Framework dont l'id est lamp.
Le constructeur renvoie les entrées du Lamp à côté de ses propres valeurs.
rules/keeper.tsexport function construct( name: string, max_hp: number, calling: string, lamp: FrameworkRef, ): { values: { name: string; max_hp: number; hp: number; calling: string; guard: number }; children: { lamp: { framework: FrameworkRef; params: { name: string; oil: number } } }; } { return { values: { name: name, max_hp: max_hp, hp: max_hp, calling: calling, guard: 0 }, children: { lamp: { framework: lamp, params: { name: "Lantern", oil: 5 } } }, }; }- Ligne 5 lamp est une FrameworkRef. La plateforme transforme en une FrameworkRef l'id de Framework reçu dans l'entrée.
- Lignes 6-9 Le type de retour liste les valeurs stockées et les emplacements enfants.
- Ligne 12 L'emplacement enfant : quel Framework construire et quelles entrées lui donner.
Donnez l'entrée lamp aux scénarios du Keeper, et attendez le Lamp que le constructeur construit.
scenarios/new-keeper.json{ "id": "new-keeper", "framework": "keeper", "parameters": { "name": "Mira", "max_hp": 10, "calling": "Guard", "lamp": "lamp" }, "expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10, "calling": "Guard", "guard": 3 }, "ledger": [{ "function": "guard", "currentValue": 0, "expected": 3 }], "expectedChildren": { "lamp": { "name": "Lantern", "oil": 5 } } }- Ligne 8 L'entrée cachée.
- Ligne 18 L'enfant que le constructeur construit, avec ses valeurs.
scenarios/heal.json"parameters": { "name": "Mira", "max_hp": 10, "calling": "Guard", "lamp": "lamp" }, "expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10, "calling": "Guard", "guard": 3 },- Ligne 8 L'entrée cachée dans heal.json.
scenarios/heal.json"expectedChildren": { "lamp": { "name": "Lantern", "oil": 5 } }- Ligne 30 L'enfant attendu dans heal.json.
Choisissez Vérifier et prévisualiser. La vérification doit réussir avant de continuer.
Le projet contient maintenant ces fichiers. Dépliez n'importe quel extrait ci-dessus pour voir son fichier entier.
manifest/project.json schemas/keeper.json schemas/lamp.json rules/guard.ts rules/heal.ts rules/hurt.ts rules/keeper.ts rules/lamp.ts layouts/keeper.json layouts/lamp.json scenarios/heal.json scenarios/new-keeper.json scenarios/new-lamp.json - Ajouter une liste et une action refusée
Une liste contient du contenu qu'un personnage gagne en jouant. Le Pack contient des Trinkets, un second Framework dont les préréglages sont le contenu. Listez son schéma et ses deux scénarios dans le manifeste.
manifest/project.json{ "formatVersion": "fabled.game-project/v1", "projectId": "game-your-game-id", "projectKind": "GAME", "compilerProfile": "native-game-v1", "name": "Lantern Keepers", "entryFramework": "keeper", "frameworks": [ "schemas/keeper.json", "schemas/lamp.json", "schemas/trinket.json" ], "scenarios": [ "scenarios/new-keeper.json", "scenarios/heal.json", "scenarios/new-lamp.json", "scenarios/new-trinket.json", "scenarios/pack.json" ] }- Lignes 8-12 Le schéma du Trinket rejoint les deux autres.
- Lignes 17-18 Le scénario du Trinket et le scénario pack.
Créez le schéma du Trinket. Son Cadre a besoin d'un id qu'aucun autre Cadre du jeu n'utilise.
schemas/trinket.json{ "id": "trinket", "name": "Trinket", "elementType": "item", "constructor": "rules/trinket.ts", "inputs": { "name": { "label": "Name" }, "weight": { "label": "Weight", "defaultValue": 1, "min": 0, "max": 5 } }, "frames": [ { "id": "trinket-card", "source": "layouts/trinket.json", "default": true } ], "content": [ { "id": "rope", "name": "Rope", "parameters": { "name": "Rope", "weight": 2 } }, { "id": "anvil", "name": "Anvil", "parameters": { "name": "Anvil", "weight": 5 } } ] }- Ligne 8 Un poids avec des limites. L'offre le lit.
- Lignes 10-16 Le Trinket a son propre Cadre.
- Lignes 17-28 Les préréglages qu'un joueur peut ranger. Leurs ids sont ce qu'un scénario choisit.
Créez son constructeur, son Cadre et son scénario.
rules/trinket.tsexport function construct( name: string, weight: number, ): { name: string; weight: number } { return { name: name, weight: weight }; }- Ligne 5 Renvoie les deux valeurs stockées.
layouts/trinket.json{ "version": "1.0", "metadata": { "name": "Trinket card", "bindingMode": "bound", "frameworkRef": "trinket", "context": "BLADE", "template": "standard-blade" }, "dataContract": { "requiredBindings": [ { "binding": "element.attributes.name", "expectedType": "string" }, { "binding": "element.attributes.weight", "expectedType": "number" } ], "optionalBindings": [], "actions": [], "regions": [] }, "layout": { "kind": "container", "children": [ { "kind": "text", "text": "{{element.attributes.name}}" }, { "kind": "text", "text": "Weight: {{element.attributes.weight}}" } ] } }- Lignes 22-23 Affiche le nom et le poids.
scenarios/new-trinket.json{ "id": "new-trinket", "framework": "trinket", "parameters": { "name": "Rope", "weight": 2 }, "expectedValues": { "name": "Rope", "weight": 2 } }- Ligne 4 Construit un Trinket seul et vérifie ses valeurs.
Déclarez l'action et la liste dans le schéma du Keeper.
schemas/keeper.json"actions": [ { "id": "hurt", "name": "Take damage", "source": "rules/hurt.ts" }, { "id": "heal", "name": "Heal", "source": "rules/heal.ts" }, { "id": "pack_trinket", "name": "Pack a trinket", "source": "rules/pack-trinket.ts" } ],- Lignes 19-23 La nouvelle action.
schemas/keeper.json"lists": { "pack": { "label": "Pack", "of": "trinket", "max": 4 } }- Ligne 37 La liste Pack : son libellé, le Framework de contenu qu'elle contient et sa taille.
Créez le fichier de règles de l'action.
rules/pack-trinket.tsexport function pack_trinket(self: ElementRef, trinket: ContentRef): void { list.add(self, "pack", trinket, offer.where({ weight: { lte: 3 } })); }- Ligne 1 Le trinket choisi arrive sous forme de ContentRef.
- Ligne 2 L'offre décide ce qui peut être rangé. Seulement les trinkets qui pèsent 3 ou moins.
Une offre peut refuser, donc testez les deux résultats. Créez scenarios/pack.json.
scenarios/pack.json{ "id": "pack-trinkets", "framework": "keeper", "parameters": { "name": "Mira", "max_hp": 10, "calling": "Guard", "lamp": "lamp" }, "expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10, "calling": "Guard", "guard": 3 }, "expectedChildren": { "lamp": { "name": "Lantern", "oil": 5 } }, "actions": [ { "action": "pack_trinket", "parameters": {}, "choose": { "trinket": "rope" }, "expectedWrites": [{ "op": "list.add", "key": "pack", "value": "rope" }] }, { "action": "pack_trinket", "parameters": {}, "choose": { "trinket": "anvil" }, "expectedRefusal": "NOT_OFFERED", "expectedWrites": [] } ], "expectedLists": { "pack": ["rope"] } }- Lignes 19-24 Accepté : la corde est assez légère, donc elle est ajoutée.
- Lignes 25-31 Refusé : l'enclume est trop lourde. L'étape attend le refus NOT_OFFERED et aucune écriture.
- Ligne 33 Après la dernière étape, le Pack ne contient que la corde.
Un Cadre qui affiche une liste utilise la version 2.0. Changez la version, déclarez l'action et une région dans le dataContract, puis dessinez le bouton et la région.
layouts/keeper.json"version": "2.0",- Ligne 2 Les Cadres avec une liste utilisent la version 2.0.
layouts/keeper.json"actions": [ { "name": "hurt", "functionRef": "hurt" }, { "name": "heal", "functionRef": "heal" }, { "name": "pack_trinket", "functionRef": "pack_trinket" } ], "regions": [{ "name": "pack", "listBinding": "element.lists.pack" }]- Ligne 21 L'alias de la nouvelle action.
- Ligne 23 Déclare la région de la liste.
layouts/keeper.json{ "kind": "button", "label": "Pack a trinket", "actionRef": "pack_trinket" }, { "kind": "region", "id": "pack_list", "listBinding": "{{element.lists.pack}}", "emptyText": "Your pack is empty." }- Lignes 37-39 Le bouton qui lance l'action.
- Ligne 42 Une région dessine une liste.
- Ligne 44 La liste à dessiner.
- Ligne 45 Affiché tant que la liste est vide.
Choisissez Vérifier et prévisualiser. La vérification doit réussir avant de continuer.
Le projet contient maintenant ces fichiers. Dépliez n'importe quel extrait ci-dessus pour voir son fichier entier.
manifest/project.json schemas/keeper.json schemas/lamp.json schemas/trinket.json rules/guard.ts rules/heal.ts rules/hurt.ts rules/keeper.ts rules/lamp.ts rules/pack-trinket.ts rules/trinket.ts layouts/keeper.json layouts/lamp.json layouts/trinket.json scenarios/heal.json scenarios/new-keeper.json scenarios/new-lamp.json scenarios/new-trinket.json scenarios/pack.json
Ce que vous avez construit
Votre Keeper a maintenant un choix, une valeur dérivée, un Framework enfant, une liste avec une action refusée, et des scénarios qui prouvent chacun d'eux. Les recettes montrent des changements plus petits, un par un.

