Carreira em Desenvolvimento de Jogos com Rust

Guia completo sobre carreira em desenvolvimento de jogos com Rust: Bevy engine, ECS, game engines, gráficos, física e áudio. Salários, empresas, habilidades e roadmap para desenvolvedores brasileiros.

Introdução

O desenvolvimento de jogos com Rust é uma das áreas mais empolgantes e de mais rápido crescimento no ecossistema da linguagem. Embora a indústria de jogos tenha sido historicamente dominada por C++ (com Unreal Engine) e C# (com Unity), Rust está emergindo como uma alternativa poderosa, especialmente com a ascensão do Bevy Engine e o crescente interesse de estúdios por ferramentas de desenvolvimento mais seguras e performáticas.

A combinação de performance de nível C++, segurança de memória, concorrência sem data races e um ecossistema moderno de ferramentas torna Rust particularmente atrativo para desenvolvimento de game engines, ferramentas de pipeline de arte, servidores de jogos multiplayer e sistemas de física/simulação.

Para desenvolvedores brasileiros, o mercado de gamedev com Rust é ainda jovem mas com enorme potencial. O Brasil possui uma comunidade de desenvolvedores de jogos vibrante e crescente, e ser um especialista em Rust gamedev posiciona você de forma única tanto no mercado nacional quanto internacional.

Por Que Rust Para Game Development?

Performance Comparável a C++

Jogos exigem cada frame renderizado em milissegundos. Rust oferece:

  • Zero overhead abstractions: Traits e generics são resolvidos em compilação
  • Sem garbage collector: Controle preciso de alocação de memória
  • Otimização LLVM: Mesmo backend de otimização do Clang/C++
  • SIMD: Suporte a instruções SIMD para cálculos vetoriais

Segurança de Memória

Bugs de memória são uma das principais causas de crashes em jogos:

  • Sem segfaults: O compilador previne acessos inválidos de memória
  • Thread safety: Paralelismo seguro para sistemas ECS
  • Sem leaks: Recursos são liberados deterministicamente via Drop trait

Entity Component System (ECS) Nativo

O padrão ECS, que revolucionou o gamedev moderno, é naturalmente expressivo em Rust graças a traits e generics:

// O padrão ECS é idiomático em Rust
// Componentes são structs simples
struct Posicao { x: f32, y: f32 }
struct Velocidade { dx: f32, dy: f32 }
struct Vida { atual: i32, maxima: i32 }

// Sistemas são funções que operam sobre conjuntos de componentes
// O type system garante acesso seguro a dados entre sistemas paralelos

Bevy Engine: O Framework Líder

Bevy é o game engine/framework mais popular do ecossistema Rust, com uma comunidade enorme e ativa:

Exemplo: Jogo Simples com Bevy

use bevy::prelude::*;

// === Componentes ===

#[derive(Component)]
struct Jogador {
    velocidade: f32,
    vida: i32,
}

#[derive(Component)]
struct Inimigo {
    velocidade: f32,
    direcao: Vec2,
}

#[derive(Component)]
struct Projetil {
    velocidade: f32,
    direcao: Vec2,
    dano: i32,
}

#[derive(Component)]
struct Pontuacao(u32);

// === Recursos ===

#[derive(Resource)]
struct ConfigJogo {
    velocidade_jogador: f32,
    velocidade_projetil: f32,
    intervalo_spawn: f32,
}

impl Default for ConfigJogo {
    fn default() -> Self {
        ConfigJogo {
            velocidade_jogador: 300.0,
            velocidade_projetil: 500.0,
            intervalo_spawn: 2.0,
        }
    }
}

#[derive(Resource)]
struct TimerSpawn(Timer);

// === Sistemas ===

/// Sistema de setup: cria entidades iniciais
fn setup(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
) {
    // Câmera
    commands.spawn(Camera2d::default());

    // Jogador
    commands.spawn((
        Sprite {
            color: Color::srgb(0.2, 0.6, 1.0),
            custom_size: Some(Vec2::new(40.0, 40.0)),
            ..default()
        },
        Transform::from_xyz(0.0, -200.0, 0.0),
        Jogador {
            velocidade: 300.0,
            vida: 100,
        },
    ));

    // Recurso de pontuação
    commands.insert_resource(ConfigJogo::default());
    commands.insert_resource(TimerSpawn(Timer::from_seconds(
        2.0,
        TimerMode::Repeating,
    )));

    println!("Jogo inicializado!");
}

