0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rust×Bevyゲーム開発レシピ: 2D物理エンジンを使ってみよう

Posted at

Bevyを使った個人でゲーム開発を行なっている登尾(のぼりお)です。

今回はRust用の物理エンジンであるRapierを使った2Dの物理シミュレーションを実装してみましょう。

スクリーンショット 2025-08-31 9.49.27.png

クレートを追加しよう

Bevy用でかつ2D版は、以下のクレートを追加すると利用できます。

cargo add bevy_rapier2d

Bevyのプラグインに追加しよう

BevyのAppへは以下のようにプラグインを追加しましょう。

.add_plugins(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(100.0))

pixels_per_meterへ渡す値はメートルあたりピクセル数かという、物理演算での単位とBevy上での単位のスケール変換に使われます。今回の場合は1メートルあたり100ピクセル、と指定しています。

地面を準備しよう

今回の例ではボールが上から順に降ってくるものとしたいので、そのボールが貯まる地面を用意しましょう。

.add_systems(Startup, (camera, spawn_world))

というようにAppに追加し、いつもやっていることですが先にカメラを追加します。

fn camera(mut commands: Commands) {
    commands.spawn(Camera2d);
}

spawn_world関数は以下のとおりです。

const GROUND_W: f32 = 1000.0;
const GROUND_H: f32 = 10.0;
const GROUND_Y: f32 = -300.0;
const GROUND_COLOR: Color = Color::srgb(1.0, 0.7, 0.4);

fn spawn_world(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<ColorMaterial>>,
) {
    let ground_mesh = Mesh::from(Rectangle::new(GROUND_W, GROUND_H));
    commands.spawn((
        Mesh2d(meshes.add(ground_mesh).into()),
        MeshMaterial2d(materials.add(GROUND_COLOR)),
        Transform::from_xyz(0.0, GROUND_Y, -0.1),
        RigidBody::Fixed,
        Collider::cuboid(GROUND_W * 0.5, GROUND_H * 0.5),
        Friction::coefficient(0.6),
    ));
}

Mesh2d、MeshMaterial2d、TransformはBevy上のもので、それぞれ形、色、位置を渡しています。
そこに加えて、RigidBody、Collier、Frictionがbevy_rapier2d経由のもので、以下の役割があります。

  • RigidBody::Fixed
    物体を固定の状態、不動のものとして扱います。重力の影響を受けません。

  • Collider::cuboid(GROUND_W * 0.5, GROUND_H * 0.5)
    直方体の当たり判定を付けます。想定する大きさの、半分の高さ、半分の幅で指定します。(ここでは幅 GROUND_Wの高さ GROUND_Hの長方形)。当たり判定があることでの、ボールとの衝突を期待します。

  • Friction::coefficient(0.6)
    摩擦係数を 0.6 に設定しています。0 なら完全に滑り、1 以上で強い摩擦になります。

Collierについては以下にその他の形についての説明があり参考になるかと思います。
https://rapier.rs/docs/user_guides/rust/colliders/#shapes

ボールを定期的に生成させよう

spawn_ballを以下のようにシステムとして追加します。ボールの生成する間隔が短すぎる場合は Duration::from_millis の引数を調整して下さい。

.add_systems(Update, spawn_ball.run_if(on_timer(Duration::from_millis(40))))

spawn_ball関数は以下の通りです。

const BALL_R: f32 = 10.0;
const BALL_START_Y: f32 = 400.0;

fn spawn_ball(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<ColorMaterial>>,
) {
        let ball_mesh = Mesh::from(Circle::new(BALL_R));
        let mut r = rand::rng();
        let x = r.random_range(-20.0..20.0);
        let color = Color::srgb(r.random::<f32>() * 0.3 + 0.7, r.random::<f32>() * 0.3 + 0.7, 1.0);

        commands.spawn((
            Mesh2d(meshes.add(ball_mesh).into()),
            MeshMaterial2d(materials.add(color)),
            Transform::from_xyz(x, BALL_START_Y, 0.1),
            RigidBody::Dynamic,
            Collider::ball(BALL_R),
            Friction {
                coefficient: 0.9,
                combine_rule: CoefficientCombineRule::Min,
            },
            Restitution {
                coefficient: 0.4,
                combine_rule: CoefficientCombineRule::Max,
            },
            Damping {
                linear_damping: 0.01,
                angular_damping: 0.05,
            },
        ));
    }

地面を作った時との大きな違いは、

  • Collider::ballを使った球体の当たり判定をつけています。

  • Friction { coefficient: 0.9, combine_rule: CoefficientCombineRule::Min }
    接触面での摩擦係数です。

  • Restitution { coefficient: 0.4, combine_rule: CoefficientCombineRule::Max }
    反発係数(バウンドのしやすさ)です。0 だと全く弾まず、1 に近いほど弾みます。

  • Damping { linear_damping: 0.01, angular_damping: 0.05 }
    物体の速度に比例して掛かる空気抵抗的な減速をしてくれます。

  • Transformに渡すx、yとMeshMaterial2dに渡す色をランダムに決定しています。

以上のような実装によって以下のようにアニメーションされます。

また、一部掲載していないコードもありますのが、全体像は以下で確認できます。

おしまい

今回もこれまで同様以下の個人リポジトリで公開しています。

cloneした後に、

% cargo run --example bounce_balls

で挙動を確認できます。
Mesh2dの代わりにSpriteを一緒にspawnさせれば画像が動くように実装できますので、色々と遊べると思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?