Framework in codice
Fai crescere Lantern fino a un vero gioco
Aggiungi una scelta, un valore derivato, un Framework figlio e un elenco al gioco dell'avvio rapido, e dimostra ogni passo con uno scenario.
Prima di iniziare
Parti dal progetto che hai costruito nell'avvio rapido. Ogni passo nomina ogni file da creare o modificare. Un estratto mostra la parte che cambia, e puoi espanderlo per vedere tutto il file. Dopo ogni passo, scegli Verifica e anteprima.
Quattro passi
- Aggiungi una scelta
Aggiungi un input Calling con due opzioni.
schemas/keeper.json"calling": { "label": "Calling", "options": ["Guard", "Scout"], "defaultValue": "Guard" }- Riga 11 Un elenco fisso di scelte. Il valore predefinito deve essere una di esse.
Il costruttore riceve il nuovo input e lo restituisce come campo salvato.
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 }; }- Riga 4 Il nuovo input.
- Righe 5-6 calling ora è un campo salvato.
Entrambi gli scenari hanno bisogno del nuovo valore, in parameters e in expectedValues. Parti da 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" } }- Riga 4 L'input che dai.
- Riga 9 Il valore salvato che ti aspetti.
Poi fai le stesse due modifiche in heal.json.
scenarios/heal.json"parameters": { "name": "Mira", "max_hp": 10, "calling": "Guard" }, "expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10, "calling": "Guard" },- Riga 4 Lo stesso input.
- Riga 9 Lo stesso valore salvato.
Scegli Verifica e anteprima. Deve passare prima di andare avanti.
Ora il progetto contiene questi file. Espandi un estratto qui sopra per vedere tutto il suo file.
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 - Ricava un valore
Una funzione del registro ricava Guard dal calling. Dichiarala nello schema.
schemas/keeper.json"ledgerFunctions": [ { "id": "guard", "name": "Guard", "field": "guard", "source": "rules/guard.ts" } ]- Righe 24-27 id e name identificano la funzione, field è il valore salvato che riempie e source è il suo file di regole.
Crea 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); }- Righe 1-3 Una funzione di supporto senza export.
- Righe 5-7 La funzione del registro legge il calling e restituisce il valore derivato.
Il costruttore restituisce anche un campo guard, con valore iniziale 0. La funzione del registro inserisce il valore vero.
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 }; }- Righe 5-6 guard fa parte del valore restituito, e parte da 0.
Uno scenario controlla la funzione. Aggiungi guard ai valori attesi di new-keeper.json e una riga del registro che chiama la funzione.
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 }] }- Riga 10 Il valore derivato, dopo l'esecuzione della funzione del registro.
- Riga 12 Chiama la funzione guard con il valore attuale 0 e si aspetta 3.
Aggiungi lo stesso valore atteso a 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 },- Riga 10 Anche in questo scenario il valore derivato resta 3.
Per mostrare Guard sulla scheda, elencalo in requiredBindings e aggiungi un nodo di testo che lo usa.
layouts/keeper.json{ "binding": "element.attributes.guard", "expectedType": "number" }- Riga 15 Il collegamento per il nuovo campo.
layouts/keeper.json{ "kind": "text", "text": "Guard: {{element.attributes.guard}}" },- Riga 32 Un nodo di testo che mostra il valore.
Scegli Verifica e anteprima. Deve passare prima di andare avanti.
Ora il progetto contiene questi file. Espandi un estratto qui sopra per vedere tutto il suo file.
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 - Aggiungi un Framework figlio
Un Keeper porta con sé una Lamp. La Lamp è un secondo Framework, con il suo schema, il suo costruttore, il suo Frame e il suo scenario. Elenca il suo schema e il suo scenario nel manifest.
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" ] }- Riga 8 Lo schema della Lamp si aggiunge a quello del Keeper.
- Righe 9-13 Lo scenario della Lamp si aggiunge a quelli del Keeper.
Crea lo schema della 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 }] }- Righe 6-9 Gli input del figlio. Anche un figlio ha bisogno di un nome.
- Riga 10 Il figlio ha il suo Frame.
Crea il suo costruttore, il suo Frame e il suo scenario.
rules/lamp.tsexport function construct(name: string, oil: number): { name: string; oil: number } { return { name: name, oil: oil }; }- Riga 1 Il costruttore restituisce gli input come valori salvati.
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}}" } ] } }- Righe 11-14 Ogni campo che il Frame mostra è elencato come collegamento.
scenarios/new-lamp.json{ "id": "new-lamp", "framework": "lamp", "parameters": { "name": "Lantern", "oil": 5 }, "expectedValues": { "name": "Lantern", "oil": 5 } }- Riga 4 Costruisce una Lamp da sola e ne controlla i valori.
Nel Keeper, un input nascosto contiene il riferimento al Framework e childFrameworks associa lo slot al Framework.
schemas/keeper.json"lamp": { "label": "Lamp", "defaultValue": "lamp", "hidden": true }- Riga 14 Un input nascosto non compare mai nella procedura guidata.
schemas/keeper.json"childFrameworks": { "lamp": "lamp" }- Riga 31 Associa lo slot lamp al Framework con id lamp.
Il costruttore restituisce gli input della Lamp accanto ai propri valori.
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 } } }, }; }- Riga 5 lamp è un FrameworkRef. La piattaforma trasforma in uno di questi l'id del Framework preso dall'input.
- Righe 6-9 Il tipo di ritorno elenca i valori salvati e gli slot figli.
- Riga 12 Lo slot figlio: quale Framework costruire e gli input da dargli.
Dai agli scenari del Keeper l'input lamp e aspettati la Lamp che il costruttore costruisce.
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 } } }- Riga 8 L'input nascosto.
- Riga 18 Il figlio che il costruttore costruisce, con i suoi valori.
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 },- Riga 8 L'input nascosto in heal.json.
scenarios/heal.json"expectedChildren": { "lamp": { "name": "Lantern", "oil": 5 } }- Riga 30 Il figlio atteso in heal.json.
Scegli Verifica e anteprima. Deve passare prima di andare avanti.
Ora il progetto contiene questi file. Espandi un estratto qui sopra per vedere tutto il suo file.
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 - Aggiungi un elenco e un'azione rifiutata
Un elenco contiene i contenuti che un personaggio ottiene giocando. Il Pack contiene Trinket, un secondo Framework i cui preset sono i contenuti. Elenca il suo schema e i suoi due scenari nel manifest.
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" ] }- Righe 8-12 Lo schema del Trinket si aggiunge agli altri due.
- Righe 17-18 Lo scenario del Trinket e lo scenario pack.
Crea lo schema del Trinket. Il suo Frame ha bisogno di un id che nessun altro Frame del gioco usa.
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 } } ] }- Riga 8 Un peso con dei limiti. L'offerta lo legge.
- Righe 10-16 Il Trinket ha il suo Frame.
- Righe 17-28 I preset che un giocatore può mettere nello zaino. I loro id sono ciò che uno scenario sceglie.
Crea il suo costruttore, il suo Frame e il suo scenario.
rules/trinket.tsexport function construct( name: string, weight: number, ): { name: string; weight: number } { return { name: name, weight: weight }; }- Riga 5 Restituisce i due valori salvati.
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}}" } ] } }- Righe 22-23 Mostra il nome e il peso.
scenarios/new-trinket.json{ "id": "new-trinket", "framework": "trinket", "parameters": { "name": "Rope", "weight": 2 }, "expectedValues": { "name": "Rope", "weight": 2 } }- Riga 4 Costruisce un Trinket da solo e ne controlla i valori.
Dichiara l'azione e l'elenco nello schema del 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" } ],- Righe 19-23 La nuova azione.
schemas/keeper.json"lists": { "pack": { "label": "Pack", "of": "trinket", "max": 4 } }- Riga 37 L'elenco Pack: la sua etichetta, il Framework di contenuti che contiene e la sua dimensione.
Crea il file di regole dell'azione.
rules/pack-trinket.tsexport function pack_trinket(self: ElementRef, trinket: ContentRef): void { list.add(self, "pack", trinket, offer.where({ weight: { lte: 3 } })); }- Riga 1 Il trinket scelto arriva come ContentRef.
- Riga 2 L'offerta decide cosa si può mettere nello zaino. Solo i trinket che pesano 3 o meno.
Un'offerta può rifiutare, quindi testa entrambi i risultati. Crea 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"] } }- Righe 19-24 Accettato: la rope è abbastanza leggera, quindi viene aggiunta.
- Righe 25-31 Rifiutato: la anvil è troppo pesante. Il passo si aspetta il rifiuto NOT_OFFERED e nessuna scrittura.
- Riga 33 Dopo l'ultimo passo il Pack contiene solo la rope.
Un Frame che mostra un elenco usa version 2.0. Cambia la versione, dichiara l'azione e una regione nel dataContract, e disegna il pulsante e la regione.
layouts/keeper.json"version": "2.0",- Riga 2 I Frame con un elenco usano 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" }]- Riga 21 L'alias per la nuova azione.
- Riga 23 Dichiara la regione dell'elenco.
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." }- Righe 37-39 Il pulsante che esegue l'azione.
- Riga 42 Una regione disegna un elenco.
- Riga 44 L'elenco da disegnare.
- Riga 45 Mostrato mentre l'elenco è vuoto.
Scegli Verifica e anteprima. Deve passare prima di andare avanti.
Ora il progetto contiene questi file. Espandi un estratto qui sopra per vedere tutto il suo file.
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
Cosa hai costruito
Il tuo Keeper ora ha una scelta, un valore derivato, un Framework figlio, un elenco con un'azione rifiutata e scenari che dimostrano ognuno di questi elementi. Le ricette mostrano modifiche più piccole, una alla volta.

