Para criar jogos e protótipos interativos em Rust em 2026, comece pelo Bevy quando você quer uma engine data-driven com Entity Component System, renderização moderna via wgpu e um código-base 100% Rust. Modele o jogo como entidades + componentes + sistemas, separe estado de lógica, carregue assets de forma explícita e só então acrescente física, áudio, UI e export WASM. Não escolha Bevy por moda: escolha quando ECS, iteração em código e controle do loop de frame resolvem o produto melhor do que um editor tradicional.
Bevy já aparece em conversas de carreira em gamedev com Rust, no panorama de Rust para jogos e em comparativos de GUI e ferramentas. Este artigo é o guia operacional: como estruturar um projeto Bevy de verdade, o que colocar no primeiro milestone e como transformar isso em sinal de portfólio e vagas Rust.
Resposta rápida: Bevy, ggez, macroquad ou engine AAA?
| Necessidade | Escolha inicial | Motivo |
|---|---|---|
| Jogo 2D/3D data-driven com ECS e ecossistema de plugins | Bevy | engine completa, schedules, assets e wgpu |
| Protótipo 2D mínimo em poucas horas | macroquad / ggez | API pequena, feedback imediato |
| Editor maduro, marketplace e time grande | Unity / Unreal | pipeline de conteúdo e hiring mais amplos |
| Ferramenta interna, simulação ou visualizador | Bevy ou egui | Bevy para cena/tempo real; egui para painéis |
| Demo jogável no browser | Bevy + WASM ou macroquad | WASM viável; cuide do tamanho e dos assets |
| Servidor multiplayer / authoritative sim | Rust + Tokio (+ Bevy só no cliente se fizer sentido) | separe simulação de rede da renderização |
Regra prática: se o valor está no modelo de dados e nos sistemas, Bevy encaixa. Se o valor está em arrastar assets num editor com designers não-programadores no dia um, avalie stacks com editor maduro.
O que Bevy resolve — e o que não resolve
Bevy organiza o jogo em três ideias:
- Entity — um ID opaco que agrupa componentes;
- Component — dados puros (
Transform,Velocity,Health,Player); - System — função que consulta o World e atualiza componentes a cada schedule.
Isso escala melhor do que uma hierarquia rígida de herança de classes de jogo. Novos comportamentos entram como novos componentes e sistemas, não como subclasses intermináveis.
Bevy resolve bem:
- loops de frame com schedules (
PreUpdate,Update,FixedUpdate,PostUpdate); - composição de comportamento sem herança profunda;
- renderização moderna via wgpu;
- hot-reload de assets em desenvolvimento;
- plugins reutilizáveis e arquitetura modular;
- demos técnicas, tools e jogos indie em Rust puro.
Bevy não resolve sozinho:
- pipeline de arte AAA com editores visuais maduros;
- hiring em massa de designers acostumados só a Unity/Unreal;
- física AAA completa sem crates/plugins adicionais;
- “jogo pronto” sem disciplina de estados, assets e performance;
- multiplayer autoritativo — rede continua sendo problema de protocolo e simulação.
Se você ainda está consolidando Rust básico, volte ao guia como aprender Rust e aos tutoriais antes de brigar com lifetimes dentro de systems complexos.
Conceitos que você precisa internalizar
World, Resource e Query
- World guarda entidades, componentes e resources.
- Resource é estado global (
Time,AssetServer, configuração, score). - Query seleciona entidades que possuem certo conjunto de componentes.
Pense em SQL mental: sistemas são consultas + updates sobre tabelas de componentes. Essa metáfora ajuda em entrevistas e no desenho de features.
Schedules e ordenação
Nem tudo roda “em qualquer ordem”. Input costuma vir antes da lógica; física em FixedUpdate; câmera e UI depois. Quando dois sistemas precisam de ordem, use sets explícitos ou .before / .after. Ordem implícita vira bug intermitente.
States
Menu, playing, paused e game over não devem virar if espalhado. Use estados do Bevy (ou uma máquina explícita) para spawnar/despawnar entidades e ativar sistemas só no momento certo.
Projeto inicial: arena 2D com player e inimigos
Um primeiro milestone crível:
bevy-arena/
Cargo.toml
assets/
sprites/
player.png
enemy.png
audio/
hit.ogg
src/
main.rs
components.rs
systems/
mod.rs
movement.rs
combat.rs
spawn.rs
states.rs
Dependências típicas (ajuste a versão à release estável escolhida):
[package]
name = "bevy-arena"
version = "0.1.0"
edition = "2021"
[dependencies]
bevy = { version = "0.15", features = ["default"] }
[profile.dev]
opt-level = 1
[profile.dev.package."*"]
opt-level = 3
Os opt-level no profile dev são um detalhe prático: Bevy em debug puro fica pesado; otimizar dependências sem abrir mão de rebuilds rápidos do seu crate melhora o feedback loop.
Componentes como dados
use bevy::prelude::*;
#[derive(Component)]
struct Player;
#[derive(Component)]
struct Enemy;
#[derive(Component, Deref, DerefMut)]
struct Velocity(Vec2);
#[derive(Component)]
struct Health {
atual: i32,
maximo: i32,
}
#[derive(Component)]
struct Collider {
raio: f32,
}
Evite colocar lógica pesada dentro dos componentes. Dados ficam nos componentes; regras ficam nos systems. Essa disciplina facilita testes e refatoração.
App, plugins e estado
use bevy::prelude::*;
mod components;
mod states;
mod systems;
use states::GameState;
use systems::{combat, movement, spawn};
fn main() {
App::new()
.add_plugins(DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
title: "Bevy Arena — Rust Brasil".into(),
resolution: (960., 540.).into(),
..default()
}),
..default()
}))
.init_state::<GameState>()
.add_systems(Startup, spawn::setup_camera)
.add_systems(OnEnter(GameState::Playing), spawn::spawn_arena)
.add_systems(
Update,
(
movement::player_input,
movement::aplicar_velocidade,
combat::detectar_colisao,
combat::aplicar_dano,
)
.run_if(in_state(GameState::Playing)),
)
.run();
}
O ponto importante não é o sprite: é a fronteira clara entre setup, enter-state, update e condições de execução.
Movimento com input
use bevy::prelude::*;
use crate::components::{Player, Velocity};
pub fn player_input(
teclado: Res<ButtonInput<KeyCode>>,
mut query: Query<&mut Velocity, With<Player>>,
) {
const SPEED: f32 = 220.0;
for mut velocity in &mut query {
let mut dir = Vec2::ZERO;
if teclado.pressed(KeyCode::KeyW) || teclado.pressed(KeyCode::ArrowUp) {
dir.y += 1.0;
}
if teclado.pressed(KeyCode::KeyS) || teclado.pressed(KeyCode::ArrowDown) {
dir.y -= 1.0;
}
if teclado.pressed(KeyCode::KeyA) || teclado.pressed(KeyCode::ArrowLeft) {
dir.x -= 1.0;
}
if teclado.pressed(KeyCode::KeyD) || teclado.pressed(KeyCode::ArrowRight) {
dir.x += 1.0;
}
velocity.0 = if dir.length_squared() > 0.0 {
dir.normalize() * SPEED
} else {
Vec2::ZERO
};
}
}
pub fn aplicar_velocidade(
tempo: Res<Time>,
mut query: Query<(&Velocity, &mut Transform)>,
) {
for (velocity, mut transform) in &mut query {
transform.translation.x += velocity.x * tempo.delta_secs();
transform.translation.y += velocity.y * tempo.delta_secs();
}
}
O padrão a gravar é: ler input → escrever Velocity → outro system integra no Transform. Separar “intenção” de “integração” facilita dash, knockback e status effects depois.
Nota: APIs como
delta_secs()e nomes deKeyCodevariam entre releases do Bevy. Trate os snippets como arquitetura; confirme a assinatura na documentação da versão fixada noCargo.toml.
Arquitetura que escala além do tutorial
1. Sistemas pequenos e compostos
Prefira vários systems com uma responsabilidade a um update_tudo. Isso melhora paralelismo potencial do ECS, clareza de bugs e testes.
2. Events em vez de acoplamento direto
Dano, coleta de item, death e mudança de fase funcionam melhor como events (EnemyDied, PlayerHit). Systems publicam; outros reagem. Evita queries gigantes e ordem frágil.
3. Resources para config e score
#[derive(Resource)]
struct ArenaConfig {
largura: f32,
altura: f32,
inimigos_iniciais: u32,
}
#[derive(Resource, Default)]
struct Score(u32);
Configurações hardcodadas em systems viram dívida. Resources e assets de config deixam balanceamento iterável.
4. FixedUpdate para lógica sensível
Movimento casual pode viver em Update. Combate, física e simulações que não podem depender do frame time do monitor tendem a FixedUpdate. Misturar os dois sem critério produz replays e colisões inconsistentes.
5. Despawn e ciclos de vida
Estados devem limpar entidades. Vazamento de entities entre Menu e Playing é um dos bugs mais comuns em projetos Bevy iniciantes. Ao sair de um estado, despawn explícito ou marcadores de “cleanup” evitam fantasmas invisíveis consumindo CPU.
Assets, áudio e UI sem drama
- Coloque sprites/áudios em
assets/e carregue viaAssetServer. - Trate handles como dados: spawnar antes do load terminar exige lidar com estados de carregamento.
- UI: comece com a UI do próprio Bevy para HUD (vida, score, pause). Para editores e ferramentas auxiliares, egui costuma ser mais rápido.
- Áudio: um hit e um tema já bastam no portfólio; volume e mute mostram cuidado de produto.
Se a meta também inclui desktop tool + jogo, diferencie os papéis: Bevy para a cena; toolkit GUI para painéis densos.
Bevy na web (WASM)
Compilar para browser é um diferencial de demo, não o primeiro passo. Ordem sensata:
- jogo desktop estável;
- assets leves e orçamento de tamanho;
- target WASM e ajustes de input/áudio;
- hospedagem estática da demo.
Para o contexto mais amplo de WebAssembly em Rust, veja Rust e WebAssembly e o fluxo de build com Trunk. Em Bevy, WASM é excelência de apresentação; não use isso para esconder arquitetura frágil.
Testes e qualidade em um projeto de jogo
Jogos parecem “impossíveis de testar”, mas a parte valiosa do Bevy é testável:
- funções puras de dano, score e spawn tables;
- systems rodando em
Appde teste com world controlado; - asserts sobre componentes após um update;
- golden tests de balanceamento (quantos frames até o player morrer em cenário X).
Exemplo de direção:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dano_nao_passa_de_zero() {
let mut h = Health { atual: 3, maximo: 3 };
h.atual = (h.atual - 10).max(0);
assert_eq!(h.atual, 0);
}
}
Suba depois para testes de system com entidades spawnadas. O objetivo não é 100% de cobertura gráfica; é proteger regras de jogo e regressões de estado.
Combine com o hábito geral de testes em Rust e, se o projeto virar crate público, com tooling de Cargo.
Performance: o que medir cedo
- Quantidade de entities e queries amplas demais;
- sistemas que rodam sempre sem
run_if; - alocações por frame em hot paths;
- sprites/texture atlases sem cuidado;
- logs excessivos em
Update.
Antes de micro-otimizar, meça com instruments do próprio Bevy/tracing e com um frame budget. Para serviços backend a conversa de profiling é outra — veja profiling em produção — mas a mentalidade é a mesma: evidência antes de heroísmo.
Bevy vs outras opções do ecossistema Rust
| Critério | Bevy | macroquad/ggez | Godot (GDExtension) | Unity/Unreal |
|---|---|---|---|---|
| Modelo mental | ECS data-driven | API imediata | árvore de nós + scripts | editor-first |
| Linguagem principal | Rust | Rust | GDScript/C#/Rust bindings | C#/C++ |
| Curva inicial | média | baixa | baixa/média | baixa para designers |
| Controle do frame | alto | alto | médio | médio |
| Editor visual | limitado/ecossistema | mínimo | forte | muito forte |
| Portfólio Rust “puro” | excelente | bom | híbrido | fraco como sinal Rust |
Para quem mira empresas que usam Rust em ferramentas, simulação, infra de jogos ou produtos interativos, Bevy comunica domínio de ECS, schedules e engenharia de runtime. Para quem mira estúdio clássico de games, ainda pesa demonstrar familiaridade com pipelines Unity/Unreal — Bevy sozinho não é passe livre.
Como montar um portfólio Bevy que ajuda em vagas
Um repositório forte para carreira Rust e entrevistas:
- GDD de uma página: objetivo, controles, win/lose, escopo cortado.
- Arquitetura: pasta
systems/, components claros, states. - Milestone jogável: 60–90 segundos de loop divertido > mapa enorme vazio.
- README: como rodar, versão do Bevy, screenshots/GIF, decisões e trade-offs.
- Testes das regras + checklist manual de build.
- Roadmap honesto: o que ficou de fora (multiplayer, save, editor).
Sinais que recrutadores entendem rápido:
- input e câmera estáveis;
- spawn/despawn sem vazamento;
- UI de pause/game over;
- configuração separada da lógica;
- commit history limpa.
Combine com o nicho em gamedev, o panorama de Rust para jogos e, se o ângulo for servidor de jogo, com mensageria ou redes (Quinn/QUIC) no backend — sem forçar Bevy no servidor se não houver ganho.
Erros comuns (e como evitar)
- God system que move, colide, anima e toca áudio.
- Estado global em
static mutem vez de Resource. - Ignorar FixedUpdate em combate/física.
- Não fixar versão do Bevy e copiar snippets de releases diferentes.
- Começar pelo WASM antes do loop divertido no desktop.
- Scope creep: inventário + crafting + árvore de skill no primeiro mês.
- Zero medição: otimizar systems sem saber se CPU ou GPU é o limite.
Roteiro de 7 dias para o primeiro jogo
| Dia | Entrega |
|---|---|
| 1 | Janela, câmera, sprite do player, movimento |
| 2 | Estados Menu/Playing/GameOver |
| 3 | Inimigos + spawn timer |
| 4 | Colisão e vida |
| 5 | Score, HUD, som de hit |
| 6 | Polimento: reset, dificuldade curta, README |
| 7 | Grava GIF, publica repo, escreve post-mortem de 20 linhas |
Se travar em ownership/borrowing no meio do caminho, pause o jogo e refine a base com traits e os tutoriais de concorrência. Bevy recompensa quem entende dados e lifetimes; pune quem tenta “só mais um clone” em todo lugar.
Perguntas frequentes
O que é Bevy em Rust?
É uma engine de jogos open source em Rust centrada em ECS, com plugins, assets e renderização via wgpu. Serve a jogos, demos e ferramentas interativas.
Bevy substitui Unity ou Unreal?
Não de forma geral. Substitui bem em times Rust, protótipos data-driven e produtos onde código e ECS importam mais que o editor. Em pipelines AAA com muitos designers, Unity/Unreal continuam padrão.
Preciso saber ECS antes de começar?
Não. Aprenda entidades, componentes e sistemas na prática, mas invista cedo em queries, schedules e states para não pintar um beco sem saída.
Bevy ajuda em portfólio e vagas?
Ajuda quando há jogo jogável, arquitetura legível e README com trade-offs. É um bom sinal para gamedev, tools, simulação e sistemas interativos.
Bevy roda no navegador?
Sim, via WebAssembly, com cuidados de assets, áudio e tamanho. Faça desktop primeiro.
Qual versão usar?
A estável mais recente no início do projeto, fixada explicitamente, com notes de migração à mão. Trate upgrades como trabalho de engenharia, não como cargo update cego.
Conclusão
Bevy é a porta de entrada mais convincente para jogos e protótipos sérios em Rust quando você topa pensar em ECS, schedules e dados. O caminho maduro é curto e disciplinado: fixe a versão, entregue um loop jogável, separe components/systems/states, teste as regras e documente decisões. Só então busque física avançada, WASM e multiplayer.
Para continuar, releia o panorama de Rust para jogos, o plano de carreira em gamedev, o comparativo de GUI em Rust e explore projetos práticos e vagas no ecossistema brasileiro. Bevy não é atalho mágico — é uma engine que recompensa engenharia clara.