---
title: "Zig e Raylib: Criando Jogos com Zig em 2026"
url: "https://ziglang.com.br/artigos/zig-raylib-jogos/"
markdown_url: "https://ziglang.com.br/artigos/zig-raylib-jogos.MD"
description: "Tutorial completo de game dev com Zig e Raylib. Configure o build system, crie janelas, renderize gráficos, trate input e construa um jogo Pong do zero."
date: "2026-03-23"
author: ""
---

# Zig e Raylib: Criando Jogos com Zig em 2026

Tutorial completo de game dev com Zig e Raylib. Configure o build system, crie janelas, renderize gráficos, trate input e construa um jogo Pong do zero.


Se você está procurando uma dupla moderna para desenvolvimento de jogos que combine performance nativa, controle de memória e simplicidade, **Zig + Raylib** é uma das melhores opções disponíveis em 2026. Zig oferece a velocidade de C com segurança de memória, e Raylib fornece uma API de jogos limpa e sem dependências pesadas.

Neste tutorial, vamos configurar o ambiente, entender o build system e criar um jogo Pong completo do zero. Se você já conhece a linguagem, ótimo. Se não, confira [por que aprender Zig](/artigos/por-que-aprender-zig/) antes de continuar.

## O que é Raylib?

[Raylib](https://www.raylib.com/) é uma biblioteca de programação de jogos inspirada na simplicidade de Borland BGI e XNA. Criada por Ramon Santamaria, ela é escrita em C puro e foi projetada para ser simples, sem dependências externas e multiplataforma.

Por que Raylib combina perfeitamente com Zig:

- **Interop C nativo**: Zig importa headers C sem FFI — basta `@cImport`
- **Sem runtime pesado**: ambos são leves e previsíveis
- **Build system integrado**: o [build.zig](/glossario/build-zig/) substitui CMake, Make e autotools
- **Controle de memória**: Zig dá controle total sobre alocações, ideal para game loops

## Configurando o Projeto

Primeiro, crie um novo projeto Zig:

```zig
// Terminal: zig init
// Isso cria a estrutura básica com build.zig e src/main.zig
```

### Adicionando Raylib como Dependência

O ecossistema Zig usa [build.zig.zon](/glossario/build-zig-zon/) para gerenciar dependências. Para adicionar Raylib, edite o arquivo `build.zig.zon`:

```zig
.{
    .name = "meu-jogo-zig",
    .version = "0.1.0",
    .dependencies = .{
        .raylib = .{
            .url = "https://github.com/raysan5/raylib/archive/refs/tags/5.5.tar.gz",
            .hash = "...", // Hash gerado pelo zig fetch
        },
    },
}
```

Para obter o hash correto, execute `zig fetch --save https://github.com/raysan5/raylib/archive/refs/tags/5.5.tar.gz` e o sistema de build atualizará o arquivo automaticamente.

### Configurando o build.zig

O `build.zig` precisa vincular Raylib ao seu executável:

```zig
const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const raylib_dep = b.dependency("raylib", .{
        .target = target,
        .optimize = optimize,
    });

    const exe = b.addExecutable(.{
        .name = "meu-jogo",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    exe.linkLibrary(raylib_dep.artifact("raylib"));
    exe.addIncludePath(raylib_dep.path("src"));

    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);
    const run_step = b.step("run", "Executar o jogo");
    run_step.dependOn(&run_cmd.step);
}
```

Com essa configuração, `zig build run` compila o Raylib do source, linka com seu projeto e executa o jogo — tudo em um único comando.

## Criando uma Janela

Vamos começar com o básico — abrir uma janela e renderizar um fundo:

```zig
const rl = @cImport({
    @cInclude("raylib.h");
});

pub fn main() void {
    const largura: c_int = 800;
    const altura: c_int = 600;

    rl.InitWindow(largura, altura, "Meu Jogo em Zig");
    defer rl.CloseWindow();

    rl.SetTargetFPS(60);

    while (!rl.WindowShouldClose()) {
        rl.BeginDrawing();
        defer rl.EndDrawing();

        rl.ClearBackground(rl.RAYWHITE);
        rl.DrawText("Olá, Zig + Raylib!", 250, 280, 30, rl.DARKGRAY);
    }
}
```

Note como o `defer` de Zig se encaixa perfeitamente com a API do Raylib. `defer rl.CloseWindow()` garante que a janela será fechada quando `main` terminar, e `defer rl.EndDrawing()` fecha o frame de desenho automaticamente ao final de cada iteração do loop.

## Desenhando Formas e Sprites

Raylib oferece funções simples para renderizar primitivas geométricas:

```zig
// Dentro do loop de desenho:
rl.BeginDrawing();
defer rl.EndDrawing();

rl.ClearBackground(rl.BLACK);

// Retângulo preenchido
rl.DrawRectangle(100, 100, 200, 150, rl.BLUE);

// Retângulo com bordas
rl.DrawRectangleLines(350, 100, 200, 150, rl.RED);

// Círculo
rl.DrawCircle(400, 400, 50, rl.GREEN);

// Linha
rl.DrawLine(0, 300, 800, 300, rl.YELLOW);

// Texto com posição e tamanho
rl.DrawText("Score: 42", 10, 10, 20, rl.WHITE);
```

Para carregar e renderizar sprites (texturas), use:

```zig
const textura = rl.LoadTexture("assets/personagem.png");
defer rl.UnloadTexture(textura);

// No loop de desenho:
rl.DrawTexture(textura, pos_x, pos_y, rl.WHITE);

// Com rotação e escala:
rl.DrawTextureEx(textura, .{ .x = 100, .y = 100 }, 45.0, 2.0, rl.WHITE);
```

## Tratando Input do Jogador

Raylib simplifica o tratamento de input com funções diretas:

```zig
// Teclado
if (rl.IsKeyDown(rl.KEY_W) or rl.IsKeyDown(rl.KEY_UP)) {
    jogador_y -= velocidade;
}
if (rl.IsKeyDown(rl.KEY_S) or rl.IsKeyDown(rl.KEY_DOWN)) {
    jogador_y += velocidade;
}
if (rl.IsKeyPressed(rl.KEY_SPACE)) {
    // Ação única ao pressionar (não repete enquanto segura)
    atirar();
}

// Mouse
const mouse_x = rl.GetMouseX();
const mouse_y = rl.GetMouseY();
if (rl.IsMouseButtonPressed(rl.MOUSE_BUTTON_LEFT)) {
    // Clique do mouse
}

// Gamepad
if (rl.IsGamepadAvailable(0)) {
    if (rl.IsGamepadButtonDown(0, rl.GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) {
        // Botão A do controle
    }
}
```

A diferença entre `IsKeyDown` (mantém enquanto pressionado) e `IsKeyPressed` (dispara uma vez) é crucial para jogos. Movimentação usa `IsKeyDown`, ações como pular ou atirar usam `IsKeyPressed`.

## Game Loop: O Coração do Jogo

Todo jogo segue o padrão **Update → Draw**. Em Zig com Raylib, isso fica limpo e organizado:

```zig
const Estado = struct {
    bola_x: f32,
    bola_y: f32,
    vel_x: f32,
    vel_y: f32,
    jogador_y: f32,
    cpu_y: f32,
    score_jogador: u32,
    score_cpu: u32,
};

fn atualizar(estado: *Estado) void {
    const dt = rl.GetFrameTime();

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

    // Colisão com bordas superior/inferior
    if (estado.bola_y <= 0 or estado.bola_y >= 600) {
        estado.vel_y = -estado.vel_y;
    }

    // Mover jogador com teclado
    if (rl.IsKeyDown(rl.KEY_UP)) estado.jogador_y -= 300 * dt;
    if (rl.IsKeyDown(rl.KEY_DOWN)) estado.jogador_y += 300 * dt;
}

fn desenhar(estado: *const Estado) void {
    rl.BeginDrawing();
    defer rl.EndDrawing();

    rl.ClearBackground(rl.BLACK);

    // Linha central
    rl.DrawLine(400, 0, 400, 600, rl.GRAY);

    // Raquetes
    rl.DrawRectangle(20, @intFromFloat(estado.jogador_y), 10, 80, rl.WHITE);
    rl.DrawRectangle(770, @intFromFloat(estado.cpu_y), 10, 80, rl.WHITE);

    // Bola
    rl.DrawCircle(@intFromFloat(estado.bola_x), @intFromFloat(estado.bola_y), 8, rl.WHITE);

    // Score
    const buf_jogador = std.fmt.bufPrint(&[_]u8{0} ** 16, "{d}", .{estado.score_jogador}) catch "0";
    rl.DrawText(@ptrCast(buf_jogador), 200, 20, 40, rl.WHITE);
}
```

## Detecção de Colisão

Raylib inclui funções prontas para colisão, mas entender a lógica é importante:

```zig
fn verificarColisao(bola_x: f32, bola_y: f32, raio: f32, rect_x: f32, rect_y: f32, rect_w: f32, rect_h: f32) bool {
    // Colisão círculo-retângulo (AABB)
    const ponto_mais_proximo_x = std.math.clamp(bola_x, rect_x, rect_x + rect_w);
    const ponto_mais_proximo_y = std.math.clamp(bola_y, rect_y, rect_y + rect_h);

    const dist_x = bola_x - ponto_mais_proximo_x;
    const dist_y = bola_y - ponto_mais_proximo_y;

    return (dist_x * dist_x + dist_y * dist_y) <= (raio * raio);
}

// Ou usando a função built-in do Raylib:
const colisao = rl.CheckCollisionCircleRec(
    .{ .x = bola_x, .y = bola_y },
    raio,
    .{ .x = rect_x, .y = rect_y, .width = rect_w, .height = rect_h },
);
```

## Construindo o Pong Completo

Com todos os conceitos acima, o fluxo completo do jogo fica assim:

1. **Inicialização**: criar janela, definir estado inicial
2. **Loop principal**: ler input → atualizar estado → verificar colisões → desenhar
3. **IA do oponente**: a raquete do CPU segue a bola com velocidade limitada
4. **Pontuação**: quando a bola passa de uma raquete, o oponente marca ponto
5. **Reset**: bola volta ao centro com direção aleatória após cada ponto

A IA do oponente pode ser simples — basta mover a raquete na direção da bola com uma velocidade máxima:

```zig
fn atualizarCPU(estado: *Estado, dt: f32) void {
    const centro_raquete = estado.cpu_y + 40; // metade da altura da raquete
    if (centro_raquete < estado.bola_y - 10) {
        estado.cpu_y += 250 * dt; // velocidade da CPU
    } else if (centro_raquete > estado.bola_y + 10) {
        estado.cpu_y -= 250 * dt;
    }
}
```

## Por que Zig para Game Dev?

Zig traz vantagens únicas para desenvolvimento de jogos:

- **Sem garbage collector**: frame times previsíveis, sem stuttering
- **Comptime para otimização**: tabelas de lookup, código gerado em compilação
- **Cross-compilation trivial**: `zig build -Dtarget=x86_64-windows` gera executável Windows a partir do Linux/Mac
- **Interop C perfeito**: use qualquer biblioteca C de jogos sem wrappers

Para quem busca uma engine mais completa, o [Mach Engine](/ecossistema/mach-engine/) é construído inteiramente em Zig e oferece um framework de game dev mais opinado. Se você está considerando uma carreira em game dev com Zig, veja nosso guia sobre [Zig para game dev](/carreira/zig-para-gamedev-carreira/).

## Próximos Passos

Depois de dominar o básico com Raylib, você pode expandir para:

- **Áudio**: `rl.InitAudioDevice()` e `rl.PlaySound()` para efeitos sonoros
- **Animações**: spritesheet com `DrawTextureRec` para frames individuais
- **Física**: implementar gravidade, fricção e velocidade angular
- **UI in-game**: Raylib inclui `raygui` para interfaces simples
- **Multiplayer**: sockets com a stdlib de Zig para jogos em rede

Se quiser explorar interfaces gráficas além de jogos, confira nosso artigo sobre [Zig e interfaces gráficas](/artigos/zig-gui-interfaces-graficas/). E para se aprofundar no build system, veja o glossário sobre [build.zig](/glossario/build-zig/) e [build.zig.zon](/glossario/build-zig-zon/).

## Conclusão

A combinação Zig + Raylib é ideal para quem quer criar jogos com controle total sobre performance e memória, sem a complexidade de engines como Unity ou Unreal. Zig oferece a ergonomia que C nunca teve, e Raylib oferece a simplicidade que SDL e OpenGL não entregam sozinhos. Se você quer comparar com o ecossistema de game dev em Rust — incluindo engines como Bevy e macroquad —, confira os recursos no <a href="https://rustlang.com.br" target="_blank" rel="noopener noreferrer" onclick="umami.track('portfolio-site-click', { destination: 'rustlang.com.br' })">Rust Lang Brasil</a>.

Com o que aprendeu neste tutorial, você já pode criar jogos 2D completos. O ecossistema de game dev em Zig está crescendo rapidamente, e dominar essas ferramentas agora é um investimento que vai valer a pena nos próximos anos.
