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. 🦀
¿Qué motor o biblioteca elegir?
Sección titulada «¿Qué motor o biblioteca elegir?»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.
El game loop
Sección titulada «El game loop»Casi todos los juegos son un gran bucle que se repite una y otra vez hasta que sales:
- Leer la entrada (teclas, ratón, mando).
- Actualizar el juego: mover cosas, comprobar choques, contar puntos.
- 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 msconst 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 msfotograma 1: 16 ms, 2 actualización(es), jugador en 6, sobran 2 msfotograma 2: 45 ms, 4 actualización(es), jugador en 14, sobran 7 msfotograma 3: 5 ms, 1 actualización(es), jugador en 16, sobran 2 msfotograma 4: 16 ms, 1 actualización(es), jugador en 18, sobran 8 msfotograma 5: 33 ms, 4 actualización(es), jugador en 26, sobran 1 msMira 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
PositionyVelocity.
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 componentestype 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 Velocityfn 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 Positionfn 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)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.
Tu primera app con Bevy
Sección titulada «Tu primera app con Bevy»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:
rustup updatecargo new my_bevy_gamecd my_bevy_gamecargo add bevyEn 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 Transformfn 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 = 3Sin 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:
cargo run --features bevy/dynamic_linkingDos 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.
Una ventana con Macroquad
Sección titulada «Una ventana con Macroquad»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.
cargo new move_the_ballcd move_the_ballcargo 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).
Juegos en la web (WebAssembly)
Sección titulada «Juegos en la web (WebAssembly)»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:
rustup target add wasm32-unknown-unknownCon Macroquad es muy fácil. Un solo comando genera un archivo .wasm:
cargo build --release --target wasm32-unknown-unknownEl 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):
cargo install wasm-bindgen-clicargo build --release --target wasm32-unknown-unknownwasm-bindgen --out-dir web --target web target/wasm32-unknown-unknown/release/my_bevy_game.wasmEsto 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.
Errores comunes
Sección titulada «Errores comunes»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.
Práctica
Sección titulada «Práctica»1. Estados del juego con un enum
Sección titulada «1. Estados del juego con un enum»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 -> MenuMenu + Enter -> PlayingPlaying + Escape -> PausedPaused + PlayerDied -> PausedPaused + Escape -> PlayingPlaying + PlayerDied -> GameOverGameOver + Enter -> MenuHacer 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.
Resumen
Sección titulada «Resumen»- 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 usadynamic_linkingsolo 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 que aprendiste
Sección titulada «Comprueba lo que aprendiste»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
Para leer más
Sección titulada «Para leer más»- 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.