0Pricing
Learn Rust Coding · Lekcja

Kolizje i stan gry

Doda Pan/Pani reguły i warunki zwycięstwa.

Kolizje i stan gry to bezpłatna lekcja Learn Rust Coding na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Learn Rust Coding, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Learn Rust Coding zawiera 4 lekcji w sumie.

Podstawy kolizji AABB

Najprostszy test kolizji sprawdza nakładanie się prostokątów ograniczających wyrównanych do osi (AABB). Dwa prostokąty kolidują, gdy nakładają się na siebie zarówno na osi x, jak i y.

W przypadku sprite’ów jest to szybkie i wystarczające dla wielu gier 2D, zanim sięgnie się po pełny silnik fizyki.

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
}

Komponent Collider

Dołącz komponent Collider zawierający półwymiary lub pełny rozmiar każdej encji. Systemy odczytują następnie transformację i collider, aby sprawdzać nakładanie się obiektów.

Przechowywanie rozmiaru w osobnym komponencie pozwala różnym encjom współdzielić ten sam system kolizji.

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

Wykrywanie kolizji w systemie

Aby porównać gracza z wieloma przeszkodami, pobierz gracza za pomocą zapytania raz, a następnie przeiteruj po przeszkodach. Dwa oddzielne zapytania pozwalają uniknąć dwukrotnego pożyczania tych samych danych.

Po wykryciu nakładania się obiektów zareaguj — zadaj obrażenia, odbij obiekt lub usuń encję — za pomocą Commands albo przez modyfikowanie komponentów.

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

Reagowanie za pomocą zdarzeń

Zamiast obsługiwać konsekwencje bezpośrednio, wyślij niestandardowe zdarzenie Event. Jeden system wykrywa kolizje i emituje zdarzenia, a inny je odczytuje i stosuje efekty.

Rozdziela to wykrywanie od reakcji i pozwala zachować niewielkie rozmiary poszczególnych systemów.

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

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

Odczytywanie zdarzeń

System odczytujący pobiera oczekujące zdarzenia za pomocą EventReader i reaguje na każde z nich. Zdarzenia są przechowywane przez dwie klatki, więc każdy odczytujący je system może je zobaczyć.

Taki przepływ publikowania i subskrypcji dobrze skaluje się w większych projektach: może mieć wielu producentów i wielu konsumentów bez ścisłego powiązania.

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

Aktualizowanie wyniku

Gdy gracz zbierze obiekt, zmodyfikuj globalny zasób Score za pomocą ResMut.

Ponieważ zasoby są unikatowe, każdy system może odczytywać lub aktualizować wynik bez konieczności ręcznego przekazywania go dalej.

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

Stany: ogólny obraz

Gry przechodzą między trybami — menu, rozgrywką, pauzą i ekranem końca gry. Bevy odwzorowuje je za pomocą enuma States zarejestrowanego przez init_state.

W danym momencie aktywny jest tylko jeden stan, a systemy można skonfigurować tak, aby uruchamiały się tylko w określonych stanach.

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

Rejestrowanie stanu

Dodaj stan do aplikacji za pomocą init_state. Bevy będzie wtedy śledzić bieżącą wartość i udostępni zasoby State oraz NextState.

Odczytaj bieżący stan za pomocą Res<State<GameState>>, gdy system musi znać aktualny tryb.

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

Uruchamianie systemów w danym stanie

Ogranicz systemy do danego stanu za pomocą warunku run_if i in_state. Ruch i kolizje są wykonywane tylko w stanie Playing.

Tak właśnie działa pauza: zatrzymaj systemy rozgrywki, opuszczając stan Playing, a przestaną się one uruchamiać.

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

Przechodzenie między stanami

Aby zmienić stan, ustaw NextState w dowolnym systemie. Bevy zastosuje przejście na granicy następnej klatki.

Używaj harmonogramów OnEnter i OnExit, aby tworzyć interfejs po wejściu w stan lub sprzątać po jego opuszczeniu.

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

Sprzątanie przy wyjściu

Przy opuszczaniu stanu Playing usuń encje rozgrywki, aby następna runda rozpoczęła się bez pozostałości. Oznacz je markerem i usuń wszystko, co go posiada.

Zarejestruj sprzątanie w OnExit(GameState::Playing), aby wykonywało się dokładnie raz przy każdym przejściu.

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

Szybkie sprawdzenie

Rozważ, jak poprawnie zatrzymać rozgrywkę.

Podsumowanie: kolizje i stan gry

Testy AABB wraz z komponentem Collider wykrywają nakładanie się obiektów, zdarzenia rozdzielają wykrywanie od reakcji, a zasób Score śledzi postęp. System States wraz z run_if, NextState i OnEnter/OnExit porządkuje menu, rozgrywkę i ekran końca gry.

Masz teraz pełną pętlę: tworzenie obiektów, sterowanie, kolizje i przechodzenie między stanami. Zbuduj kompletną grę w Bevy, korzystając z tych elementów.

Często zadawane pytania

Czy lekcja „Kolizje i stan gry” jest bezpłatna?

Tak — pełny tekst „Kolizje i stan gry” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Learn Rust Coding, przejdź na CoddyKit PRO. Kurs Learn Rust Coding zawiera 4 lekcji w sumie.

Co nauczysz się w „Kolizje i stan gry”?

Doda Pan/Pani reguły i warunki zwycięstwa. Ćwiczysz Learn Rust Coding z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Learn Rust Coding?

Nie wymagamy żadnego doświadczenia. Learn Rust Coding w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Kolizje i stan gry”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Learn Rust Coding?

Tak. Każda lekcja Learn Rust Coding zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Sposób myślenia ECS
  2. Tworzenie i poruszanie encjami
  3. Obsługa wejścia i czasu
  4. Kolizje i stan gry
← Powrót do Learn Rust Coding