/// Sistema de movimento do jogador
fn mover_jogador(
    keyboard: Res<ButtonInput<KeyCode>>,
    time: Res<Time>,
    mut query: Query<(&Jogador, &mut Transform)>,
) {
    for (jogador, mut transform) in query.iter_mut() {
        let mut direcao = Vec3::ZERO;

        if keyboard.pressed(KeyCode::ArrowLeft) || keyboard.pressed(KeyCode::KeyA) {
            direcao.x -= 1.0;
        }
        if keyboard.pressed(KeyCode::ArrowRight) || keyboard.pressed(KeyCode::KeyD) {
            direcao.x += 1.0;
        }
        if keyboard.pressed(KeyCode::ArrowUp) || keyboard.pressed(KeyCode::KeyW) {
            direcao.y += 1.0;
        }
        if keyboard.pressed(KeyCode::ArrowDown) || keyboard.pressed(KeyCode::KeyS) {
            direcao.y -= 1.0;
        }

        if direcao.length() > 0.0 {
            direcao = direcao.normalize();
        }

        transform.translation +=
            direcao * jogador.velocidade * time.delta_secs();

        // Limitar posição à tela
        transform.translation.x = transform.translation.x.clamp(-400.0, 400.0);
        transform.translation.y = transform.translation.y.clamp(-300.0, 300.0);
    }
}

/// Sistema de disparo de projéteis
fn disparar_projetil(
    mut commands: Commands,
    keyboard: Res<ButtonInput<KeyCode>>,
    config: Res<ConfigJogo>,
    query: Query<&Transform, With<Jogador>>,
) {
    if keyboard.just_pressed(KeyCode::Space) {
        for transform in query.iter() {
            commands.spawn((
                Sprite {
                    color: Color::srgb(1.0, 1.0, 0.0),
                    custom_size: Some(Vec2::new(8.0, 16.0)),
                    ..default()
                },
                Transform::from_translation(transform.translation),
                Projetil {
                    velocidade: config.velocidade_projetil,
                    direcao: Vec2::new(0.0, 1.0),
                    dano: 25,
                },
            ));
        }
    }
}

/// Sistema de movimento dos projéteis
fn mover_projeteis(
    mut commands: Commands,
    time: Res<Time>,
    mut query: Query<(Entity, &Projetil, &mut Transform)>,
) {
    for (entity, projetil, mut transform) in query.iter_mut() {
        transform.translation.x +=
            projetil.direcao.x * projetil.velocidade * time.delta_secs();
        transform.translation.y +=
            projetil.direcao.y * projetil.velocidade * time.delta_secs();

        // Remover projéteis fora da tela
        if transform.translation.y > 400.0
            || transform.translation.y < -400.0
            || transform.translation.x > 500.0
            || transform.translation.x < -500.0
        {
            commands.entity(entity).despawn();
        }
    }
}

/// Sistema de spawn de inimigos
fn spawn_inimigos(
    mut commands: Commands,
    time: Res<Time>,
    mut timer: ResMut<TimerSpawn>,
) {
    timer.0.tick(time.delta());

    if timer.0.just_finished() {
        let x = (rand::random::<f32>() - 0.5) * 700.0;

        commands.spawn((
            Sprite {
                color: Color::srgb(1.0, 0.2, 0.2),
                custom_size: Some(Vec2::new(35.0, 35.0)),
                ..default()
            },
            Transform::from_xyz(x, 350.0, 0.0),
            Inimigo {
                velocidade: 100.0 + rand::random::<f32>() * 100.0,
                direcao: Vec2::new(0.0, -1.0),
            },
        ));
    }
}

/// Sistema de movimento dos inimigos
fn mover_inimigos(
    mut commands: Commands,
    time: Res<Time>,
    mut query: Query<(Entity, &Inimigo, &mut Transform)>,
) {
    for (entity, inimigo, mut transform) in query.iter_mut() {
        transform.translation.y +=
            inimigo.direcao.y * inimigo.velocidade * time.delta_secs();

        // Remover inimigos que saíram da tela
        if transform.translation.y < -400.0 {
            commands.entity(entity).despawn();
        }
    }
}

/// Sistema de colisão simples
fn detectar_colisoes(
    mut commands: Commands,
    projeteis: Query<(Entity, &Transform, &Projetil)>,
    inimigos: Query<(Entity, &Transform), With<Inimigo>>,
) {
    for (proj_entity, proj_transform, _projetil) in projeteis.iter() {
        for (inimigo_entity, inimigo_transform) in inimigos.iter() {
            let distancia = proj_transform
                .translation
                .distance(inimigo_transform.translation);

            if distancia < 30.0 {
                commands.entity(proj_entity).despawn();
                commands.entity(inimigo_entity).despawn();
            }
        }
    }
}

