No description
Find a file
2026-08-01 09:34:21 +02:00
assets/scripts feat: create first mvp 2026-08-01 09:34:21 +02:00
src feat: create first mvp 2026-08-01 09:34:21 +02:00
.gitignore Initial commit 2026-08-01 07:33:48 +00:00
Cargo.toml feat: create first mvp 2026-08-01 09:34:21 +02:00
CONTRACT.md feat: create first mvp 2026-08-01 09:34:21 +02:00
LICENSE Initial commit 2026-08-01 07:33:48 +00:00
README.md feat: create first mvp 2026-08-01 09:34:21 +02:00

PoC4: Diálogo Ramificado (Yarn-style)

Objetivo

Demonstrar sistema de diálogo ramificado com parser .dialogue próprio (similar a Yarn Spinner), 2+ nós por arquivo, variáveis $flag sincronizadas com WorldState Rust, comandos custom <<set_quest>> e <<set_flag>>, UI de diálogo com texto + opções, trigger por tecla E perto do NPC.

Como rodar

cargo run -p poc4

Controles

  • WASD / setas: mover o player (movimento livre contínuo, 200 px/s; travado enquanto um diálogo está aberto; bloqueado por obstáculos e limitado à área jogável — ver Colisão abaixo)
  • E: abrir diálogo com NPC próximo (proximity check, raio de 50px)
  • 1/2/3: escolher opção de diálogo
  • ESC: fechar diálogo

O que aparece na tela

  • Fundo: cinza/preto padrão do Bevy
  • 2 quadrados coloridos 24×24:
    • 🔵 Azul em (-250, -150) — Player (controlado por WASD/setas)
    • 🟡 Amarelo em (0, 0) — NPC (Guide)
  • 2 obstáculos cinza 40×40 (pedra/parede) em (-125, -75) e (150, 100) — o primeiro fica bem no caminho reto do player até o NPC
  • Controles: andar até o NPC e apertar E perto dele abre o diálogo
  • Diálogo: caixa de texto com fala do NPC + botões numerados [1], [2], [3] pra escolher opção. ESC fecha.

Colisão

  • Player vs NPC/obstáculos: bloqueio circular (raio do player + raio do obstáculo); o player para na borda em vez de atravessar. Implementado em collision.rs (Obstacle, is_blocked_by_obstacle), sem wall-sliding — se o passo colide, o player simplesmente não anda naquele frame.
  • Limites de cena: SceneBounds (800×600 centrado na origem, -400..400 × -300..300) clampa a posição do player para nunca sair da área jogável.

Fluxo principal

  1. Player spawna perto do NPC
  2. Aperta E → DialogueRunner carrega intro.dialogue
  3. Player lê texto + escolhe opções
  4. Comando <<set_flag player_met_npc>> modifica WorldState
  5. Player sai → flag persiste

Arquitetura

  • poc4/src/main.rs — entry + init_resource::<WorldState>()
  • poc4/src/collision.rsObstacle, SceneBounds, checagem circular de colisão e clamp de bounds
  • poc4/src/dialogue.rs — structs Dialogue, DialogueRunner, NpcDialogue, DialoguePlugin
  • poc4/src/parser.rs — parser .dialogue com suporte a nós, comandos <<...>>, escolhas -> texto => Alvo
  • poc4/src/commands.rsset_flag_command, set_quest_command, execute_command
  • poc4/src/dialogue_ui.rs — UI bevy_ui com bolha de texto + botões de escolha
  • poc4/src/trigger.rs — proximity check + tecla E, spawna DialogueRunner
  • poc4/src/sync.rs — sincronização bidirecional $vars ↔ WorldState
  • poc4/assets/scripts/intro.dialogue — exemplo com 5 nós, condicionais <<if>>, variáveis $player_name

Formato .dialogue

title: Start
---
<<set_flag intro_shown true>>
Texto do diálogo.
-> Opção 1 => AlvoNode
-> Opção 2 => OutroNode
---

Contratos com outros PoCs

  • Consome WorldState de poc2 (set/get flags)
  • Emite comandos para poc6 (QuestSet, FlagSet via execute_command)
  • API pública: DialogueRunner, Dialogue (asset), NpcDialogue, comandos <<set_flag>>/<<set_quest>>
  • Contrato congelado em CONTRACT.md — PoC6 não deve começar sem ele

Status

Roda limpo após fix do init_resource | Player e NPC spawnados (fix da tela preta — main.rs registrava plugins mas nunca spawnava entidades) | Diálogo ramificado funcional | 5 nós no intro.dialogue | Testes unitários no parser e commands