0Pricing
Learn Rust Coding · 강의

충돌과 게임 상태

규칙과 승리 조건을 추가해 보세요.

충돌과 게임 상태은(는) CoddyKit의 무료 Learn Rust Coding 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Learn Rust Coding 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Learn Rust Coding 강의에는 총 4개의 강의가 포함되어 있습니다.

AABB 충돌 기초

가장 간단한 충돌 검사는 축에 정렬된 경계 상자(AABB)의 겹침을 확인하는 것입니다. 두 사각형이 x축과 y축 모두에서 겹치면 충돌한 것입니다.

스프라이트의 경우 전체 물리 엔진을 사용하기 전에 많은 2D 게임에서 충분히 빠르고 적절한 방법입니다.

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
}

Collider 컴포넌트

각 엔터티에 반쪽 크기 또는 전체 크기를 저장하는 Collider 컴포넌트를 추가합니다. 그러면 시스템이 변환값과 콜라이더를 함께 읽어 겹침을 검사합니다.

크기를 별도의 컴포넌트에 보관하면 서로 다른 엔터티가 동일한 충돌 시스템을 공유할 수 있습니다.

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

시스템에서 충돌 감지하기

플레이어를 여러 장애물과 비교하려면 플레이어는 한 번 쿼리하고 장애물들을 순회합니다. 서로 다른 두 쿼리를 사용하면 같은 데이터를 두 번 빌리는 일을 피할 수 있습니다.

겹침이 발생하면 Commands를 사용하거나 컴포넌트를 변경하여 피해를 주거나, 튕겨 내거나, 제거하는 등의 반응을 수행합니다.

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

이벤트로 반응하기

결과를 감지 과정 안에서 바로 처리하는 대신 사용자 지정 Event를 보냅니다. 한 시스템이 충돌을 감지하고 이벤트를 발생시키면 다른 시스템이 이벤트를 읽어 효과를 적용합니다.

이렇게 하면 감지와 반응이 분리되어 각 시스템을 작게 유지할 수 있습니다.

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

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

이벤트 읽기

리더 시스템은 EventReader로 대기 중인 이벤트를 가져와 각각 처리합니다. 이벤트는 두 프레임 동안 유지되므로 모든 리더가 이벤트를 확인할 수 있습니다.

이 발행-구독 방식은 결합도를 높이지 않고도 여러 생산자와 여러 소비자로 확장할 수 있습니다.

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

점수 업데이트하기

플레이어가 아이템을 획득하면 ResMut을 사용해 전역 Score 리소스를 변경합니다.

리소스는 하나만 존재하므로 어떤 시스템에서든 점수를 직접 전달하지 않고 읽거나 업데이트할 수 있습니다.

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

상태: 전체 그림

게임은 메뉴, 플레이 중, 일시 정지, 게임 오버와 같은 모드 사이를 이동합니다. Bevy에서는 init_state로 등록한 States 열거형으로 이러한 모드를 모델링합니다.

한 번에 하나의 상태만 활성화되며, 시스템이 특정 상태에서만 실행되도록 제한할 수 있습니다.

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

상태 등록하기

init_state를 사용해 앱에 상태를 추가합니다. 그러면 Bevy가 현재 값을 추적하고 State 및 NextState 리소스를 제공합니다.

시스템에서 현재 모드를 알아야 할 때는 Res<State<GameState>>로 현재 상태를 읽습니다.

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

상태에서 시스템 실행하기

run_if 조건과 in_state를 사용해 시스템을 특정 상태로 제한합니다. 이동과 충돌은 Playing 상태일 때만 실행됩니다.

이것이 일시 정지가 작동하는 방식입니다. Playing 상태를 벗어나 게임플레이 시스템을 멈추면 해당 시스템은 실행되지 않습니다.

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

상태 전환하기

상태를 변경하려면 어떤 시스템에서든 NextState를 설정합니다. Bevy는 다음 프레임 경계에서 전환을 적용합니다.

OnEnter 및 OnExit 일정을 사용하면 상태에 진입할 때 UI를 생성하거나 상태를 벗어날 때 정리 작업을 수행할 수 있습니다.

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

종료 시 정리하기

Playing을 벗어날 때 게임플레이 엔터티를 제거하면 다음 라운드를 깨끗한 상태로 시작할 수 있습니다. 엔터티에 표시용 태그를 붙인 다음 해당 태그가 있는 모든 엔터티를 제거합니다.

정리 작업을 OnExit(GameState::Playing)에 등록하면 전환마다 정확히 한 번 실행됩니다.

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

빠른 확인

게임플레이를 깔끔하게 일시 정지하는 방법을 생각해 보세요.

복습: 충돌과 게임 상태

AABB 검사와 Collider 컴포넌트로 겹침을 감지하고, 이벤트로 감지와 반응을 분리하며, Score 리소스로 진행 상황을 추적합니다. run_if, NextState, OnEnter/OnExit를 사용하는 States 시스템은 메뉴, 플레이, 게임 오버를 체계적으로 구성합니다.

이제 생성하고, 조작하고, 충돌하고, 전환하는 전체 흐름을 갖추었습니다. 이 구성 요소들을 활용해 완전한 Bevy 게임을 만들어 보세요.

자주 묻는 질문

“충돌과 게임 상태” 강의는 무료인가요?

네 — “충돌과 게임 상태” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Learn Rust Coding 강의 전체를 잠금 해제할 수 있습니다. Learn Rust Coding 강의에는 총 4개의 강의가 포함되어 있습니다.

“충돌과 게임 상태”에서 뭘 배우나요?

규칙과 승리 조건을 추가해 보세요. 브라우저에서 직접 실행하는 실습 코드로 Learn Rust Coding을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Learn Rust Coding을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Learn Rust Coding은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“충돌과 게임 상태” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Learn Rust Coding 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Learn Rust Coding 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. ECS 사고방식
  2. 엔터티 생성하고 이동하기
  3. 입력과 시간 처리하기
  4. 충돌과 게임 상태
← Learn Rust Coding(으)로 돌아가기