/// Ponto de entrada do jogo
fn main() {
    App::new()
        .add_plugins(DefaultPlugins.set(WindowPlugin {
            primary_window: Some(Window {
                title: "Meu Jogo Rust - Bevy".to_string(),
                resolution: (800.0, 600.0).into(),
                ..default()
            }),
            ..default()
        }))
        .add_systems(Startup, setup)
        .add_systems(
            Update,
            (
                mover_jogador,
                disparar_projetil,
                mover_projeteis,
                spawn_inimigos,
                mover_inimigos,
                detectar_colisoes,
            ),
        )
        .run();
}

Outros Frameworks e Engines

macroquad

Framework simples e minimalista, ideal para game jams e protótipos:

use macroquad::prelude::*;

#[macroquad::main("Pong Simples")]
async fn main() {
    let mut jogador_y: f32 = 300.0;
    let mut bola_x: f32 = 400.0;
    let mut bola_y: f32 = 300.0;
    let mut vel_x: f32 = 200.0;
    let mut vel_y: f32 = 150.0;
    let mut pontos: u32 = 0;

    let velocidade_paddle: f32 = 400.0;
    let tamanho_paddle: f32 = 80.0;
    let raio_bola: f32 = 8.0;

    loop {
        let dt = get_frame_time();

        // Input do jogador
        if is_key_down(KeyCode::Up) {
            jogador_y -= velocidade_paddle * dt;
        }
        if is_key_down(KeyCode::Down) {
            jogador_y += velocidade_paddle * dt;
        }
        jogador_y = jogador_y.clamp(0.0, 600.0 - tamanho_paddle);

        // Mover bola
        bola_x += vel_x * dt;
        bola_y += vel_y * dt;

        // Colisão com paredes
        if bola_y <= 0.0 || bola_y >= 600.0 {
            vel_y = -vel_y;
        }
        if bola_x >= 800.0 {
            vel_x = -vel_x;
        }

        // Colisão com paddle do jogador
        if bola_x <= 30.0
            && bola_y >= jogador_y
            && bola_y <= jogador_y + tamanho_paddle
        {
            vel_x = vel_x.abs();
            pontos += 1;
        }

        // Reset se a bola sair pela esquerda
        if bola_x < 0.0 {
            bola_x = 400.0;
            bola_y = 300.0;
            pontos = 0;
        }

        // Renderização
        clear_background(BLACK);

        // Paddle do jogador
        draw_rectangle(10.0, jogador_y, 15.0, tamanho_paddle, WHITE);

        // Bola
        draw_circle(bola_x, bola_y, raio_bola, YELLOW);

        // Linha central
        for i in 0..30 {
            draw_rectangle(
                398.0,
                i as f32 * 20.0,
                4.0,
                10.0,
                GRAY,
            );
        }

        // Pontuação
        draw_text(
            &format!("Pontos: {}", pontos),
            350.0,
            30.0,
            30.0,
            WHITE,
        );

        // FPS
        draw_text(
            &format!("FPS: {}", get_fps()),
            10.0,
            590.0,
            20.0,
            GREEN,
        );

        next_frame().await;
    }
}

wgpu: Gráficos de Baixo Nível

Para quem quer trabalhar diretamente com a GPU:

use wgpu;

/// Inicialização básica de um contexto wgpu
async fn inicializar_gpu() -> (wgpu::Device, wgpu::Queue) {
    // Criar instância wgpu
    let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
        backends: wgpu::Backends::all(),
        ..Default::default()
    });

    // Solicitar adaptador (GPU)
    let adapter = instance
        .request_adapter(&wgpu::RequestAdapterOptions {
            power_preference: wgpu::PowerPreference::HighPerformance,
            compatible_surface: None,
            force_fallback_adapter: false,
        })
        .await
        .expect("Falha ao encontrar GPU compatível");

    println!("GPU encontrada: {}", adapter.get_info().name);
    println!("Backend: {:?}", adapter.get_info().backend);

    // Criar device e queue
    let (device, queue) = adapter
        .request_device(
            &wgpu::DeviceDescriptor {
                label: Some("Meu Device"),
                required_features: wgpu::Features::empty(),
                required_limits: wgpu::Limits::default(),
                memory_hints: wgpu::MemoryHints::default(),
            },
            None,
        )
        .await
        .expect("Falha ao criar device GPU");

    (device, queue)
}

Áreas de Atuação no Gamedev

Desenvolvimento de Game Engines

