Ir al contenido

Desarrollo de videojuegos en Rust: Bevy, Macroquad y más

Mucha gente aprende Rust porque quiere hacer un videojuego. ¡Es un motivo estupendo! Los juegos necesitan velocidad, un uso cuidadoso de la memoria y código que no se cuelgue en plena pelea contra el jefe final, y eso es justo lo que Rust hace bien.

Esta página te da una imagen honesta: qué se construye ya con Rust, qué motor o biblioteca elegir, y las dos ideas que usa casi cualquier juego, el game loop (bucle de juego) y ECS. Después verás un primer programa en Bevy y otro en Macroquad.

¿Qué ejemplos funcionan dónde? El game loop, el pequeño mundo ECS y el ejercicio de práctica son Rust puro, así que tienen un botón “Pruébalo tú mismo” para el Playground de Rust. Bevy y Macroquad abren una ventana, así que esos ejemplos son para tu propio ordenador, con cargo run. El ejemplo de Macroquad se compiló (también para la web) mientras se escribía esta página; el de Bevy sigue los ejemplos oficiales de Bevy.

La situación real del desarrollo de juegos en Rust

Sección titulada «La situación real del desarrollo de juegos en Rust»

La web de la comunidad Are We Game Yet? (en inglés) sigue de cerca el ecosistema de juegos en Rust. Su respuesta a su propia pregunta (“¿ya podemos hacer juegos?”) es: “Casi. Tenemos las piezas; el pegamento lo pones tú”. Es un buen resumen.

Lo que ya funciona bien:

  • Se publican juegos de verdad. Tiny Glade, un juego tranquilo de construir castillos que está en Steam, y Veloren, un RPG de vóxeles de código abierto, aparecen los dos en Are We Game Yet como juegos hechos en Rust.
  • Un motor potente. Bevy tiene una comunidad grande y activa, y saca una versión nueva cada pocos meses.
  • Muchas piezas para construir. Are We Game Yet lista crates para física, audio, entrada (teclado, ratón, mando), red, interfaz y más.
  • Tu juego puede funcionar en la web. Rust compila a WebAssembly, así que muchos juegos en Rust también funcionan en un navegador.

Lo que todavía cuesta:

  • Aún no hay un “Unity de Rust”. La mayoría de los motores de Rust se manejan desde el código. Hay editores visuales (Fyrox tiene uno, y Godot puede usar Rust), pero son más jóvenes que las grandes herramientas comerciales.
  • Las cosas cambian. Bevy todavía no ha llegado a la 1.0, y cada versión trae cambios incompatibles. Un tutorial del año pasado puede que ya no compile.
  • Los tiempos de compilación. Los motores grandes tardan minutos en la primera compilación. Más abajo verás trucos para esto.

Si tu objetivo es publicar un juego 3D comercial el año que viene con un equipo de artistas, Unity, Unreal o Godot son opciones más seguras. Si quieres aprender, hacer juegos 2D, participar en game jams, crear herramientas o simulaciones, o simplemente disfrutas de Rust, es un lugar muy divertido. 🦀

Hay dos tipos de herramientas. Un motor (engine) te da toda una estructura: cómo funcionan los objetos del juego, las escenas y los recursos. Una biblioteca (o framework) te da una ventana, dibujo, sonido y entrada, y el resto lo organizas tú.

Crate Qué es Bueno para Lo que conviene saber
bevy (0.20) Un motor completo 2D y 3D construido alrededor de ECS Proyectos más grandes, 3D, aprender cómo funcionan los motores modernos El motor de Rust más conocido. Cambios incompatibles en cada versión; primera compilación larga
macroquad (0.4) Una biblioteca 2D sencilla, inspirada en raylib Tu primer juego, game jams, juegos para la web Muy pocas dependencias, compila rápido. Llamas a funciones de dibujo dentro de un bucle
ggez (0.10) Un framework 2D ligero, inspirado en LÖVE Juegos 2D con una estructura clara Implementas un trait EventHandler con update y draw
fyrox (1.0) Un motor 2D y 3D con editor de escenas Quien quiere un editor, como en Godot o Unity Llegó a la versión 1.0 en 2026. Comunidad más pequeña que la de Bevy
raylib (6.0) Bindings de Rust para la biblioteca de C raylib Quien ya conoce raylib desde C Necesita CMake y herramientas de compilación de C, porque compila la biblioteca de C (mira FFI)
godot (0.5, “gdext”) Bindings de Rust para el motor Godot 4 Usar el editor de Godot con la lógica del juego en Rust Escribes clases de Rust que Godot carga como una GDExtension

