Фреймворки на коде
Быстрый старт: ваш первый фреймворк на коде
Напишите небольшую игру с одним персонажем, двумя действиями и листом. Затем проверьте её и создайте персонажа в The Forge.
Перед началом
- Чтобы создать игру, нужен платный тариф.
- Создайте приватную игру в The Forge. Выберите «СОЗДАЙТЕ СВОЮ ИГРУ», затем «Ручной редактор» и создайте игру.
- Напишите файлы в любом редакторе и вставьте их в редактор исходного кода или набирайте их прямо там.
Игра
В Lantern Keepers один персонаж, Keeper. У Keeper есть имя, максимум HP и текущее HP. HP меняют два действия: Получить урон и Лечение. Лечение никогда не поднимает HP выше максимума.
Шаг 1: манифест
Манифест называет проект и перечисляет каждый файл Framework и сценария. Оставьте projectId, который редактор создал для вашей игры. Значение в этом примере только заглушка.
{
"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"]
}- Строка 3 Оставьте projectId, который создал редактор для вашей игры. Этот id только для примера.
- Строки 4-5 GAME это полная игра с играбельным персонажем. native-game-v1 это единственный профиль.
- Строка 7 Фреймворк, который игрок создаёт первым.
- Строки 8-9 Здесь перечислены все файлы фреймворка и все файлы сценариев.
Шаг 2: фреймворк
Файл фреймворка объявляет, что вводит игрок (входные данные), что может делать Keeper (действия) и какой фрейм его рисует. Конструктор и каждое действие указывают на файл правил.
{
"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 }
]
}- Строки 2-5 Кто такой фреймворк: его id, отображаемое имя, вид элемента, который он создаёт, и файл правил, который его строит.
- Строки 6-9 Входные данные, которые заполняет игрок. Каждый ключ соответствует параметру конструктора.
- Строки 10-13 Действия. Каждое указывает на файл правил.
- Строки 14-16 Фреймы, которые рисуют Keeper. Ровно один из них стоит по умолчанию.
Шаг 3: конструктор
Конструктор превращает входные данные в начальные значения. Его возвращаемый тип перечисляет все хранимые поля. Новый Keeper начинает с полным 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 };
}- Строки 1-4 Входные данные и поля, которые возвращает конструктор.
- Строка 5 Начальные значения. Новый Keeper начинает с полным hp.
Шаг 4: действия
Действие получает сначала элемент, затем свои входные данные. Оно меняет значения только через журнал. Получить урон добавляет отрицательное число. Когда игрок нажимает кнопку действия с входными данными, например amount, Fabled запрашивает их в диалоговом окне.
export function hurt(self: ElementRef, amount: number): void {
ledger.add(self, "hp", 0 - amount);
}- Строка 2 ledger.add меняет hp на заданную величину. Если добавить отрицательное число, значение уменьшится.
Лечение читает два значения, затем устанавливает новое HP. Если у Keeper уже полное HP, оно ничего не делает, и в этом случае ничего не записывается.
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));
}
}- Строки 2-3 Прочитайте текущее и максимальное hp. element.var даёт значение, которое вы приводите через as number.
- Строка 4 Ничего не делайте, если у Keeper уже полное hp: в этом случае запись не создаётся.
- Строка 5 Задайте hp равным меньшему из двух значений: максимума и вылеченного.
Шаг 5: фрейм
Фрейм рисует лист. Текст показывает значения через привязки вида {{element.attributes.name}}. Каждая кнопка называет псевдоним действия, который объявлен в контракте данных.
{
"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" }
]
}
}- Строки 3-9 metadata называет фрейм и указывает, какому фреймворку он принадлежит.
- Строки 10-22 dataContract перечисляет поля, которые читает фрейм, и действия, которые могут вызывать его кнопки.
- Строки 23-34 layout это дерево, которое рисуется. Text показывает поля в двойных фигурных скобках, а кнопки называют псевдоним действия.
Шаг 6: сценарии
Сценарий создаёт Keeper и проверяет его начальные значения.
{
"id": "new-keeper",
"framework": "keeper",
"parameters": { "name": "Mira", "max_hp": 10 },
"expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10 }
}- Строка 4 Входные данные, из которых строится Keeper.
- Строка 5 Каждое значение, которое должен вернуть конструктор.
Этот сценарий получает урон, лечится сверх максимума и лечится ещё раз при полном HP. Каждый шаг перечисляет точные записи, которые должно сделать действие. В последнем шаге записей нет.
{
"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": [] }
]
}- Строки 7-11 Шаг первый: получить 6 урона. Действие должно сделать ровно одну запись: ledger.add со значением -6.
- Строки 12-16 Шаг второй: вылечить 9. Результат ограничен максимумом, поэтому hp становится 10.
- Строка 17 Шаг третий: снова лечить при полном hp. Защита пропускает запись, поэтому записей не ожидается.
Перенесите проект в The Forge
- Откройте свою игру в The Forge.
- На шаге «Геймплей» выберите «Дополнительно: исходный код и версии», чтобы открыть редактор исходников.
- Если в игре ещё нет проекта, выберите «Написать самостоятельно», чтобы начать с редактируемых примеров. Не выбирайте «Начать создание моей игры»: это путь через ИИ. Замените файлы примеров файлами выше: используйте «Добавить файл» для новых путей и «Удалить файл» для ненужных файлов. Оставьте projectId, который редактор записал в манифест.
- Нажмите «Проверить и показать». Исправьте все перечисленные проблемы и проверьте снова.
- Нажмите «Сохранить проект».
- Нажмите «Подготовить мою игру». Это создаст приватные фреймворки, фреймы и контент из сохранённой версии.
- Нажмите «Создать персонажа в этой игре» и попробуйте «Получить урон» и «Лечение» на листе.
Сломайте проект нарочно
Замените поле, в которое пишет Лечение, с hp на mana. Компилятор остановится и назовёт проблему.
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));
}
}Проверка сообщит:
Action "keeper.heal" calls ledger.set(self, "mana", ...), and "mana" is not declared on this schema. Declared scalar fields: hp, max_hp, name.Верните имя hp, и проверка пройдёт. Правила могут писать только в поля, которые возвращает конструктор.

