Odin tiene una ventaja poco conocida: Raylib viene incluido de serie. En el directorio vendor del compilador hay bindings completos para Raylib, la librería de gráficos, audio e input para juegos 2D y 3D. No hace falta instalar nada extra ni gestionar dependencias: descarga Odin, escribe código, compila.
Este artículo cubre el camino desde el primer programa hasta un juego 2D básico con física simple, y explica por qué la combinación Odin + Raylib se ha convertido en una alternativa real a Godot con GDScript o Unity con C# para quien prefiere control sobre abstracción.
Por qué Raylib en lugar de un motor
Godot, Unity o Bevy hacen mucho por ti: gestión de escenas, editor visual, física integrada, audio con efectos, animaciones, exportación multiplataforma. A cambio, trabajas dentro de sus abstracciones y asumes su complejidad.
Raylib es lo contrario: una librería que dibuja cosas, procesa input y reproduce audio. Sin editor, sin escenas, sin sistemas de componentes. El juego es un programa que llama a funciones. Esto es más trabajo, pero también control total: sabes exactamente qué hace tu juego y por qué.
Odin encaja perfectamente en esa filosofía. Es un lenguaje que compila a código nativo, sin runtime ni GC, con un modelo de memoria manual pero ergonómico.
Configuración inicial
Con Odin instalado, crear un proyecto es tan sencillo como un directorio con un fichero:
mkdir mi-juego cd mi-juego # crear main.odin
El programa mínimo con Raylib en Odin:
package main
import rl "vendor:raylib"
main :: proc() {
rl.InitWindow(800, 600, "Mi Juego")
defer rl.CloseWindow()
for !rl.WindowShouldClose() {
rl.BeginDrawing()
rl.ClearBackground(rl.DARKBLUE)
rl.DrawText("Hola, Odin + Raylib", 250, 270, 30, rl.WHITE)
rl.EndDrawing()
}
}
Compilar y ejecutar:
odin run . -file
Un personaje con movimiento y gravedad
El siguiente paso natural es añadir un sprite que se mueva. Odin no tiene un sistema de física, así que lo implementamos nosotros. Aquí la estructura básica de un personaje con gravedad y salto:
package main
import rl "vendor:raylib"
Player :: struct {
pos: rl.Vector2,
vel: rl.Vector2,
on_floor: bool,
}
GRAVITY :: f32(800.0)
JUMP_FORCE :: f32(-400.0)
SPEED :: f32(200.0)
update_player :: proc(p: ^Player, dt: f32) {
// Gravedad
p.vel.y += GRAVITY * dt
// Movimiento horizontal
p.vel.x = 0
if rl.IsKeyDown(.LEFT) { p.vel.x = -SPEED }
if rl.IsKeyDown(.RIGHT) { p.vel.x = SPEED }
// Salto
if rl.IsKeyPressed(.SPACE) && p.on_floor {
p.vel.y = JUMP_FORCE
p.on_floor = false
}
// Actualizar posición
p.pos += p.vel * dt
// Suelo simple
if p.pos.y >= 500 {
p.pos.y = 500
p.vel.y = 0
p.on_floor = true
}
}
SOA para muchos sprites
Una de las características distintivas de Odin es el soporte nativo para Structure of Arrays (SOA). En lugar de un array de structs (la forma habitual), puedes tener un struct de arrays. Para juegos con muchos enemigos o partículas, esto mejora el rendimiento de caché considerablemente:
// Array de structs (AOS) - normal Enemies_AOS :: [100]Enemy // Struct de arrays (SOA) - mejor para caché Enemies_SOA :: #soa [100]Enemy
Cuando iteras para actualizar posiciones, accedes a enemies.pos[i] en lugar de enemies[i].pos. Los datos de posición de todos los enemigos están contiguos en memoria, lo que mejora la localidad de caché en bucles de actualización masivos.
Recursos para seguir
El tutorial de Karl Zylinski en zylinski.se es la referencia principal para Odin + Raylib: cubre desde el setup hasta un juego completo con colisiones, sprites animados y audio. El libro «Understanding the Odin Programming Language» (odinbook.com) profundiza en el lenguaje en sí.
Para entender mejor el lenguaje antes de empezar con juegos, el artículo sobre Odin: el lenguaje que enamora a los que vienen de C da el contexto necesario.
Imagen: Pexels / Rafael Minguet Delgado
