175 lines
4.4 KiB
Markdown
175 lines
4.4 KiB
Markdown
# Uma Certa Engine de Visual Novel Programável (Go)
|
|
|
|
Uma engine de visual novel implementada em Go usando `ebiten`, com scripts YAML para dialogos, ramificacoes, imports, variaveis tipadas, salvar/carregar, fundos e sprites de personagem.
|
|
|
|
## Recursos
|
|
|
|
- Tela de carregamento na inicializacao + validação automatica
|
|
- A tela de titulo fica bloqueada ate o validação terminar
|
|
- Imports YAML recursivos para dividir a historia em varios arquivos
|
|
- Profundidade maxima de import configuravel (`MaxImportNesting` em `internal/vn/script.go`)
|
|
- Execucao de script por cenas com ramificacoes
|
|
- Variaveis tipadas: `string`, `bool`, `int`, `float`
|
|
- Comando `if` com blocos `then`/`else`
|
|
- Salvamento/carregamento do estado do jogo em JSON
|
|
- Modo debug (`F2`) para inspecionar variaveis e pular para cenas
|
|
- Fundos por chave de cor ou caminho de imagem
|
|
- Sprites de personagem por caminho de imagem
|
|
|
|
## Inicio rapido
|
|
|
|
```bash
|
|
go mod tidy
|
|
go run ./cmd/vnengine
|
|
```
|
|
|
|
Por padrao, a engine sempre carrega `default/script.yaml`.
|
|
Todos os textos da interface/debug visiveis ao usuario sao carregados de `default/ui.yaml`.
|
|
|
|
## Controles
|
|
|
|
- Tela de carregamento: validação automatica ao iniciar
|
|
- Tela de titulo: `Up`/`Down` + `Enter`
|
|
- Historia `Enter`: avancar dialogo / confirmar escolha selecionada
|
|
- Historia `Up`/`Down`: navegar pelas escolhas
|
|
- Historia `Left Click`: avancar dialogo (quando nao estiver em escolhas)
|
|
- `F2`: alterna modo debug (mostra variaveis, digita ID da cena e aperta `Enter` para pular)
|
|
- `F5`: salvar
|
|
- `F9`: carregar
|
|
- `Esc`: voltar para a tela de titulo
|
|
|
|
## Imports de script
|
|
|
|
Use `imports` em qualquer arquivo de script. Os caminhos sao relativos ao arquivo que declara o import.
|
|
|
|
```yaml
|
|
title: "Minha Historia"
|
|
start: intro
|
|
imports:
|
|
- chapters/act1.yaml
|
|
```
|
|
|
|
Os imports podem ser aninhados recursivamente ate `MaxImportNesting`.
|
|
|
|
## Variaveis
|
|
|
|
Defina variaveis com valores YAML tipados:
|
|
|
|
```yaml
|
|
- type: set
|
|
key: player_name
|
|
value: "Mira" # string
|
|
|
|
- type: set
|
|
key: trust
|
|
value: true # bool
|
|
|
|
- type: set
|
|
key: coins
|
|
value: 3 # int
|
|
|
|
- type: set
|
|
key: luck
|
|
value: 1.5 # float
|
|
```
|
|
|
|
Interpolacao em campos de texto/sprite/fundo usa `{var_name}`.
|
|
|
|
## Condicoes e fluxo if/else
|
|
|
|
Condicao inline (guarda no nivel do comando):
|
|
|
|
```yaml
|
|
- type: say
|
|
if: "coins >= 2"
|
|
speaker: Narrador
|
|
text: "Voce consegue pagar o bonde."
|
|
```
|
|
|
|
`if/else` estruturado:
|
|
|
|
```yaml
|
|
- type: if
|
|
if: "trust == true"
|
|
then:
|
|
- type: say
|
|
speaker: Mira
|
|
text: "Entao me siga."
|
|
else:
|
|
- type: say
|
|
speaker: Mira
|
|
text: "Mantenha distancia."
|
|
```
|
|
|
|
Operadores suportados: `==`, `!=`, `>`, `<`, `>=`, `<=`.
|
|
|
|
## Validação
|
|
|
|
Na inicializacao, a engine verifica:
|
|
|
|
- se todos os arquivos de script carregados existem
|
|
- se todos os alvos de `goto` e `choice` existem
|
|
- se os assets de fundo/sprite referenciados existem (para caminhos estaticos)
|
|
|
|
Caminhos dinamicos de asset contendo variaveis (ex.: `{mood}.png`) sao ignorados na verificacao estatica de existencia.
|
|
|
|
## Referencia de comandos
|
|
|
|
- `say`
|
|
- `background` (`background` ou `background_image`)
|
|
- `character` (`character`, `emotion`, `sprite` opcional)
|
|
- `set`
|
|
- `if` (`if`, `then`, `else`)
|
|
- `goto`
|
|
- `choice`
|
|
- `end`
|
|
|
|
## Cena de menu interativo (`menu`)
|
|
|
|
Voce pode criar um menu em cena com sprites posicionados e navegacao por setas (`Left`/`Right`/`Up`/`Down`) + `Enter`.
|
|
|
|
```yaml
|
|
- type: menu
|
|
background_image: assets/bg_hub.png
|
|
menu_items:
|
|
- id: oficina
|
|
sprite: assets/menu_oficina.png
|
|
x: 0.25
|
|
y: 0.45
|
|
selectable: true
|
|
commands:
|
|
- type: set
|
|
key: destino
|
|
value: oficina
|
|
- type: goto
|
|
target: cena_oficina
|
|
|
|
- id: mercado
|
|
sprite: assets/menu_mercado.png
|
|
x: 0.65
|
|
y: 0.45
|
|
if: "coins >= 2"
|
|
selectable: true
|
|
commands:
|
|
- type: say
|
|
speaker: Narrador
|
|
text: "Voce vai para o mercado."
|
|
|
|
- id: decoracao
|
|
sprite: assets/menu_estatua.png
|
|
x: 0.45
|
|
y: 0.2
|
|
selectable: false
|
|
commands:
|
|
- type: say
|
|
speaker: Narrador
|
|
text: "Isto nao deve executar porque nao e selecionavel."
|
|
```
|
|
|
|
Notas:
|
|
- `x`/`y` entre `0` e `1` sao tratados como proporcao da tela.
|
|
- `x`/`y` acima de `1` sao tratados como pixels absolutos.
|
|
- Itens com `if` falso nao aparecem.
|
|
- Itens com `selectable: false` aparecem, mas nao recebem destaque nem selecao.
|
|
- `commands` de um item aceitam qualquer fluxo suportado (`set`, `if`, `goto`, `say`, etc.).
|