用 Rust 開發遊戲 - 3 地面和重力

現在我們有了一個窗口,並在屏幕上繪製了一個角色,是時候讓我們的角色加入一些特徵了。本文將解釋當玩家跳躍的時候,如何添加重力將玩家拉向地面,並使其在接觸地面時停止。

理論

我們的最終目標是實現真實的運動,這是一個很複雜的問題。我們需要一個方法:

爲了實現這個功能,我們將引入一個物理庫:Rapier。Rapier 讓我們能夠輕鬆地模擬重力,並處理碰撞檢測 (檢測我們的玩家何時在空中或接觸到一個表面)。

加入重力

第一步:向 Cargo.toml 中添加 bevy_rapier2d 庫:

[dependencies]
bevy = "0.5"
bevy_rapier2d = "0.11.0"

第二步:在我們的應用程序中註冊 Rapier 插件:

// main.rs
use bevy_rapier2d::prelude::*;
// ...
    App::build()
        // ...
        .add_plugin(RapierPhysicsPlugin::<NoUserData>::default())

第三步:向玩家添加碰撞器和剛體組件:

fn spawn_player(mut commands: Commands, mut materials: ResMut<Assets<ColorMaterial>>) {
    let rigid_body = RigidBodyBundle {
        mass_properties: RigidBodyMassPropsFlags::ROTATION_LOCKED.into(),
        activation: RigidBodyActivation::cannot_sleep(),
        ccd: RigidBodyCcd { ccd_enabled: true, ..Default::default() },
        ..Default::default()
    };
    let collider = ColliderBundle {
        shape: ColliderShape::cuboid(0.5, 0.5),
        flags: ColliderFlags {
            active_events: ActiveEvents::CONTACT_EVENTS,
            ..Default::default()
        },
        ..Default::default()
    };
    commands
        .spawn_bundle(SpriteBundle {
            material: materials.add(Color::rgb(0.7, 0.7, 0.7).into()),
            sprite: Sprite::new(Vec2::new(1.0, 1.0)),
            ..Default::default()
        })
        .insert_bundle(rigid_body)
        .insert_bundle(collider)
        .insert(RigidBodyPositionSync::Discrete)
        .insert(Player);
}

這裏發生了很多事情,讓我們解釋一下都發生了什麼。

剛體負責實體的動力學和運動學 (運動和或由力產生的運動)。在本例中,我們使用這些屬性創建了一個基本的 RigidBodyBundle:

碰撞器負責碰撞檢測,碰撞器還定義了物體的形狀和質量 (如果我們在模擬物理,這一點很重要)。在這個例子中,我們創建了一個帶有以下屬性的基本 ColliderBundle:

我們的代碼通過 RigidBodyPositionSync::Discrete 組件將剛體和碰撞器綁定到我們的玩家身上。

如果你在你的終端運行 cargo run,你應該會看到我們的玩家掉進窗口底部的深淵。

地面

讓我們在玩家下方添加一個地面:

// ...
.add_startup_stage("floor_setup", SystemStage::single(spawn_floor.system()))
// ...
fn spawn_floor(mut commands: Commands, mut materials: ResMut<Assets<ColorMaterial>>) {
    let width = 10.;
    let height = 1.;
    let rigid_body = RigidBodyBundle {
        position: Vec2::new(0.0, -2.).into(),
        body_type: RigidBodyType::Static,
        ..Default::default()
    };
    let collider = ColliderBundle {
        shape: ColliderShape::cuboid(width / 2, height / 2),
        ..Default::default()
    };
    commands
        .spawn_bundle(SpriteBundle {
            material: materials.add(Color::rgb(0.7, 0.7, 0.7).into()),
            sprite: Sprite::new(Vec2::new(width, height)),
            ..Default::default()
        })
        .insert_bundle(rigid_body)
        .insert_bundle(collider)
        .insert(RigidBodyPositionSync::Discrete);
}

如果你運行 cargo run,你應該看到我們的玩家掉在地上,並呆在那裏。

這段代碼與另一段代碼非常相似。一個區別是剛體的 body_type 屬性設置爲 RigidBodyType::Static。這告訴 Rapier 我們的地面永遠不會移動。

本文翻譯自:

https://dev.to/sbelzile/making-games-in-rust-part-3-floors-and-gravity-3lag

coding 到燈火闌珊 專注於技術分享,包括 Rust、Golang、分佈式架構、雲原生等。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/1DwqNVfCu2O23Sj3ee4q1g