0Pricing
Learn Rust Coding · Lección

Colisiones y estado del juego

Añada reglas y condiciones de victoria

Colisiones y estado del juego es una lección gratuita de Learn Rust Coding en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Learn Rust Coding, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Learn Rust Coding incluye 4 lecciones en total.

Conceptos básicos de las colisiones AABB

La prueba de colisión más sencilla es la superposición de cajas delimitadoras alineadas con los ejes (AABB). Dos rectángulos colisionan cuando se superponen en los ejes x e y.

Para los sprites, este método es rápido y suficiente para muchos juegos 2D antes de recurrir a un motor de física completo.

fn overlaps(a_pos: Vec2, a_size: Vec2, b_pos: Vec2, b_size: Vec2) -> bool {
    (a_pos.x - b_pos.x).abs() < (a_size.x + b_size.x) * 0.5
        && (a_pos.y - b_pos.y).abs() < (a_size.y + b_size.y) * 0.5
}

Un componente Collider

Adjunte un componente Collider que contenga las semidimensiones o el tamaño completo de cada entidad. Después, los sistemas leen el transform y el collider para comprobar las superposiciones.

Mantener el tamaño en su propio componente permite que distintas entidades compartan el mismo sistema de colisiones.

#[derive(Component)]
struct Collider {
    size: Vec2,
}

Detección de colisiones en un sistema

Para comparar un jugador con muchos obstáculos, consulte al jugador una vez e itere sobre los obstáculos. Dos consultas independientes evitan tomar prestados los mismos datos dos veces.

Cuando se produce una superposición, reaccione —infligiendo daño, rebotando o eliminando la entidad— mediante Commands o modificando componentes.

fn detect(
    player: Query<(&Transform, &Collider), With<Player>>,
    walls: Query<(&Transform, &Collider), With<Wall>>,
) {
    let (pt, pc) = player.single().unwrap();
    for (wt, wc) in &walls {
        if overlaps(pt.translation.truncate(), pc.size, wt.translation.truncate(), wc.size) {
            info!("hit a wall");
        }
    }
}

Reaccionar con eventos

En lugar de gestionar las consecuencias directamente, envíe un Event personalizado. Un sistema detecta las colisiones y emite eventos; otro los lee y aplica los efectos.

Esto desacopla la detección de la reacción y mantiene cada sistema pequeño.

#[derive(Event)]
struct CollisionEvent { entity: Entity }

fn emit(mut writer: EventWriter<CollisionEvent>, e: Entity) {
    writer.send(CollisionEvent { entity: e });
}

Lectura de eventos

Un sistema lector obtiene los eventos en cola con un EventReader y actúa sobre cada uno. Los eventos viven durante dos fotogramas, por lo que cualquier lector puede verlos.

Este flujo de publicación y suscripción es escalable: permite muchos productores y consumidores sin un acoplamiento estrecho.

fn on_hit(mut reader: EventReader<CollisionEvent>, mut commands: Commands) {
    for ev in reader.read() {
        commands.entity(ev.entity).despawn();
    }
}

Actualización de la puntuación

Cuando el jugador recoge un objeto, modifique el recurso global Score con ResMut.

Como los recursos son únicos, cualquier sistema puede leer o actualizar la puntuación sin tener que pasarla manualmente.

fn collect(mut score: ResMut<Score>, mut reader: EventReader<PickupEvent>) {
    for _ in reader.read() {
        score.0 += 10;
    }
}

Estados: visión general

Los juegos cambian entre modos: menú, juego, pausa y fin de la partida. Bevy los modela con un enum States registrado mediante init_state.

Solo hay un estado activo a la vez y los sistemas pueden configurarse para ejecutarse en estados específicos.

#[derive(States, Default, Debug, Clone, PartialEq, Eq, Hash)]
enum GameState {
    #[default]
    Menu,
    Playing,
    GameOver,
}

Registro de un estado

Añada el estado a la aplicación con init_state. Bevy realiza un seguimiento del valor actual y expone los recursos State y NextState.

Lea el estado actual con Res<State<GameState>> cuando un sistema necesite conocer el modo.

App::new()
    .add_plugins(DefaultPlugins)
    .init_state::<GameState>()
    .run();

Ejecución de sistemas en un estado

Restrinja los sistemas a un estado con la condición in_state de run_if. El movimiento y las colisiones solo se ejecutan mientras está activo Playing.

Así funciona la pausa: detenga los sistemas de juego saliendo del estado Playing y, sencillamente, dejarán de ejecutarse.

app.add_systems(
    Update,
    (drive, detect).run_if(in_state(GameState::Playing)),
);

Transición entre estados

Para cambiar de estado, establezca NextState desde cualquier sistema. Bevy aplica la transición en el siguiente límite de fotograma.

Utilice las planificaciones OnEnter y OnExit para generar la interfaz al entrar en un estado o limpiarla al salir de él.

fn lose(mut next: ResMut<NextState<GameState>>, health: Res<Health>) {
    if health.0 == 0 {
        next.set(GameState::GameOver);
    }
}

Limpieza al salir

Al salir de Playing, elimine las entidades del juego para que la siguiente ronda comience limpiamente. Asígneles una etiqueta de marcador y elimine todo lo que la contenga.

Registre la limpieza en OnExit(GameState::Playing) para que se ejecute exactamente una vez por transición.

fn cleanup(mut commands: Commands, q: Query<Entity, With<GameEntity>>) {
    for e in &q {
        commands.entity(e).despawn();
    }
}
// app.add_systems(OnExit(GameState::Playing), cleanup);

Comprobación rápida

Considere cómo pausar el juego correctamente.

Repaso: colisiones y estado del juego

Las pruebas AABB junto con un componente Collider detectan superposiciones; los eventos desacoplan la detección de la reacción y un recurso Score realiza un seguimiento del progreso. El sistema States, junto con run_if, NextState y OnEnter/OnExit, estructura los menús, el juego y el fin de la partida.

Ahora dispone del ciclo completo: generar, controlar, colisionar y realizar transiciones. Construya un juego completo de Bevy a partir de estas piezas.

Preguntas frecuentes

¿La lección «Colisiones y estado del juego» es gratis?

Sí — el texto completo de «Colisiones y estado del juego» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Learn Rust Coding, actualiza a CoddyKit PRO. El curso de Learn Rust Coding incluye 4 lecciones en total.

¿Qué aprenderé en «Colisiones y estado del juego»?

Añada reglas y condiciones de victoria Practicas Learn Rust Coding con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Learn Rust Coding?

No se requiere experiencia previa. Learn Rust Coding en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Colisiones y estado del juego»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Learn Rust Coding?

Sí. Cada lección de Learn Rust Coding incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. La mentalidad ECS
  2. Crear y mover entidades
  3. Gestionar la entrada y el tiempo
  4. Colisiones y estado del juego
← Volver a Learn Rust Coding