Una regla sencilla: empieza con Macroquad para tu primer juego 2D. Elige Bevy cuando quieras un motor completo y te apetezca aprender ECS. Elige Godot con gdext o Fyrox si quieres un editor para colocar las cosas de forma visual.

Casi todos los juegos son un gran bucle que se repite una y otra vez hasta que sales:

  1. Leer la entrada (teclas, ratón, mando).
  2. Actualizar el juego: mover cosas, comprobar choques, contar puntos.
  3. Dibujar la imagen nueva en la pantalla.

Cada vuelta del bucle se llama fotograma (frame). A 60 fotogramas por segundo (FPS), cada fotograma tiene unos 16 milisegundos. Pero no todos los fotogramas tardan lo mismo. Puede que tu ordenador esté ocupado, o que un fotograma tenga que cargar un archivo.

Si tu juego mueve al jugador “2 unidades en cada fotograma”, irá más rápido en un ordenador rápido y más lento en uno lento. Una solución muy usada es un paso de tiempo fijo (fixed timestep): la lógica del juego siempre avanza en pasos iguales (aquí, 10 ms), y cada fotograma ejecuta tantos pasos como quepan en el tiempo que ha pasado. El tiempo que sobra espera en un acumulador hasta el siguiente fotograma.

const STEP_MS: u32 = 10; // la lógica del juego siempre avanza de 10 en 10 ms
const SPEED: i32 = 2; // el jugador se mueve 2 unidades en cada actualización
fn main() {
// Lo que tardó de verdad cada fotograma. Un juego real lo mide con un reloj.
let frame_times = [16, 16, 45, 5, 16, 33];
let mut accumulator = 0; // tiempo que ya pasó pero aún no se ha simulado
let mut position = 0;
for (frame, elapsed) in frame_times.into_iter().enumerate() {
accumulator += elapsed;
// Ejecuta tantos pasos fijos como quepan en el tiempo que tenemos
let mut updates = 0;
while accumulator >= STEP_MS {
position += SPEED; // update(): la lógica del juego
accumulator -= STEP_MS;
updates += 1;
}
// render(): dibuja una vez por fotograma, pase lo que pase
println!("fotograma {frame}: {elapsed:>2} ms, {updates} actualización(es), jugador en {position:>2}, sobran {accumulator} ms");
}
}

Salida:

fotograma 0: 16 ms, 1 actualización(es), jugador en 2, sobran 6 ms
fotograma 1: 16 ms, 2 actualización(es), jugador en 6, sobran 2 ms
fotograma 2: 45 ms, 4 actualización(es), jugador en 14, sobran 7 ms
fotograma 3: 5 ms, 1 actualización(es), jugador en 16, sobran 2 ms
fotograma 4: 16 ms, 1 actualización(es), jugador en 18, sobran 8 ms
fotograma 5: 33 ms, 4 actualización(es), jugador en 26, sobran 1 ms
▶ Pruébalo tú mismo

Mira el fotograma 2: fue lento (45 ms), así que el juego hizo 4 actualizaciones para ponerse al día. En total pasaron 131 ms, y el juego hizo 13 actualizaciones de 10 ms. El jugador acaba en 26, da igual cómo se repartiera el tiempo entre los fotogramas. Eso hace que la física sea estable e igual en todos los ordenadores, algo que también importa para las repeticiones y los juegos en línea. Un peligro: si un fotograma es muy lento, el juego hace muchas actualizaciones para ponerse al día, y eso hace que el siguiente fotograma también sea lento. Por eso los bucles reales también limitan el número de actualizaciones por fotograma (el reloj de juego de Bevy, por ejemplo, avanza como mucho 250 ms por fotograma de forma predeterminada).

La otra forma habitual es el delta time (tiempo delta): mides los segundos desde el último fotograma y multiplicas las velocidades por ese valor (x += speed * dt). Es más sencillo, y es lo que hacen los ejemplos de Bevy y Macroquad de más abajo. Muchos motores usan las dos: delta time para la animación y un paso fijo para la física.

Qué es ECS: entidades, componentes y sistemas

Sección titulada «Qué es ECS: entidades, componentes y sistemas»

