Learn Rust Coding · Lezione

Collisioni e stato del gioco

Aggiunga regole e condizioni di vittoria.

Lezione 4 di 413 passaggi

Collisioni e stato del gioco è una lezione Learn Rust Coding gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Learn Rust Coding, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Learn Rust Coding include 4 lezioni in totale.

Nozioni di base sulle collisioni AABB

Il test di collisione più semplice consiste nel verificare la sovrapposizione di riquadri di delimitazione allineati agli assi (AABB). Due rettangoli collidono quando si sovrappongono sia sull’asse x sia sull’asse y.

Per gli sprite, questo metodo è veloce e sufficientemente preciso per molti giochi 2D, prima di ricorrere a un motore fisico 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

Assegni a ogni entità un componente Collider che contenga le semi-dimensioni o le dimensioni complete. I sistemi possono quindi leggere il transform insieme al collider per verificare le sovrapposizioni.

Mantenere le dimensioni in un componente separato consente a entità diverse di condividere lo stesso sistema di collisione.

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

Rilevare le collisioni in un sistema

Per confrontare il giocatore con molti ostacoli, esegua una query sul giocatore una sola volta e iteri sugli ostacoli. Due query separate evitano di prendere in prestito gli stessi dati due volte.

In caso di sovrapposizione, reagisca infliggendo danno, facendo rimbalzare l'entità o rimuovendola, tramite Commands oppure modificando i componenti.

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");
        }
    }
}

Reagire con gli eventi

Anziché gestire le conseguenze direttamente, invii un Event personalizzato. Un sistema rileva le collisioni e genera gli eventi; un altro li legge e applica gli effetti.

In questo modo il rilevamento è separato dalla reazione e ogni sistema rimane di dimensioni ridotte.

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

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

Leggere gli eventi

Un sistema di lettura recupera gli eventi in coda con un EventReader e agisce su ciascuno di essi. Gli eventi rimangono disponibili per due frame, quindi ogni lettore può vederli.

Questo flusso di pubblicazione e sottoscrizione è scalabile: consente di avere molti produttori e molti consumer senza uno stretto accoppiamento.

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

Aggiornare il punteggio

Quando il giocatore raccoglie un oggetto, modifichi la risorsa globale Score con ResMut.

Poiché le risorse sono uniche, qualsiasi sistema può leggere o aggiornare il punteggio senza doverlo passare manualmente.

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

Stati: il quadro generale

I giochi passano da una modalità all'altra: menu, gioco, pausa e game over. Bevy rappresenta queste modalità con un enum States registrato tramite init_state.

È attivo un solo stato alla volta e i sistemi possono essere configurati per essere eseguiti solo in stati specifici.

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

Registrare uno stato

Aggiunga lo stato all'app con init_state. Bevy tiene quindi traccia del valore corrente ed espone le risorse State e NextState.

Legga lo stato corrente con Res<State<GameState>> quando un sistema deve conoscere la modalità attiva.

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

Eseguire i sistemi in uno stato

Limiti l'esecuzione dei sistemi a uno stato usando la condizione run_if in_state. Il movimento e le collisioni vengono eseguiti solo mentre è attivo Playing.

È così che funziona la pausa: interrompa i sistemi di gioco uscendo dallo stato Playing e questi smetteranno semplicemente di essere eseguiti.

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

Cambiare stato

Per cambiare stato, imposti NextState da qualsiasi sistema. Bevy applica la transizione al confine del frame successivo.

Utilizzi le schedule OnEnter e OnExit per generare l'interfaccia quando si entra in uno stato o per eseguire la pulizia quando lo si lascia.

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

Eseguire la pulizia all'uscita

Quando si lascia Playing, rimuova le entità di gioco in modo che il round successivo inizi con una scena pulita. Le contrassegni con un marker e rimuova tutto ciò che lo contiene.

Registri la pulizia in OnExit(GameState::Playing), così verrà eseguita esattamente una volta per ogni transizione.

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);

Verifica rapida

Consideri come mettere in pausa il gioco in modo ordinato.

Riepilogo: collisioni e stato del gioco

I test AABB insieme a un componente Collider rilevano le sovrapposizioni; gli eventi separano il rilevamento dalla reazione e una risorsa Score tiene traccia dei progressi. Il sistema States, con run_if, NextState e OnEnter/OnExit, struttura menu, gioco e game over.

Ora dispone dell'intero ciclo: generare, controllare, gestire le collisioni e cambiare stato. Costruisca un gioco Bevy completo a partire da questi elementi.

Gratis per iniziare

Impara Rust con un tutor IA — gratis

Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.

Corsi
39
Lezioni
144

Domande Frequenti

La lezione «Collisioni e stato del gioco» è gratuita?

Sì — il testo completo di «Collisioni e stato del gioco» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Learn Rust Coding, passa a CoddyKit PRO. Il corso Learn Rust Coding include 4 lezioni in totale.

Cosa imparerò in «Collisioni e stato del gioco»?

Aggiunga regole e condizioni di vittoria. Eserciti Learn Rust Coding con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Learn Rust Coding?

Non è richiesta alcuna esperienza precedente. Learn Rust Coding su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Collisioni e stato del gioco»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Learn Rust Coding?

Sì. Ogni lezione Learn Rust Coding include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. La mentalità ECS
  2. Creare e muovere entità
  3. Gestire input e tempo
  4. Collisioni e stato del gioco
← Torna a Learn Rust Coding