用 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:
-
mass_properties:ROTATION_LOCKED 屬性阻止 Rapier 對玩家施加旋轉力。
-
activation:Rapier 將不移動的物體標記爲睡眠,這個設置可以防止睡眠對象觸發不必要的行爲。
-
ccd:用於在我們的玩家身上啓用碰撞檢測。稍後再詳細說明。
碰撞器負責碰撞檢測,碰撞器還定義了物體的形狀和質量 (如果我們在模擬物理,這一點很重要)。在這個例子中,我們創建了一個帶有以下屬性的基本 ColliderBundle:
-
圖形:玩家的形狀。這裏,是一個正方形。注意碰撞器圖形的 x 和 y 是實際玩家圖形的一半長。我花了一段時間才明白…
-
標誌:碰撞器上需要激活的特性。代碼裏提供的是 CONTACT_EVENTS,稍後會詳細介紹。
我們的代碼通過 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