En muchos lenguajes harías una clase Player, una clase Enemy que hereda de Character, y así sucesivamente. Eso se complica rápido: ¿y si hay un enemigo que además se puede recoger? La mayoría de los motores de juegos en Rust usan ECS (Entity Component System, sistema de entidades y componentes):

  • Una entidad es solo un ID, como un número. No tiene datos ni comportamiento propios.
  • Un componente es un dato simple que le pegas a una entidad: Position, Velocity, Health. En Rust son structs o enums normales.
  • Un sistema es una función que se ejecuta sobre todas las entidades que tienen ciertos componentes. Un sistema de movimiento, por ejemplo, trabaja con todo lo que tenga a la vez Position y Velocity.

Un árbol tiene Position pero no Velocity, así que el sistema de movimiento lo salta. ¿Quieres que el árbol se mueva? Dale una Velocity. No cambias ninguna clase. Los datos y el comportamiento van por separado, y eso además encaja muy bien con las reglas de borrowing (préstamo) de Rust.

Aquí tienes un mundo ECS diminuto en Rust puro. Cada tipo de componente vive en su propio vector, y el ID de la entidad es el índice. None significa “esta entidad no tiene ese componente” (mira Option). Los nombres que se imprimen se quedan en inglés (player es el jugador, tree el árbol y arrow la flecha), porque {:<6} los alinea en columnas de 6 caracteres y “jugador” no cabría.

struct Position { x: i32, y: i32 }
struct Velocity { dx: i32, dy: i32 }
// Una entidad es solo un ID: un índice en cada lista de componentes
type Entity = usize;
#[derive(Default)]
struct World {
names: Vec<&'static str>,
positions: Vec<Option<Position>>,
velocities: Vec<Option<Velocity>>,
}
impl World {
fn spawn(&mut self, name: &'static str, pos: Option<Position>, vel: Option<Velocity>) -> Entity {
self.names.push(name);
self.positions.push(pos);
self.velocities.push(vel);
self.names.len() - 1
}
}
// Un sistema: trabaja con cada entidad que tiene a la vez Position y Velocity
fn movement_system(world: &mut World) {
for (pos, vel) in world.positions.iter_mut().zip(&world.velocities) {
if let (Some(pos), Some(vel)) = (pos, vel) {
pos.x += vel.dx;
pos.y += vel.dy;
}
}
}
// Otro sistema: imprime cada entidad que tiene Position
fn print_system(world: &World, tick: u32) {
println!("tick {tick}:");
for (id, pos) in world.positions.iter().enumerate() {
if let Some(pos) = pos {
println!(" #{id} {:<6} at ({}, {})", world.names[id], pos.x, pos.y);
}
}
}
fn main() {
let mut world = World::default();
world.spawn("player", Some(Position { x: 0, y: 0 }), Some(Velocity { dx: 1, dy: 0 }));
world.spawn("tree", Some(Position { x: 5, y: 2 }), None); // sin Velocity: nunca se mueve
world.spawn("arrow", Some(Position { x: 0, y: 3 }), Some(Velocity { dx: 3, dy: -1 }));
for tick in 1..=2 {
movement_system(&mut world);
print_system(&world, tick);
}
}

Salida:

tick 1:
#0 player at (1, 0)
#1 tree at (5, 2)
#2 arrow at (3, 2)
tick 2:
#0 player at (2, 0)
#1 tree at (5, 2)
#2 arrow at (6, 1)
▶ Pruébalo tú mismo

El árbol se queda en (5, 2) porque no tiene Velocity. Nadie escribió “los árboles no se mueven”; simplemente sale de los datos. Las bibliotecas de ECS reales son mucho más rápidas y listas que esto (guardan los componentes de forma que la CPU los lea deprisa, y ejecutan los sistemas en paralelo), pero la idea es la misma.

Bevy es el motor de Rust más conocido, y todo en él es ECS. La versión 0.20 salió en octubre de 2026. Bevy necesita la última versión estable de Rust, así que actualiza primero y después crea un proyecto:

Terminal window
rustup update
cargo new my_bevy_game
cd my_bevy_game
cargo add bevy

En Linux también necesitas algunas bibliotecas del sistema (sonido, entrada, gráficos). La guía de instalación de Bevy (en inglés) las lista para cada distribución. En Windows necesitas las Visual Studio C++ Build Tools, y en macOS las herramientas de línea de comandos de Xcode.