Criar ou contribuir para game engines é uma das áreas mais valorizadas:

  • Rendering engines: Pipelines de renderização 2D/3D
  • Physics engines: Simulação de física com Rapier
  • Audio engines: Processamento de áudio em tempo real
  • Asset pipelines: Carregamento e processamento de assets
  • Scripting systems: Integração com linguagens de script
  • Networking: Netcode para multiplayer

Ferramentas de Pipeline

Estúdios de jogos precisam de ferramentas de produção:

  • Level editors: Editores de níveis e mapas
  • Asset converters: Conversão de formatos 3D, texturas, áudio
  • Build systems: Automação de builds e packaging
  • Profilers: Ferramentas de análise de performance
  • Testing frameworks: Testes automatizados para gameplay

Servidores de Jogos

Backend para jogos multiplayer é uma área em alta demanda:

  • Game servers: Servidores autoritativos para multiplayer
  • Matchmaking: Sistemas de matchmaking e ranking
  • Anti-cheat: Detecção de trapaças no lado do servidor
  • Analytics: Coleta e processamento de telemetria

Crates Essenciais para Gamedev

Engines e Frameworks

CrateDescrição
bevyGame engine/framework ECS completo
macroquadFramework simples para jogos 2D
ggezFramework 2D inspirado no LOVE2D
fyroxGame engine 3D com editor visual
godot-rustBindings Rust para Godot Engine

Gráficos

CrateDescrição
wgpuAPI gráfica cross-platform (Vulkan/Metal/DX12)
winitCriação de janelas e input
glamBiblioteca de matemática para games
imageCarregamento e manipulação de imagens
lyonTessellation para renderização 2D

Física e Colisão

CrateDescrição
rapierEngine de física 2D/3D
parryDetecção de colisão
nalgebraÁlgebra linear
nphysicsSimulação de física (predecessor do Rapier)

Áudio

CrateDescrição
rodioReprodução de áudio simples
cpalAcesso a dispositivos de áudio
kiraSistema de áudio para jogos
oddioÁudio 3D posicional

Networking para Games

CrateDescrição
naiaNetworking para jogos multiplayer
matchboxWebRTC peer-to-peer para jogos
quinnImplementação QUIC (UDP confiável)
laminarProtocolo de rede para jogos

Utilidades

CrateDescrição
randGeração de números aleatórios
noiseGeração procedural (Perlin, Simplex)
serdeSerialização para save games
specsECS alternativo ao Bevy
hecsECS minimalista e rápido

Empresas que Contratam

Estúdios de Jogos

  • Embark Studios: Estúdio sueco usando Rust extensivamente
  • Ready At Dawn: Agora parte da Meta, com componentes Rust
  • Foresight Mining: Simulação e visualização com Rust

Ferramentas e Engines

  • Bevy Foundation: Desenvolvimento do Bevy Engine (grants/sponsorship)
  • Dimforge: Criadores do Rapier (engine de física)
  • Fyrox: Game engine 3D em Rust
  • Ambient: Engine multiplayer em Rust

Servidores e Infraestrutura

  • Riot Games: Infraestrutura de servidores
  • Epic Games: Componentes de backend
  • Unity: Ferramentas internas e otimização
  • Roblox: Infraestrutura de plataforma

Empresas de Tecnologia para Games

  • Valve: Steam e infraestrutura de distribuição
  • Discord: Real-time communication infrastructure
  • Activision-Blizzard: Backend e anti-cheat

No Brasil

  • Estúdios indie: Crescente comunidade de gamedev brasileiro
  • Empresas de gamificação: Aplicações de gamificação empresarial
  • Consultorias: Desenvolvimento de jogos por projeto
  • Trabalho remoto: Estúdios internacionais contratam remotamente

Roadmap de Habilidades

Nível Júnior (0-12 meses)

  1. Fundamentos Rust: Ownership, traits, generics, ECS concepts
  2. Bevy básico: Setup, sprites, input, audio, cenas
  3. Matemática para games: Vetores, matrizes, trigonometria
  4. Game design básico: Loops, estados, game feel
  5. 2D primeiro: Comece com jogos 2D antes de 3D
  6. Game jams: Participe de jams para praticar

Nível Pleno (1-3 anos)

  1. Bevy avançado: Plugins, sistemas complexos, networking
  2. Gráficos: Shaders, rendering pipeline, wgpu
  3. Física: Rapier, detecção de colisão, raycasting
  4. Áudio: Sistemas de áudio posicional, mixing
  5. AI para games: Pathfinding, behavior trees, FSM
  6. Otimização: Profiling, batching, LOD, culling

