Frameworki kodowe
Szybki start: Twój pierwszy framework kodowy
Napisz małą grę z jedną postacią, dwiema akcjami i kartą. Potem sprawdź ją i utwórz postać w The Forge.
Zanim zaczniesz
- Aby utworzyć grę, potrzebujesz płatnego planu.
- Utwórz prywatną grę w The Forge. Wybierz „STWÓRZ WŁASNĄ GRĘ”, potem „Edytor ręczny” i utwórz grę.
- Napisz pliki w dowolnym edytorze, a potem wklej je do edytora kodu źródłowego albo wpisz je od razu tam.
Gra
Lantern Keepers ma jedną postać, Keepera. Keeper ma imię, maksymalne HP i bieżące HP. Dwie akcje zmieniają HP: Take damage i Heal. Heal nigdy nie podnosi HP ponad maksimum.
Krok 1: manifest
Manifest podaje nazwę projektu i wymienia każdy Framework oraz każdy plik scenariusza. Zachowaj projectId, który edytor utworzył dla Twojej gry. Wartość w tym przykładzie to tylko wzór.
{
"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"],
"scenarios": ["scenarios/new-keeper.json", "scenarios/heal.json"]
}- Wiersz 3 Zachowaj projectId, który edytor utworzył dla Twojej gry. Ten jest tylko wzorem.
- Wiersze 4-5 GAME to pełna gra z postacią, którą można grać. native-game-v1 to jedyny profil.
- Wiersz 7 Framework, który gracz tworzy jako pierwszy.
- Wiersze 8-9 Tutaj wymieniony jest każdy plik frameworka i każdy plik scenariusza.
Krok 2: framework
Plik frameworka deklaruje, co wpisuje gracz (dane wejściowe), co potrafi Keeper (akcje) i która ramka go rysuje. Konstruktor i każda akcja wskazują plik z regułami.
{
"id": "keeper",
"name": "Keeper",
"elementType": "character",
"constructor": "rules/keeper.ts",
"inputs": {
"name": { "label": "Name" },
"max_hp": { "label": "Maximum HP", "defaultValue": 10 }
},
"actions": [
{ "id": "hurt", "name": "Take damage", "source": "rules/hurt.ts" },
{ "id": "heal", "name": "Heal", "source": "rules/heal.ts" }
],
"frames": [
{ "id": "sheet", "source": "layouts/keeper.json", "default": true }
]
}- Wiersze 2-5 Kim jest framework: jego id, nazwa wyświetlana, rodzaj elementu, który buduje, i plik reguł, który go buduje.
- Wiersze 6-9 Dane wejściowe, które wypełnia gracz. Każdy klucz odpowiada parametrowi konstruktora.
- Wiersze 10-13 Akcje. Każda wskazuje plik reguł.
- Wiersze 14-16 Ramki, które rysują Keepera. Dokładnie jedna jest domyślna.
Krok 3: konstruktor
Konstruktor zamienia dane wejściowe na wartości początkowe. Jego typ zwracany wymienia każde zapisywane pole. Nowy Keeper zaczyna z pełnym HP.
export function construct(
name: string,
max_hp: number,
): { name: string; max_hp: number; hp: number } {
return { name: name, max_hp: max_hp, hp: max_hp };
}- Wiersze 1-4 Dane wejściowe i pola, które zwraca konstruktor.
- Wiersz 5 Wartości początkowe. Nowy Keeper zaczyna z pełnym HP.
Krok 4: akcje
Akcja przyjmuje najpierw element, potem własne dane wejściowe. Zmienia wartości tylko przez ledger. Take damage dodaje wartość ujemną. Gdy gracz użyje przycisku akcji z danymi wejściowymi, takimi jak amount, Fabled prosi o nie w oknie dialogowym.
export function hurt(self: ElementRef, amount: number): void {
ledger.add(self, "hp", 0 - amount);
}- Wiersz 2 ledger.add zmienia hp o podaną wartość. Dodanie liczby ujemnej odejmuje.
Heal odczytuje dwie wartości, a potem ustawia nowe HP. Nic nie robi, gdy Keeper ma już pełne HP, więc w tym przypadku nic nie zapisuje.
export function heal(self: ElementRef, amount: number): void {
const hp: number = element.var(self, "hp") as number;
const max_hp: number = element.var(self, "max_hp") as number;
if (hp < max_hp) {
ledger.set(self, "hp", math.min(max_hp, hp + amount));
}
}- Wiersze 2-3 Odczytaj bieżące i maksymalne HP. element.var daje wartość, którą rzutujesz przez as number.
- Wiersz 4 Nie rób nic, gdy Keeper ma już pełne HP, więc w tym przypadku nic się nie zapisuje.
- Wiersz 5 Ustaw hp na mniejszą z dwóch wartości: maksimum albo wyleczone HP.
Krok 5: ramka
Ramka rysuje kartę. Tekst pokazuje wartości za pomocą powiązań w stylu {{element.attributes.name}}. Każdy przycisk wskazuje alias akcji zadeklarowany w kontrakcie danych.
{
"version": "1.0",
"metadata": {
"name": "Keeper sheet",
"bindingMode": "bound",
"frameworkRef": "keeper",
"context": "BLADE",
"template": "standard-blade"
},
"dataContract": {
"requiredBindings": [
{ "binding": "element.attributes.name", "expectedType": "string" },
{ "binding": "element.attributes.hp", "expectedType": "number" },
{ "binding": "element.attributes.max_hp", "expectedType": "number" }
],
"optionalBindings": [],
"actions": [
{ "name": "hurt", "functionRef": "hurt" },
{ "name": "heal", "functionRef": "heal" }
],
"regions": []
},
"layout": {
"kind": "container",
"children": [
{ "kind": "text", "text": "{{element.attributes.name}}" },
{
"kind": "text",
"text": "HP: {{element.attributes.hp}} / {{element.attributes.max_hp}}"
},
{ "kind": "button", "label": "Take damage", "actionRef": "hurt" },
{ "kind": "button", "label": "Heal", "actionRef": "heal" }
]
}
}- Wiersze 3-9 metadata nazywa ramkę i mówi, do którego frameworka należy.
- Wiersze 10-22 dataContract wymienia pola, które ramka czyta, i akcje, które mogą wywołać jej przyciski.
- Wiersze 23-34 layout to drzewo, które jest rysowane. Tekst pokazuje pola w podwójnych nawiasach klamrowych, a przyciski wskazują alias akcji.
Krok 6: scenariusze
Scenariusz buduje Keepera i sprawdza jego wartości początkowe.
{
"id": "new-keeper",
"framework": "keeper",
"parameters": { "name": "Mira", "max_hp": 10 },
"expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10 }
}- Wiersz 4 Dane wejściowe, z których powstaje Keeper.
- Wiersz 5 Każda wartość, którą musi zwrócić konstruktor.
Ten scenariusz zadaje obrażenia, leczy ponad maksimum i leczy jeszcze raz przy pełnym HP. Każdy krok wymienia dokładne zapisy, które akcja musi wykonać. Ostatni krok nie wymienia żadnych.
{
"id": "heal-after-damage",
"framework": "keeper",
"parameters": { "name": "Mira", "max_hp": 10 },
"expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10 },
"actions": [
{
"action": "hurt",
"parameters": { "amount": 6 },
"expectedWrites": [{ "op": "ledger.add", "key": "hp", "value": -6 }]
},
{
"action": "heal",
"parameters": { "amount": 9 },
"expectedWrites": [{ "op": "ledger.set", "key": "hp", "value": 10 }]
},
{ "action": "heal", "parameters": { "amount": 3 }, "expectedWrites": [] }
]
}- Wiersze 7-11 Krok pierwszy: otrzymaj 6 obrażeń. Akcja musi wykonać dokładnie jeden zapis, ledger.add z wartością -6.
- Wiersze 12-16 Krok drugi: ulecz 9. Wynik jest ograniczony do maksimum, więc hp jest ustawione na 10.
- Wiersz 17 Krok trzeci: ulecz jeszcze raz przy pełnym HP. Warunek pomija zapis, więc nie oczekujemy żadnych zapisów.
Umieść to w The Forge
- Otwórz swoją grę w The Forge.
- W kroku „Rozgrywka” wybierz „Zaawansowane: kod źródłowy i wersje”, aby otworzyć edytor źródeł.
- Jeśli gra nie ma jeszcze projektu, wybierz „Napiszę samodzielnie”, aby zacząć od przykładów do edycji. Nie wybieraj „Zacznij tworzyć moją grę”, bo to droga przez AI. Zastąp pliki przykładowe plikami z góry: użyj „Dodaj plik” dla nowych ścieżek i „Usuń plik” dla plików, których nie potrzebujesz. Zachowaj projectId, który edytor wpisał do manifestu.
- Wybierz Sprawdź i wyświetl. Popraw każdy wymieniony problem, a potem sprawdź ponownie.
- Wybierz Zapisz projekt.
- Wybierz Przygotuj moją grę. To tworzy prywatne frameworki, ramki i treści z zapisanej wersji.
- Wybierz Stwórz postać w tej grze i wypróbuj Take damage i Heal na karcie.
Zepsuj to celowo
Zmień pole, które zapisuje Heal, z hp na mana. Kompilator zatrzyma się i nazwie problem.
export function heal(self: ElementRef, amount: number): void {
const hp: number = element.var(self, "hp") as number;
const max_hp: number = element.var(self, "max_hp") as number;
if (hp < max_hp) {
ledger.set(self, "mana", math.min(max_hp, hp + amount));
}
}Sprawdzenie zgłasza:
Action "keeper.heal" calls ledger.set(self, "mana", ...), and "mana" is not declared on this schema. Declared scalar fields: hp, max_hp, name.Przywróć nazwę hp, a sprawdzenie przejdzie. Reguły mogą zapisywać tylko pola, które zwraca konstruktor.