Este programa se basa en el ejemplo oficial 2d/move_sprite de Bevy. Dibuja un cuadrado naranja que se desliza a izquierda y derecha. (El ejemplo oficial carga una imagen; aquí se usa un cuadrado de un solo color, así que no necesitas ningún archivo de imagen).

use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins) // ventana, renderizado, entrada, audio...
.add_systems(Startup, setup) // se ejecuta una vez al principio
.add_systems(Update, sprite_movement) // se ejecuta en cada fotograma
.run();
}
// Un componente: hacia dónde se mueve esta entidad
#[derive(Component)]
enum Direction {
Left,
Right,
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
// Crea una entidad con tres componentes
commands.spawn((
Sprite::from_color(Color::srgb(1.0, 0.5, 0.2), Vec2::new(50.0, 50.0)),
Transform::from_xyz(0.0, 0.0, 0.0),
Direction::Right,
));
}
// Un sistema: se ejecuta en cada entidad que tiene un Direction Y un Transform
fn sprite_movement(time: Res<Time>, mut sprite_position: Query<(&mut Direction, &mut Transform)>) {
for (mut logo, mut transform) in &mut sprite_position {
match *logo {
Direction::Right => transform.translation.x += 150. * time.delta_secs(),
Direction::Left => transform.translation.x -= 150. * time.delta_secs(),
}
if transform.translation.x > 200. {
*logo = Direction::Left;
} else if transform.translation.x < -200. {
*logo = Direction::Right;
}
}
}

Compáralo con el pequeño mundo ECS de antes. #[derive(Component)] convierte un enum normal en un componente. commands.spawn((...)) crea una entidad con una tupla de componentes. Y Query<(&mut Direction, &mut Transform)> le pide a Bevy “todas las entidades que tengan las dos cosas”, igual que hacía nuestro movement_system con zip. time.delta_secs() es el delta time de la sección del game loop, así que el cuadrado se mueve 150 píxeles por segundo en cualquier ordenador.

Ejecútalo con cargo run. La primera compilación compila cientos de crates y puede tardar varios minutos, así que ten paciencia. Después, las recompilaciones son mucho más rápidas.

Haz que Bevy compile (y funcione) más rápido

Sección titulada «Haz que Bevy compile (y funcione) más rápido»

La guía de instalación de Bevy recomienda dos cosas. Primero, añade esto a Cargo.toml. Optimiza Bevy y tus otras dependencias, pero deja que tu propio código compile rápido:

[dependencies]
bevy = "0.20"
# Activa un poco de optimización en el perfil dev.
[profile.dev]
opt-level = 1
# Activa mucha optimización en el perfil dev para las dependencias.
[profile.dev.package."*"]
opt-level = 3

Sin esto, una compilación de depuración de un juego puede ir muy lenta: pocos fotogramas por segundo y cargas largas. Las dependencias se compilan una sola vez, así que la optimización solo la pagas en la primera compilación. (Los perfiles se explican en Rendimiento en Rust).

Segundo, mientras desarrollas, activa la feature dynamic_linking. Así Bevy se compila como una biblioteca compartida aparte, y Cargo no tiene que volver a enlazar todo Bevy dentro de tu programa con cada cambio:

Terminal window
cargo run --features bevy/dynamic_linking

Dos avisos de la guía de Bevy: en Windows, dynamic_linking solo funciona junto con los ajustes de opt-level de arriba. Y no publiques tu juego con esta feature: el juego necesitaría un archivo de biblioteca extra a su lado. Compila tu versión final sin ella. La guía también explica cómo usar un enlazador más rápido (lld o mold), que ayuda mucho en Linux.

Macroquad se siente muy distinto. No hay ECS ni un constructor de la app: el game loop lo escribes tú, y dibujas con funciones sencillas como draw_circle. Tiene muy pocas dependencias, así que una compilación desde cero tarda segundos, no minutos.

Terminal window
cargo new move_the_ball
cd move_the_ball
cargo add macroquad
[dependencies]
macroquad = "0.4"

Este pequeño juego muestra una pelota que mueves con las flechas del teclado:

