- Rust 100%
| src | ||
| tests | ||
| .gitignore | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
PoC1: Mapa Isométrico com 12 Áreas
Objetivo
Demonstrar um mapa isométrico com 12 áreas distintas (1 overworld 200×200 + 3 cidades subterrâneas + 8 cavernas), com transição automática entre áreas por proximidade a escadas.
Como rodar
cargo run -p poc1
Controles
- WASD ou Setas: mover o player 1 tile por tap (snap-to-grid, 16px). Segurar a tecla continua andando: primeiro passo imediato, depois auto-repeat (delay inicial 250ms, repetição a cada 120ms). Movimento tile-a-tile com lookahead para bloqueio por paredes (inclusive pedras e árvores do Overworld) e clamp para
AreaBoundsda área atual. - Proximidade a StairsDown: transita para a área subterrânea alvo (exit-zone: player precisa sair da zona de proximidade de 32px de todas as stairs antes de poder trocar novamente; player teleportado para spawn da área destino).
- Proximidade a StairsUp: transita de volta ao Overworld (exit-zone + teleport para spawn).
O que aparece na tela
- Overworld: mapa 200×200 tiles com 3 cidades (16×16, 32×32, 48×48), 8 entradas de caverna, caminhos conectando cidades, ~90 decorações (árvores, pedras, arbustos). Pedras e árvores (tons cinza-pedra e verde-arbusto) bloqueiam o movimento como paredes; grama e terra são só cosméticas.
- Cidades subterrâneas: 3 áreas (Small 16×16, Medium 32×32, Large 48×48) com floor tiles, paredes no perímetro, 1 StairsUp no centro.
- Cavernas: 8 áreas 12×12 isoladas, cada uma com floor tiles, paredes, 1 StairsUp no centro.
- Player: quadrado verde, spawn perto da escada da Medium City (tile 83,83 — 3 tiles na diagonal da StairsDown, fora da exit-zone de 32px). Renderiza em z=10 (
PLAYER_Z), sempre em primeiro plano sobre chão, muros, bordas e escadas. - StairsDown: quadrado laranja 16×16 (visível no Overworld, perto de cidades/cavernas).
- StairsUp: quadrado amarelo 16×16 (visível nas áreas subterrâneas).
HUD de Área
No canto superior-esquerdo, um label Text2d mostra o nome do AppState atual (ex: "Overworld", "CitySmallUnder", "Cave1Under"). Atualiza automaticamente quando o player troca de área.
Background Tint por Área
Um sprite fullscreen muda de cor conforme a categoria da área:
- Overworld: cinza escuro neutro (0.15, 0.15, 0.12)
- Cidades: azul escuro médio (0.08, 0.10, 0.20)
- Cavernas: roxo escuro (0.12, 0.06, 0.18)
Flash de Transição
Ao mudar de área, um flash overlay cobre a tela por 0.3s:
- Overworld: flash amarelo quente
- Cidades: flash azul
- Cavernas: flash roxo
Arquitetura
poc1/
src/
main.rs -- entry point, plugin registration, system wiring
lib.rs -- exports modules for integration tests
state.rs -- AppState enum (12 variants)
world_layout.rs -- WORLD_LAYOUT: 3 cities, 8 caves, 2 paths, ~90 decorations
area_spawn.rs -- spawn/despawn systems for each area (OnEnter/OnExit)
entities.rs -- Player, StairsDown, StairsUp, City, Cave, Wall, etc.
movement.rs -- WASD + grid snapping (16px) + wall lookahead
collision.rs -- AreaBounds resource + tile_collision_check (clamp)
swap.rs -- swap_layer_on_proximity + exit-zone + teleport
camera.rs -- MainCamera marker + follow_player_camera
visuals.rs -- placeholder sprites (player, stairs)
hud.rs -- HUD label, transition flash, background tint
tests/
integration_headless.rs -- 4 headless E2E tests (no GPU required)
AppState (state.rs)
Enum com 12 variantes:
Overworld(default)CitySmallUnder,CityMediumUnder,CityLargeUnderCave1Under..Cave8Under
Cada variante tem seu próprio sistema OnEnter que spawna a área e injeta AreaBounds.
WorldLayout (world_layout.rs)
LazyLock<WorldLayout> com:
- Overworld 200×200 tiles
- 3 cidades: Small (16×16), Medium (32×32), Large (48×48)
- 8 cavernas: 12×12 cada, entradas distribuídas pelo overworld
- 2 caminhos conectando cidades
- ~90 decorações (determinísticas, sem RNG)
AreaBounds (collision.rs)
Resource injetado por cada sistema OnEnter com os bounds (min, max) em tile coords da área atual. O sistema tile_collision_check clampa o player para esses bounds.
Câmera (camera.rs)
MainCamera marker component. Sistema follow_player_camera copia a posição XY do player para a câmera a cada frame, preservando o Z da câmera.
Detalhes técnicos
- Grid: 200×200 tiles (overworld), cada tile com 16px
- Transição: usa
State<AppState>do Bevy, sem loading screen - Colisão:
AreaBoundsresource +Wallmarker query, sem plugin de física - Sem LDtk: todas as entidades são spawnadas por sistemas Rust (bevy_ecs_ldtk removido)
Contratos com outros PoCs
- Fornece a base de mapa isométrico reusada por poc6 (quest system) e poc7 (minigame state transition)
AppStateé exportado vialib.rspara uso por outros crates do workspace
Testes
59 testes passando:
- 59 testes unitários inline (collision, movement, swap, hud, visuals, camera, area_spawn, world_layout)
- 4 testes de integração headless (app startup, stairs transitions, camera follow)
Rodar testes:
cargo test -p poc1
Status
- Roda sem panic
- 12 áreas funcionais com spawn/despawn automático
- Transições Overworld ↔ Underground funcionais por proximidade
- 8 cavernas isoladas (sem conexões cross-cave)
- Câmera segue player por todo o mapa 200×200
- 63 testes passando (59 unitários + 4 integração headless)
- Movimento tile-a-tile com snap-to-grid, lookahead para bloqueio por paredes, e clamp para AreaBounds