Nível Sênior (3+ anos)

  1. Engine development: Arquitetura de game engines
  2. Gráficos avançados: PBR, GI, ray tracing
  3. Networking: Netcode, rollback, prediction
  4. Ferramentas: Editors, asset pipelines, build systems
  5. Liderança: Direção técnica, mentoria, arquitetura
  6. Contribuição core: Bevy, wgpu, ou engine própria

Expectativas Salariais

Brasil (CLT/PJ)

NívelFaixa Salarial (R$/mês)Observações
JúniorR$ 4.000 - R$ 8.000Gameplay programming
PlenoR$ 8.000 - R$ 16.000Engine/systems programming
SêniorR$ 16.000 - R$ 28.000Engine architecture, tech lead
LeadR$ 28.000 - R$ 40.000+Direção técnica

Remoto Internacional (USD)

NívelFaixa Salarial (USD/ano)Observações
Júnior$50.000 - $80.000Estúdios indie
Pleno$80.000 - $130.000Estúdios AA/AAA
Sênior$130.000 - $200.000Engine development
Lead/Principal$200.000 - $300.000+Big studios, tech lead

Observações

  • Salários em gamedev tendem a ser ligeiramente menores que em outras áreas de software, mas a satisfação profissional é frequentemente mais alta
  • Especialistas em engine development (gráficos, física, networking) tendem a ter os maiores salários
  • O nicho de Rust gamedev ainda é pequeno, o que significa menos vagas mas também menos competição

Projetos Práticos para o Portfólio

Jogos 2D

  1. Clone de Pong: Introdução a input, física e rendering
  2. Breakout/Arkanoid: Colisão, power-ups, sistema de pontuação
  3. Platformer: Gravidade, tiles, animação de sprites
  4. Tower Defense: AI básica, pathfinding, upgrades
  5. Roguelike: Geração procedural, inventário, turnos

Jogos 3D

  1. FPS simples: Câmera 3D, raycasting, inimigos
  2. Jogo de corrida: Física de veículos, pistas
  3. Sandbox voxel: Geração de terreno, destruição de blocos

Ferramentas

  1. Editor de níveis: Interface gráfica para criar mapas
  2. Particle system: Sistema de partículas configurável
  3. Shader playground: Ferramenta para testar shaders em tempo real

Recursos de Aprendizado

Livros e Tutoriais

  • “Hands-on Rust” (Herbert Wolverson): Gamedev com Rust passo a passo
  • “Bevy Cheatbook”: Referência prática para Bevy
  • Bevy Examples: Exemplos oficiais do Bevy no GitHub
  • “Game Programming Patterns” (Robert Nystrom): Padrões universais de gamedev

Comunidades

  • Bevy Discord: Comunidade oficial do Bevy Engine
  • r/rust_gamedev: Subreddit de gamedev com Rust
  • Rust GameDev Working Group: Grupo de trabalho oficial
  • Rust Brasil: Comunidade brasileira

Game Jams

  • Ludum Dare: Uma das maiores game jams do mundo
  • Global Game Jam: Evento presencial global
  • Bevy Jam: Game jam específica para Bevy
  • Rust Game Jam: Jam focada em jogos com Rust
  • SBGames (Brasil): Simpósio Brasileiro de Jogos

Conclusão

O desenvolvimento de jogos com Rust está em um momento especial: o ecossistema está maduro o suficiente para criar jogos reais, mas jovem o suficiente para que novos participantes possam ter impacto significativo. O Bevy Engine, em particular, é um dos projetos open source mais ativos e bem financiados do ecossistema Rust.

Próximos Passos Concretos

  1. Instale Bevy: Configure um projeto Bevy e rode os exemplos
  2. Faça o tutorial oficial: Complete o tutorial de introdução do Bevy
  3. Clone um jogo clássico: Pong, Snake ou Breakout para aprender os fundamentos
  4. Estude ECS: Entenda profundamente o padrão Entity Component System
  5. Participe de game jams: Ludum Dare, Bevy Jam e jams brasileiras
  6. Aprenda matemática de games: Vetores, matrizes, quaternions, trigonometria
  7. Explore gráficos: Shaders, wgpu, rendering pipeline
  8. Construa um jogo completo: Com menu, save/load, sons, polido
  9. Publique: itch.io, Steam ou web (via WebAssembly)
  10. Contribua para o Bevy: Issues marcadas como “good first issue”

O gamedev com Rust é uma jornada desafiadora e incrivelmente gratificante. Cada sistema que você implementa, cada bug que você resolve e cada jogo que você publica constrói habilidades transferíveis para qualquer área de programação de sistemas. Comece hoje e faça parte da revolução do gamedev com Rust.