use macroquad::prelude::*;
#[macroquad::main("Move the Ball")]
async fn main() {
let mut player = vec2(screen_width() / 2.0, screen_height() / 2.0);
let speed = 250.0; // píxeles por segundo
loop {
// 1. Entrada: las flechas mueven al jugador
let dt = get_frame_time(); // segundos desde el último fotograma
if is_key_down(KeyCode::Right) {
player.x += speed * dt;
}
if is_key_down(KeyCode::Left) {
player.x -= speed * dt;
}
if is_key_down(KeyCode::Down) {
player.y += speed * dt;
}
if is_key_down(KeyCode::Up) {
player.y -= speed * dt;
}
if is_key_pressed(KeyCode::Escape) {
break;
}
// 2. Mantén al jugador dentro de la pantalla
player.x = player.x.clamp(0.0, screen_width());
player.y = player.y.clamp(0.0, screen_height());
// 3. Dibuja todo lo de este fotograma
clear_background(DARKBLUE);
draw_circle(player.x, player.y, 20.0, ORANGE);
draw_text("Arrow keys to move, Esc to quit", 20.0, 30.0, 28.0, WHITE);
next_frame().await
}
}

Aquí se ven los tres pasos del game loop: entrada, actualización y dibujo. #[macroquad::main("Move the Ball")] abre una ventana con ese título (“Mueve la pelota”). main es async, pero no necesitas Tokio ni saber async: next_frame().await solo significa “muestra este fotograma y espera al siguiente”. El texto que se dibuja en pantalla dice “flechas para moverte, Esc para salir”. En Linux, el README de Macroquad indica algunos paquetes del sistema que hay que instalar antes (pkg-config libx11-dev libxi-dev libgl1-mesa-dev libasound2-dev en Ubuntu).

Tanto Macroquad como Bevy pueden compilar tu juego para el navegador como WebAssembly. Si Wasm es nuevo para ti, lee primero Rust y WebAssembly. Siempre empiezas añadiendo el target de Wasm:

Terminal window
rustup target add wasm32-unknown-unknown

Con Macroquad es muy fácil. Un solo comando genera un archivo .wasm:

Terminal window
cargo build --release --target wasm32-unknown-unknown

El archivo queda en target/wasm32-unknown-unknown/release/move_the_ball.wasm (para el ejemplo de arriba ocupaba unos 600 KB). El README de Macroquad trae un index.html corto que lo carga con un pequeño archivo de JavaScript, mq_js_bundle.js. Pon los dos archivos en una carpeta y sírvela con cualquier servidor web local, por ejemplo basic-http-server . (lo instalas con cargo install basic-http-server). Hacer doble clic en el archivo HTML normalmente no funciona, porque los navegadores bloquean la carga del archivo .wasm directamente desde el disco.

Bevy usa wasm-bindgen para crear el código de unión con JavaScript. Estos pasos están adaptados del README de ejemplos de Bevy (para el proyecto my_bevy_game de arriba):

Terminal window
cargo install wasm-bindgen-cli
cargo build --release --target wasm32-unknown-unknown
wasm-bindgen --out-dir web --target web target/wasm32-unknown-unknown/release/my_bevy_game.wasm

Esto escribe un archivo .js y otro _bg.wasm en la carpeta web; una pequeña página HTML importa el archivo .js y arranca el juego. La guía de instalación de Bevy también sugiere un perfil wasm-release con opt-level = "s" para que la descarga sea más pequeña. Las versiones web son una forma genial de compartir lo que haces en una game jam: la gente puede jugar con un clic, sin instalar nada.

Moverse una cantidad fija en cada fotograma. Con x += 5.0 en cada fotograma, el juego va el doble de rápido a 120 FPS que a 60 FPS. Multiplica por el delta time (x += speed * dt) o usa un paso de tiempo fijo.

Seguir un tutorial antiguo de Bevy. Bevy cambia su API en cada versión, así que un artículo para la 0.12 a menudo no compila con la 0.20. Comprueba qué versión usa un tutorial, y da preferencia a los ejemplos oficiales de tu versión. Cada versión también tiene una guía de migración en la web de Bevy.

Compilaciones de depuración lentas. Si tu juego de Bevy va a pocos fotogramas por segundo, seguramente olvidaste los ajustes de opt-level en Cargo.toml.

Empezar demasiado a lo grande. Un RPG de mundo abierto es un primer proyecto difícil en cualquier lenguaje. Empieza con Pong, Snake, Breakout o Flappy Bird. Termínalo, y haz el siguiente un poco más grande.

