Code frameworks
Início rápido: seu primeiro code framework
Escreva um jogo pequeno com um personagem, duas ações e uma ficha. Depois verifique e crie um personagem no The Forge.
Antes de começar
- Você precisa de um plano pago para criar um Jogo.
- Crie um jogo privado no The Forge. Escolha “CRIE SEU PRÓPRIO JOGO”, depois “Editor manual”, e crie o jogo.
- Escreva os arquivos em qualquer editor e cole no editor de código-fonte, ou digite direto nele.
O jogo
Lantern Keepers tem um personagem, o Keeper. Um Keeper tem um nome, um HP máximo e o HP atual. Duas ações mudam o HP: Take damage e Heal. Heal nunca passa do máximo.
Passo 1: o manifesto
O manifest dá nome ao projeto e lista todos os Frameworks e arquivos de cenário. Mantenha o projectId que o editor criou para o seu jogo. O valor deste exemplo é só um marcador.
{
"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"]
}- Linha 3 Mantenha o projectId que o editor criou para o seu jogo. Este é só um marcador.
- Linhas 4-5 GAME é um jogo completo com um personagem jogável. native-game-v1 é o único perfil.
- Linha 7 O Framework que um jogador cria primeiro.
- Linhas 8-9 Todo arquivo de Framework e todo arquivo de cenário está listado aqui.
Passo 2: o Framework
Um arquivo de Framework declara o que o jogador informa (entradas), o que o Keeper pode fazer (ações) e qual Frame o desenha. O construtor e cada ação apontam para um arquivo de regras.
{
"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 }
]
}- Linhas 2-5 Quem é o Framework: seu id, seu nome de exibição, o tipo de Element que ele cria e o arquivo de regras que cria um.
- Linhas 6-9 As entradas que o jogador preenche. Cada chave corresponde a um parâmetro do construtor.
- Linhas 10-13 As ações. Cada uma aponta para um arquivo de regras.
- Linhas 14-16 Os Frames que desenham um Keeper. Exatamente um é o padrão.
Passo 3: o construtor
O construtor transforma as entradas nos valores iniciais. Seu tipo de retorno lista todos os campos guardados. Um novo Keeper começa com o HP cheio.
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 };
}- Linhas 1-4 As entradas e os campos que o construtor retorna.
- Linha 5 Os valores iniciais. Um novo Keeper começa com o HP cheio.
Passo 4: as ações
Uma ação recebe primeiro o Element, depois suas próprias entradas. Ela só muda valores por meio do ledger. Take damage soma um valor negativo. Quando um jogador usa o botão de uma ação com entradas, como amount, o Fabled pede esses valores em uma caixa de diálogo.
export function hurt(self: ElementRef, amount: number): void {
ledger.add(self, "hp", 0 - amount);
}- Linha 2 ledger.add muda hp por um valor. Somar um número negativo subtrai.
Heal lê dois valores e depois define o novo HP. Ele não faz nada quando o Keeper já está com o HP cheio, então esse caso não escreve nada.
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));
}
}- Linhas 2-3 Leia o HP atual e o máximo. element.var dá um valor que você converte com as number.
- Linha 4 Não faça nada quando o Keeper já está com o HP cheio, então esse caso não escreve nada.
- Linha 5 Defina hp como o menor valor entre o máximo e o HP curado.
Passo 5: o Frame
O Frame desenha a ficha. O texto mostra valores com bindings no estilo {{element.attributes.name}}. Cada botão indica um alias de ação que o contrato de dados declara.
{
"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" }
]
}
}- Linhas 3-9 metadata dá nome ao Frame e diz a qual Framework ele pertence.
- Linhas 10-22 dataContract lista os campos que o Frame lê e as ações que seus botões podem chamar.
- Linhas 23-34 layout é a árvore que é desenhada. O texto mostra campos com chaves duplas, e os botões indicam um alias de ação.
Passo 6: os cenários
Um cenário cria um Keeper e confere seus valores iniciais.
{
"id": "new-keeper",
"framework": "keeper",
"parameters": { "name": "Mira", "max_hp": 10 },
"expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10 }
}- Linha 4 As entradas para criar o Keeper.
- Linha 5 Todo valor que o construtor deve retornar.
Este cenário sofre dano, usa Heal além do máximo e usa Heal de novo com o HP cheio. Cada passo lista as escritas exatas que a ação deve fazer. O último passo não lista nenhuma.
{
"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": [] }
]
}- Linhas 7-11 Passo um: sofrer 6 de dano. A ação deve fazer exatamente uma escrita, um ledger.add de -6.
- Linhas 12-16 Passo dois: curar 9. O resultado fica limitado ao máximo, então hp é definido como 10.
- Linha 17 Passo três: curar de novo com o HP cheio. A proteção pula a escrita, então nenhuma escrita é esperada.
Coloque no The Forge
- Abra o seu jogo no The Forge.
- Na etapa “Jogabilidade”, escolha “Avançado: código-fonte e versões” para abrir o editor de código-fonte.
- Se o jogo ainda não tem projeto, escolha “Escrever por conta própria” para começar com exemplos editáveis. Não escolha “Começar a criar meu jogo”, que é o caminho com IA. Troque os arquivos de exemplo pelos arquivos acima: use “Adicionar arquivo” para novos caminhos e “Remover arquivo” para arquivos de que você não precisa. Mantenha o projectId que o editor colocou no manifest.
- Escolha Verificar e visualizar. Corrija cada problema listado e verifique de novo.
- Escolha Salvar projeto.
- Escolha Preparar meu jogo. Isso cria Frameworks, Frames e conteúdo privados a partir da sua versão salva.
- Escolha Criar um personagem neste jogo e teste Take damage e Heal na ficha.
Quebre de propósito
Mude o campo que Heal escreve de hp para mana. O compilador para e aponta o problema.
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));
}
}A verificação informa:
Action "keeper.heal" calls ledger.set(self, "mana", ...), and "mana" is not declared on this schema. Declared scalar fields: hp, max_hp, name.Volte o nome para hp e a verificação passa. As regras só podem escrever campos que o construtor retorna.

