Learn Rust Coding · บทเรียน

การชนและสถานะเกม

เพิ่มกฎและเงื่อนไขชนะ

บทเรียน 4 จาก 413 ขั้นตอน

การชนและสถานะเกม เป็นบทเรียน Learn Rust Coding ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Learn Rust Coding และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 4 บทเรียน

พื้นฐานการชนแบบ AABB

การทดสอบการชนที่ง่ายที่สุดคือการตรวจสอบการทับซ้อนของกรอบล้อมรอบที่จัดแนวตามแกน (AABB) สี่เหลี่ยมสองรูปจะชนกันเมื่อทับซ้อนกันทั้งบนแกน x และแกน y

สำหรับสไปรต์ วิธีนี้ทำงานได้รวดเร็วและเพียงพอสำหรับเกม 2 มิติจำนวนมาก ก่อนที่จะเลือกใช้เอนจินฟิสิกส์เต็มรูปแบบ

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 ที่เก็บระยะครึ่งหนึ่งของขนาดหรือขนาดเต็มของแต่ละเอนทิตี จากนั้นระบบจะอ่าน transform ร่วมกับ 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();
    }
}

การอัปเดตคะแนน

เมื่อผู้เล่นเก็บไอเท็มได้ ให้แก้ไขทรัพยากรส่วนกลาง Score ด้วย ResMut

เนื่องจากทรัพยากรมีได้เพียงหนึ่งชุด ระบบใด ๆ ก็สามารถอ่านหรืออัปเดตคะแนนได้โดยไม่ต้องส่งต่อด้วยตนเอง

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

สถานะ: ภาพรวมสำคัญ

เกมจะเปลี่ยนไปมาระหว่างโหมดต่าง ๆ เช่น เมนู กำลังเล่น หยุดชั่วคราว และจบเกม Bevy จำลองสิ่งเหล่านี้ด้วย enum States ที่ลงทะเบียนผ่าน init_state

ในแต่ละช่วงเวลาจะมีสถานะที่ทำงานอยู่เพียงหนึ่งสถานะ และสามารถกำหนดให้ระบบทำงานเฉพาะในสถานะที่ระบุได้

#[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 เพื่อสร้างส่วนติดต่อผู้ใช้เมื่อเข้าสู่สถานะ หรือทำความสะอาดเมื่อออกจากสถานะ

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 ใช้ติดตามความคืบหน้า ระบบ States พร้อมด้วย run_if, NextState และ OnEnter/OnExit ช่วยจัดโครงสร้างเมนู การเล่น และสถานะจบเกม

ตอนนี้คุณมีวงจรการทำงานครบถ้วนแล้ว: สร้าง ควบคุม ตรวจจับการชน และเปลี่ยนสถานะ จงสร้างเกม Bevy ให้สมบูรณ์จากองค์ประกอบเหล่านี้

เริ่มต้นได้ฟรี

เรียนรู้ Rust ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
39
บทเรียน
144

คำถามที่พบบ่อย

บทเรียน “การชนและสถานะเกม” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การชนและสถานะเกม” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Learn Rust Coding ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การชนและสถานะเกม”

เพิ่มกฎและเงื่อนไขชนะ คุณปฏิบัติ Learn Rust Coding ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Learn Rust Coding หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Learn Rust Coding บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การชนและสถานะเกม” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Learn Rust Coding นี้ได้ไหม

ได้ บทเรียน Learn Rust Coding ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. แนวคิดแบบ ECS
  2. สร้างและเคลื่อนย้ายเอนทิตี
  3. จัดการข้อมูลนำเข้าและเวลา
  4. การชนและสถานะเกม
← กลับไปที่ Learn Rust Coding