0Pricing
Learn Rust Coding · Lektion

Kollisionen und Spielzustand

Fügen Sie Regeln und Siegbedingungen hinzu.

Kollisionen und Spielzustand ist eine kostenlose Learn Rust Coding-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Learn Rust Coding-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Learn Rust Coding-Kurs umfasst insgesamt 4 Lektionen.

Grundlagen der AABB-Kollision

Der einfachste Kollisionstest ist die Überlappung achsenparalleler Begrenzungsboxen (AABB). Zwei Rechtecke kollidieren, wenn sie sich sowohl auf der x- als auch auf der y-Achse überlappen.

Für Sprites ist diese Methode schnell und für viele 2D-Spiele ausreichend, bevor Sie eine vollständige Physik-Engine einsetzen.

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
}

Eine Collider-Komponente

Fügen Sie jeder Entität eine Collider-Komponente hinzu, die deren halbe Ausdehnungen oder vollständige Größe enthält. Systeme lesen dann Transform und Collider aus, um Überlappungen zu prüfen.

Wenn die Größe in einer eigenen Komponente gespeichert wird, können verschiedene Entitäten dasselbe Kollisionssystem verwenden.

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

Kollisionen in einem System erkennen

Um einen Spieler mit vielen Hindernissen zu vergleichen, fragen Sie den Spieler einmal ab und iterieren Sie über die Hindernisse. Zwei getrennte Abfragen vermeiden, dass dieselben Daten zweimal ausgeliehen werden.

Bei einer Überlappung reagieren Sie — etwa mit Schaden, einem Abprallen oder dem Entfernen der Entität — über Commands oder durch das Ändern von Komponenten.

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

Mit Events reagieren

Anstatt Konsequenzen direkt an dieser Stelle zu behandeln, senden Sie ein benutzerdefiniertes Event. Ein System erkennt Kollisionen und erzeugt Events, ein anderes liest sie aus und wendet die Auswirkungen an.

Dadurch werden Erkennung und Reaktion entkoppelt, und jedes System bleibt klein.

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

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

Events auslesen

Ein Lesersystem ruft ausstehende Events mit einem EventReader ab und verarbeitet jedes einzelne. Events bleiben zwei Frames lang bestehen, sodass jeder Leser sie sehen kann.

Dieser Publish-Subscribe-Ablauf ist skalierbar: Viele Erzeuger und viele Verbraucher können ohne enge Kopplung zusammenarbeiten.

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

Den Punktestand aktualisieren

Wenn der Spieler ein Pickup-Objekt einsammelt, ändern Sie die globale Score-Ressource mit ResMut.

Da Ressourcen eindeutig sind, kann jedes System den Punktestand lesen oder aktualisieren, ohne ihn manuell weiterreichen zu müssen.

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

Zustände: Der große Überblick

Spiele wechseln zwischen verschiedenen Modi — Menü, Spiel, pausiert und Game Over. Bevy bildet diese mit einer über init_state registrierten States-Enumeration ab.

Immer nur ein Zustand ist aktiv, und Systeme können so eingeschränkt werden, dass sie nur in bestimmten Zuständen ausgeführt werden.

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

Einen Zustand registrieren

Fügen Sie den Zustand mit init_state zur App hinzu. Bevy verfolgt anschließend den aktuellen Wert und stellt die Ressourcen State und NextState bereit.

Lesen Sie den aktuellen Zustand mit Res<State<GameState>> aus, wenn ein System den Modus kennen muss.

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

Systeme in einem Zustand ausführen

Beschränken Sie Systeme mit der Bedingung in_state von run_if auf einen Zustand. Bewegung und Kollision werden nur ausgeführt, solange Playing aktiv ist.

So funktioniert das Pausieren: Verlassen Sie den Zustand Playing, um die Gameplay-Systeme anzuhalten; sie werden dann einfach nicht ausgeführt.

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

Zustände wechseln

Um den Zustand zu ändern, setzen Sie NextState in einem beliebigen System. Bevy wendet den Übergang an der Grenze zum nächsten Frame an.

Verwenden Sie die Zeitpläne OnEnter und OnExit, um beim Betreten eines Zustands die UI zu erzeugen oder beim Verlassen aufzuräumen.

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

Beim Verlassen aufräumen

Entfernen Sie beim Verlassen von Playing die Gameplay-Entitäten, damit die nächste Runde in einem sauberen Zustand beginnt. Kennzeichnen Sie sie mit einem Marker und entfernen Sie alles, was ihn trägt.

Registrieren Sie die Bereinigung in OnExit(GameState::Playing), damit sie bei jedem Übergang genau einmal ausgeführt wird.

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

Kurze Prüfung

Überlegen Sie, wie sich das Gameplay sauber pausieren lässt.

Zusammenfassung: Kollisionen und Spielzustand

AABB-Tests in Verbindung mit einer Collider-Komponente erkennen Überlappungen; Events entkoppeln Erkennung und Reaktion, und eine Score-Ressource verfolgt den Fortschritt. Das States-System strukturiert mit run_if, NextState und OnEnter/OnExit Menüs, das Spiel und den Game-Over-Zustand.

Sie verfügen nun über den vollständigen Ablauf: Erzeugen, Steuern, Kollidieren und Zustandswechsel. Erstellen Sie aus diesen Bausteinen ein vollständiges Bevy-Spiel.

Häufig gestellte Fragen

Ist die Lektion „Kollisionen und Spielzustand“ kostenlos?

Ja — der vollständige Text von „Kollisionen und Spielzustand“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Learn Rust Coding-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Learn Rust Coding-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Kollisionen und Spielzustand“?

Fügen Sie Regeln und Siegbedingungen hinzu. Du übst Learn Rust Coding mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Learn Rust Coding zu starten?

Keine Vorkenntnisse erforderlich. Learn Rust Coding auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.

Wie lange dauert die Lektion „Kollisionen und Spielzustand“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Learn Rust Coding-Lektion Code schreiben und ausführen?

Ja. Jede Learn Rust Coding-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Die ECS-Denkweise
  2. Entitäten erzeugen und bewegen
  3. Eingaben und Zeit behandeln
  4. Kollisionen und Spielzustand
← Zurück zu Learn Rust Coding