Todo juego tiene pantallas: un menú, el juego en sí, una pantalla de pausa, “game over”. Crea un enum GameState con Menu, Playing, Paused y GameOver, y un enum Input con Enter, Escape y PlayerDied. Escribe fn next_state(state: GameState, input: Input) -> GameState: Enter empieza la partida desde el menú, Escape pausa y quita la pausa, morir termina la partida, y Enter en “game over” vuelve al menú. Cualquier otra entrada no cambia nada. Pásale una lista fija de entradas e imprime cada cambio. Pista: haz match sobre la tupla (state, input), y termina con (same, _) => same.

Ver solución
#[derive(Debug, Clone, Copy)]
enum GameState {
Menu,
Playing,
Paused,
GameOver,
}
#[derive(Debug, Clone, Copy)]
enum Input {
Enter,
Escape,
PlayerDied,
}
fn next_state(state: GameState, input: Input) -> GameState {
match (state, input) {
(GameState::Menu, Input::Enter) => GameState::Playing,
(GameState::Playing, Input::Escape) => GameState::Paused,
(GameState::Paused, Input::Escape) => GameState::Playing,
(GameState::Playing, Input::PlayerDied) => GameState::GameOver,
(GameState::GameOver, Input::Enter) => GameState::Menu,
// Cualquier otra cosa: ignora la entrada y quédate donde estás
(same, _) => same,
}
}
fn main() {
use Input::*; // nos deja escribir Enter en vez de Input::Enter
let inputs = [Escape, Enter, Escape, PlayerDied, Escape, PlayerDied, Enter];
let mut state = GameState::Menu;
for input in inputs {
let new_state = next_state(state, input);
println!("{state:?} + {input:?} -> {new_state:?}");
state = new_state;
}
}

Salida:

Menu + Escape -> Menu
Menu + Enter -> Playing
Playing + Escape -> Paused
Paused + PlayerDied -> Paused
Paused + Escape -> Playing
Playing + PlayerDied -> GameOver
GameOver + Enter -> Menu
▶ Pruébalo tú mismo

Hacer match sobre una tupla reúne todos los cambios permitidos en un solo lugar, y la última rama hace que cualquier otra entrada no tenga efecto. Un jugador en pausa no puede morir, porque (Paused, PlayerDied) cae en (same, _). Bevy trae esta misma idea incorporada, con el nombre de States.

  • Rust es una opción real para hacer juegos: “casi listo”, con un motor potente (Bevy), bibliotecas sencillas (Macroquad, ggez), opciones con editor (Fyrox, Godot con gdext) y muchas piezas para construir.
  • Todo juego ejecuta un bucle: entrada, actualización, dibujo. Usa delta time o un paso de tiempo fijo para que la velocidad no dependa de los fotogramas por segundo.
  • ECS divide un juego en entidades (IDs), componentes (datos simples) y sistemas (funciones que se ejecutan sobre las entidades que tienen ciertos componentes).
  • En Bevy todo es ECS. Añade los ajustes de perfil opt-level, y usa dynamic_linking solo mientras desarrollas.
  • Macroquad es la forma más rápida de empezar en 2D: el bucle lo escribes tú y dibujas con funciones sencillas.
  • Los dos pueden compilar para el navegador con el target wasm32-unknown-unknown.

Comprueba lo aprendido

1. En ECS, ¿qué es una entidad?

2. ¿Por qué un paso de tiempo fijo hace que un juego se comporte igual en todos los ordenadores?

3. ¿Con qué ajuste de Bevy NO deberías publicar tu juego terminado?

4. Quieres hacer tu primer juego 2D pequeño con tiempos de compilación muy cortos. ¿Qué crate recomienda esta página?

Puntuación: 0 / 4

  • Are We Game Yet? (en inglés): el resumen de la comunidad sobre motores de juegos en Rust, bibliotecas de física, audio y red, y juegos hechos con Rust.
  • Bevy Quick Start: Setup (en inglés): la guía oficial para instalar Bevy, los ajustes para compilar rápido y los perfiles de versión final y de Wasm.
  • Game development in Rust with Macroquad (en inglés): un libro en línea gratuito que construye paso a paso un juego completo de naves espaciales con Macroquad.
  • The godot-rust book (en inglés): cómo escribir la lógica de un juego de Godot 4 en Rust con gdext.
  • Game Loop — Game Programming Patterns (en inglés): una explicación amable y detallada de los game loops, el delta time y los pasos de tiempo fijos.