コンテンツにスキップ

Rustのゲーム開発:Bevy・Macroquadほか

ゲームを作りたくてRustを学び始める人はたくさんいます。すばらしい理由です! ゲームには速さと、メモリの慎重な使い方と、ボス戦の途中でクラッシュしないコードが必要です。そしてそれは、まさにRustが得意とすることです。

このページでは、ありのままの姿をお見せします。Rustですでにどんなものが作られているのか、どのエンジンやライブラリを選べばいいのか、そしてほとんどのゲームが使う2つの考え方、ゲームループとECSです。そのあと、BevyとMacroquadで最初のプログラムを見ていきます。

どの例がどこで動く? ゲームループ、小さなECSの世界、そして練習問題はふつうのRustなので、Rust Playgroundで動かせる「▶ 実際に試してみよう」ボタンがあります。BevyとMacroquadはウィンドウを開くので、それらの例は自分のパソコンで cargo run して試すためのものです。Macroquadの例はこのページを書くときに実際にコンパイルしました(Web向けにも)。Bevyの例はBevyの公式のサンプルに沿っています。

コミュニティのサイトAre We Game Yet?(英語)は、Rustのゲームのエコシステムを追いかけています。サイト名の問いに対する答えは「Almost. We have the blocks, bring your own glue.」(もう少し。部品はそろっているから、つなぎは自分で持ってきて)です。うまいまとめだと思います。

今の時点でよいところ:

  • 本物のゲームがリリースされています。 Steamで配信されている、のんびりお城を作るゲームのTiny Gladeと、オープンソースのボクセルRPGのVelorenは、どちらもAre We Game YetにRustのゲームとして載っています。
  • 強力なエンジンがあります。 Bevyには大きく活発なコミュニティがあり、数か月ごとに新しいリリースが出ます。
  • 部品がたくさんあります。 Are We Game Yetには、物理演算、オーディオ、入力、ネットワーク、UIなどのクレートが並んでいます。
  • ゲームをWebでも動かせます。 RustはWebAssemblyにコンパイルできるので、多くのRustのゲームはブラウザでも動きます。

まだ大変なところ:

  • 「RustのUnity」はまだありません。 Rustのエンジンのほとんどはコードが中心です。ビジュアルエディタもあります(Fyroxにはエディタがあり、GodotではRustを使えます)が、大手の商用ツールと比べるとまだ若いです。
  • どんどん変わります。 Bevyはまだ1.0より前で、リリースのたびに破壊的変更があります。去年のチュートリアルは、もうコンパイルできないかもしれません。
  • コンパイル時間。 大きなエンジンは、最初のビルドに数分かかります。対策はこのページの後半で紹介します。

アーティストのチームと一緒に来年商用の3Dゲームを出すのが目標なら、Unity、Unreal、Godotのほうが安全です。学ぶため、2Dゲーム、ゲームジャム、ツールやシミュレーションを作るため、あるいは単にRustが好きだからというのなら、とても楽しい場所です。🦀

どのエンジン・ライブラリを選ぶ?

Section titled “どのエンジン・ライブラリを選ぶ?”

道具には2種類あります。エンジンは全体の構造を用意してくれます。ゲームのオブジェクト、シーン、アセットがどう動くかまで決まっています。ライブラリ(またはフレームワーク)は、ウィンドウ、描画、サウンド、入力を用意してくれて、残りは自分で組み立てます。

クレート どんなものか 向いていること 知っておきたいこと
bevy(0.20) ECSを中心に作られた2D・3Dの本格的なエンジン 大きめのプロジェクト、3D、最近のエンジンのしくみを学ぶこと いちばん有名なRustのエンジン。リリースごとに破壊的変更があり、最初のビルドが長い
macroquad(0.4) raylibに影響を受けたシンプルな2Dライブラリ はじめてのゲーム、ゲームジャム、Webゲーム 依存クレートがとても少なく、ビルドが速い。ループの中で描画関数を呼ぶ
ggez(0.10) LÖVEに影響を受けた軽量な2Dフレームワーク 構造がはっきりした2Dゲーム update と draw を持つ EventHandler トレイトを実装する
fyrox(1.0) シーンエディタ付きの2D・3Dエンジン GodotやUnityのようなエディタがほしい人 2026年にバージョン1.0になった。コミュニティはBevyより小さい
raylib(6.0) CのライブラリraylibへのRustバインディング Cでraylibを使ったことがある人 Cのライブラリをビルドするので、CMakeとCのビルドツールが必要(FFIを参照)
godot(0.5、「gdext」) Godot 4エンジン用のRustバインディング Godotのエディタを使いつつ、ゲームのロジックをRustで書くこと GodotがGDExtensionとして読み込むRustのクラスを書く

シンプルなルール: はじめての2DゲームならMacroquadから始めましょう。本格的なエンジンがほしくて、ECSを学ぶのも楽しめるならBevyです。エディタで見ながら物を配置したいなら、Godot + gdextかFyroxを選びましょう。

ほとんどすべてのゲームは、終了するまで何度もくり返し実行される、1つの大きなループです。

  1. 入力を読む(キー、マウス、コントローラー)。
  2. ゲームを更新する:物を動かし、衝突を調べ、点数を数えます。
  3. 新しい絵を画面に描く。

ループの1回をフレームと呼びます。1秒間に60フレーム(60 FPS)なら、1フレームの持ち時間は約16ミリ秒です。でも、すべてのフレームが同じ時間で終わるわけではありません。パソコンが忙しいこともあれば、あるフレームでファイルを読み込む必要があることもあります。

ゲームがプレイヤーを「毎フレーム2ずつ」動かすと、速いパソコンでは速く、遅いパソコンでは遅く動いてしまいます。よく使われる解決策が固定タイムステップ(fixed timestep)です。ゲームのロジックはいつも同じ幅(ここでは10ミリ秒)ずつ進み、各フレームでは、経過した時間に収まるだけのステップを実行します。余った時間は、次のフレームまでアキュムレータ(accumulator)にためておきます。

const STEP_MS: u32 = 10; // ゲームのロジックはいつも10ミリ秒ずつ進む
const SPEED: i32 = 2; // プレイヤーは1回の更新で2だけ動く
fn main() {
// 各フレームに実際にかかった時間。本物のゲームでは時計で計る
let frame_times = [16, 16, 45, 5, 16, 33];
let mut accumulator = 0; // 経過したけれど、まだシミュレーションしていない時間
let mut position = 0;
for (frame, elapsed) in frame_times.into_iter().enumerate() {
accumulator += elapsed;
// 手元の時間に収まるだけ、固定のステップを実行する
let mut updates = 0;
while accumulator >= STEP_MS {
position += SPEED; // update():ゲームのロジック
accumulator -= STEP_MS;
updates += 1;
}
// render():何が起きても、描画は1フレームに1回
println!("frame {frame}: {elapsed:>2} ms, {updates} update(s), player at {position:>2}, {accumulator} ms left over");
}
}

実行結果:

frame 0: 16 ms, 1 update(s), player at 2, 6 ms left over
frame 1: 16 ms, 2 update(s), player at 6, 2 ms left over
frame 2: 45 ms, 4 update(s), player at 14, 7 ms left over
frame 3: 5 ms, 1 update(s), player at 16, 2 ms left over
frame 4: 16 ms, 1 update(s), player at 18, 8 ms left over
frame 5: 33 ms, 4 update(s), player at 26, 1 ms left over
▶ 実際に試してみよう

フレーム2を見てください。このフレームは遅かった(45ミリ秒)ので、ゲームは追いつくために4回更新しています。全部で131ミリ秒が経過し、ゲームは10ミリ秒の更新を13回実行しました。時間がどんなふうにフレームに分かれても、プレイヤーは最後に26の位置にいます。そのため物理演算が安定し、どのパソコンでも同じ動きになります。これはリプレイやオンラインゲームでも大切です。ひとつ危険なのは、あるフレームがとても遅いと、追いつくためにたくさん更新して、次のフレームまで遅くなってしまうことです。そのため本物のループでは、1フレームあたりの更新回数に上限も設けます(たとえばBevyのゲーム時計は、標準では1フレームで最大250ミリ秒しか進みません)。

もうひとつのよくある方法がデルタタイム(delta time)です。前のフレームからの秒数を計り、速さにそれを掛けます(x += speed * dt)。こちらのほうがシンプルで、下のBevyとMacroquadの例もこの方法を使っています。多くのエンジンは両方を使います。アニメーションにはデルタタイム、物理演算には固定ステップ、という具合です。

ECSとは:エンティティ、コンポーネント、システム

Section titled “ECSとは:エンティティ、コンポーネント、システム”

多くの言語では、Player クラスを作り、Character を継承した Enemy クラスを作り……と進めていくでしょう。でも、これはすぐにややこしくなります。拾うこともできる敵はどうしましょう? そこでRustのゲームエンジンのほとんどは、代わりにECS(Entity Component System)を使います。

  • エンティティ(entity)は、番号のようなただのIDです。それ自身はデータも振る舞いも持ちません。
  • コンポーネント(component)は、エンティティに付けるただのデータです。Position、Velocity、Health などです。Rustではふつうの構造体や列挙型です。
  • システム(system)は、特定のコンポーネントを持つすべてのエンティティに対して実行される関数です。たとえば移動のシステムは、Position と Velocity の両方を持つものすべてを処理します。

木は Position を持っていますが、Velocity は持っていないので、移動のシステムは木を飛ばします。木を動かしたい? それなら Velocity を付けるだけです。クラスを書き換える必要はありません。データと振る舞いが分かれていて、これはRustの借用のルールともよく合います。

ふつうのRustで作った、小さなECSの世界を見てみましょう。コンポーネントの種類ごとに専用のベクタがあり、エンティティのIDはそのインデックスです。None は「このエンティティはそのコンポーネントを持っていない」という意味です(Optionを参照)。

struct Position { x: i32, y: i32 }
struct Velocity { dx: i32, dy: i32 }
// エンティティはただのID:すべてのコンポーネントのリストへのインデックス
type Entity = usize;
#[derive(Default)]
struct World {
names: Vec<&'static str>,
positions: Vec<Option<Position>>,
velocities: Vec<Option<Velocity>>,
}
impl World {
fn spawn(&mut self, name: &'static str, pos: Option<Position>, vel: Option<Velocity>) -> Entity {
self.names.push(name);
self.positions.push(pos);
self.velocities.push(vel);
self.names.len() - 1
}
}
// システム:Position と Velocity の「両方」を持つすべてのエンティティを処理する
fn movement_system(world: &mut World) {
for (pos, vel) in world.positions.iter_mut().zip(&world.velocities) {
if let (Some(pos), Some(vel)) = (pos, vel) {
pos.x += vel.dx;
pos.y += vel.dy;
}
}
}
// もうひとつのシステム:Position を持つすべてのエンティティを表示する
fn print_system(world: &World, tick: u32) {
println!("tick {tick}:");
for (id, pos) in world.positions.iter().enumerate() {
if let Some(pos) = pos {
println!(" #{id} {:<6} at ({}, {})", world.names[id], pos.x, pos.y);
}
}
}
fn main() {
let mut world = World::default();
world.spawn("player", Some(Position { x: 0, y: 0 }), Some(Velocity { dx: 1, dy: 0 }));
world.spawn("tree", Some(Position { x: 5, y: 2 }), None); // Velocity がない:決して動かない
world.spawn("arrow", Some(Position { x: 0, y: 3 }), Some(Velocity { dx: 3, dy: -1 }));
for tick in 1..=2 {
movement_system(&mut world);
print_system(&world, tick);
}
}

実行結果:

tick 1:
#0 player at (1, 0)
#1 tree at (5, 2)
#2 arrow at (3, 2)
tick 2:
#0 player at (2, 0)
#1 tree at (5, 2)
#2 arrow at (6, 1)
▶ 実際に試してみよう

名前は {:<6} で幅をそろえて表示しているので、英語のままにしています(日本語の文字は画面上で2文字分の幅になり、そろわなくなるためです)。

木は Velocity を持っていないので、(5, 2) にとどまります。誰も「木は動かない」とは書いていません。データからそうなるだけです。本物のECSライブラリはこれよりずっと速く賢くできています(CPUがすばやく読めるようにコンポーネントを並べて保存し、システムを並列に実行します)が、考え方は同じです。

Bevy(英語)はいちばん有名なRustのエンジンで、すべてがECSでできています。バージョン0.20は2026年10月に出ました。Bevyには最新のstable版のRustが必要なので、まずアップデートしてから、プロジェクトを作りましょう。

Terminal window
rustup update
cargo new my_bevy_game
cd my_bevy_game
cargo add bevy

Linuxでは、いくつかのシステムライブラリ(サウンド、入力、グラフィックス)も必要です。Bevyのセットアップガイド(英語)に、ディストリビューションごとの一覧があります。WindowsではVisual StudioのC++ビルドツール、macOSではXcodeのコマンドラインツールが必要です。

このプログラムは、Bevyの公式サンプル 2d/move_sprite をもとにしています。オレンジ色の四角が左右に滑るように動きます(公式のサンプルは画像を読み込みますが、ここでは画像ファイルがいらないように、ただの色付きの四角を使っています)。

use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins) // ウィンドウ、描画、入力、オーディオ……
.add_systems(Startup, setup) // 最初に1回だけ実行される
.add_systems(Update, sprite_movement) // 毎フレーム実行される
.run();
}
// コンポーネント:このエンティティがどちらに動いているか
#[derive(Component)]
enum Direction {
Left,
Right,
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
// 3つのコンポーネントを持つエンティティを1つ作る
commands.spawn((
Sprite::from_color(Color::srgb(1.0, 0.5, 0.2), Vec2::new(50.0, 50.0)),
Transform::from_xyz(0.0, 0.0, 0.0),
Direction::Right,
));
}
// システム:Direction と Transform の「両方」を持つすべてのエンティティで実行される
fn sprite_movement(time: Res<Time>, mut sprite_position: Query<(&mut Direction, &mut Transform)>) {
for (mut logo, mut transform) in &mut sprite_position {
match *logo {
Direction::Right => transform.translation.x += 150. * time.delta_secs(),
Direction::Left => transform.translation.x -= 150. * time.delta_secs(),
}
if transform.translation.x > 200. {
*logo = Direction::Left;
} else if transform.translation.x < -200. {
*logo = Direction::Right;
}
}
}

上の小さなECSの世界と比べてみてください。#[derive(Component)] は、ふつうの列挙型をコンポーネントにします。commands.spawn((...)) は、コンポーネントのタプルを持つエンティティを作ります。そして Query<(&mut Direction, &mut Transform)> はBevyに「両方を持つすべてのエンティティ」を頼んでいます。私たちの movement_system が zip でやっていたのと同じです。time.delta_secs() はゲームループのセクションで見たデルタタイムなので、どのパソコンでも四角は1秒間に150ピクセル動きます。

cargo run で実行します。最初のビルドでは数百個のクレートをコンパイルするので数分かかることがあります。気長に待ちましょう。そのあとのビルドはずっと速くなります。

Bevyのコンパイル(と実行)を速くする

Section titled “Bevyのコンパイル(と実行)を速くする”

Bevyのセットアップガイドは2つのことをすすめています。1つ目は、Cargo.toml に次の設定を追加することです。Bevyとほかの依存クレートを最適化しつつ、自分のコードはすばやくコンパイルできるようにします。

[dependencies]
bevy = "0.20"
# Enable a small amount of optimization in the dev profile.
[profile.dev]
opt-level = 1
# Enable a large amount of optimization in the dev profile for dependencies.
[profile.dev.package."*"]
opt-level = 3

これがないと、ゲームのデバッグビルドはとても遅くなることがあります。フレームレートが低く、読み込みにも時間がかかります。依存クレートのコンパイルは一度だけなので、最適化のコストを払うのは最初のビルドのときだけです(プロファイルについてはパフォーマンスで説明しています)。

2つ目は、開発中は dynamic_linking フィーチャーをオンにすることです。するとBevyは別の共有ライブラリとしてビルドされるので、変更のたびにCargoがBevy全体をあなたのプログラムにリンクし直す必要がなくなります。

Terminal window
cargo run --features bevy/dynamic_linking

Bevyのガイドには注意が2つあります。Windowsでは、dynamic_linking は上の opt-level の設定と一緒でないと動きません。そして、この設定のままゲームを配布しないでください。ゲームの横に追加のライブラリファイルが必要になってしまいます。リリース版はこのフィーチャーなしでビルドしましょう。ガイドでは、より速いリンカ(lld や mold)の使い方も紹介されていて、特にLinuxで大きな効果があります。

Macroquad(英語)は、雰囲気がまったく違います。ECSもアプリビルダーもありません。ゲームループは自分で書き、draw_circle のようなシンプルな関数で描画します。依存クレートがとても少ないので、まっさらな状態からのビルドも数分ではなく数秒で終わります。

Terminal window
cargo new move_the_ball
cd move_the_ball
cargo add macroquad
[dependencies]
macroquad = "0.4"

この小さなゲームでは、矢印キーでボールを動かせます。

use macroquad::prelude::*;
#[macroquad::main("Move the Ball")]
async fn main() {
let mut player = vec2(screen_width() / 2.0, screen_height() / 2.0);
let speed = 250.0; // 1秒あたりのピクセル数
loop {
// 1. 入力:矢印キーでプレイヤーを動かす
let dt = get_frame_time(); // 前のフレームからの秒数
if is_key_down(KeyCode::Right) {
player.x += speed * dt;
}
if is_key_down(KeyCode::Left) {
player.x -= speed * dt;
}
if is_key_down(KeyCode::Down) {
player.y += speed * dt;
}
if is_key_down(KeyCode::Up) {
player.y -= speed * dt;
}
if is_key_pressed(KeyCode::Escape) {
break;
}
// 2. プレイヤーを画面の中にとどめる
player.x = player.x.clamp(0.0, screen_width());
player.y = player.y.clamp(0.0, screen_height());
// 3. このフレームのすべてを描く
clear_background(DARKBLUE);
draw_circle(player.x, player.y, 20.0, ORANGE);
draw_text("Arrow keys to move, Esc to quit", 20.0, 30.0, 28.0, WHITE);
next_frame().await
}
}

ゲームループの3つのステップ、入力・更新・描画が見えますね。#[macroquad::main("Move the Ball")] は、そのタイトルのウィンドウを開きます。main は async ですが、Tokioもasyncの知識も必要ありません。next_frame().await は単に「このフレームを表示して、次のフレームを待つ」という意味です。Linuxでは、MacroquadのREADMEに、先にインストールしておくシステムパッケージがいくつか挙がっています(Ubuntuなら pkg-config libx11-dev libxi-dev libgl1-mesa-dev libasound2-dev)。

MacroquadもBevyも、ゲームをブラウザ向けのWebAssemblyとしてビルドできます。Wasmがはじめてなら、先にRustとWebAssemblyを読んでください。どちらの場合も、まずWasmのターゲットを追加します。

Terminal window
rustup target add wasm32-unknown-unknown

Macroquadなら、とても簡単です。コマンド1つで .wasm ファイルができます。

Terminal window
cargo build --release --target wasm32-unknown-unknown

ファイルは target/wasm32-unknown-unknown/release/move_the_ball.wasm にできます(上の例では約600 KBでした)。MacroquadのREADMEには、小さなJavaScriptファイル mq_js_bundle.js を使ってそれを読み込む、短い index.html が載っています。両方のファイルを1つのフォルダに入れ、好きなローカルWebサーバーで配信しましょう。たとえば basic-http-server . です(cargo install basic-http-server でインストールできます)。HTMLファイルをダブルクリックするだけでは、たいていうまくいきません。ブラウザが、ディスクから直接 .wasm ファイルを読み込むのをブロックするからです。

Bevyは、JavaScriptとのつなぎのコードを作るのに wasm-bindgen を使います。次の手順は、BevyのexamplesのREADMEをもとにしています(上の my_bevy_game プロジェクトの場合)。

Terminal window
cargo install wasm-bindgen-cli
cargo build --release --target wasm32-unknown-unknown
wasm-bindgen --out-dir web --target web target/wasm32-unknown-unknown/release/my_bevy_game.wasm

これで web フォルダに .js ファイルと _bg.wasm ファイルができます。小さなHTMLページが .js ファイルを読み込んで、ゲームを始めます。Bevyのセットアップガイドでは、ダウンロードを小さくするために opt-level = "s" を使う wasm-release プロファイルもすすめています。Web版のビルドは、ゲームジャムの作品を共有するのにぴったりです。みんながワンクリックで遊べて、何もインストールする必要がありません。

毎フレーム決まった量だけ動かす。 毎フレーム x += 5.0 とすると、120 FPSでは60 FPSのときの2倍の速さでゲームが進んでしまいます。デルタタイムを掛ける(x += speed * dt)か、固定タイムステップを使いましょう。

古いBevyのチュートリアルどおりに書く。 BevyはリリースのたびにAPIが変わるので、0.12向けのブログ記事は0.20ではコンパイルできないことがよくあります。チュートリアルがどのバージョン向けかを確かめ、自分のバージョンの公式サンプルを優先しましょう。リリースごとに、Bevyのサイトには移行ガイドもあります。

デバッグビルドが遅い。 Bevyのゲームが数フレーム毎秒でしか動かないなら、たぶん Cargo.toml の opt-level の設定を忘れています。

いきなり大きく始める。 オープンワールドのRPGは、どの言語でもはじめてのプロジェクトには難しすぎます。Pong、Snake、ブロック崩し、Flappy Birdから始めましょう。まず完成させて、次のものを少しだけ大きくすればいいのです。

1. 列挙型でゲームの状態を表す

Section titled “1. 列挙型でゲームの状態を表す”

どのゲームにも画面があります。メニュー、ゲーム本体、ポーズ画面、「ゲームオーバー」です。Menu、Playing、Paused、GameOver を持つ列挙型 GameState と、Enter、Escape、PlayerDied を持つ列挙型 Input を作ってください。そして fn next_state(state: GameState, input: Input) -> GameState を書きましょう。メニューでEnterを押すとゲームが始まり、Escapeでポーズと再開を切り替え、プレイヤーがやられるとゲームオーバーになり、「ゲームオーバー」でEnterを押すとメニューに戻ります。それ以外の入力では何も変わりません。決まった入力のリストを順番に与えて、変化を1つずつ出力してください。ヒント: タプル (state, input) に対してmatchを使い、最後を (same, _) => same で締めくくりましょう。

解答を見る
#[derive(Debug, Clone, Copy)]
enum GameState {
Menu,
Playing,
Paused,
GameOver,
}
#[derive(Debug, Clone, Copy)]
enum Input {
Enter,
Escape,
PlayerDied,
}
fn next_state(state: GameState, input: Input) -> GameState {
match (state, input) {
(GameState::Menu, Input::Enter) => GameState::Playing,
(GameState::Playing, Input::Escape) => GameState::Paused,
(GameState::Paused, Input::Escape) => GameState::Playing,
(GameState::Playing, Input::PlayerDied) => GameState::GameOver,
(GameState::GameOver, Input::Enter) => GameState::Menu,
// それ以外:入力を無視して、今の状態のままにする
(same, _) => same,
}
}
fn main() {
use Input::*; // Input::Enter の代わりに Enter と書けるようにする
let inputs = [Escape, Enter, Escape, PlayerDied, Escape, PlayerDied, Enter];
let mut state = GameState::Menu;
for input in inputs {
let new_state = next_state(state, input);
println!("{state:?} + {input:?} -> {new_state:?}");
state = new_state;
}
}

実行結果:

Menu + Escape -> Menu
Menu + Enter -> Playing
Playing + Escape -> Paused
Paused + PlayerDied -> Paused
Paused + Escape -> Playing
Playing + PlayerDied -> GameOver
GameOver + Enter -> Menu
▶ 実際に試してみよう

タプルでマッチすると、許される変化がすべて1か所に並びます。そして最後のアームが、それ以外のすべての入力を無害にしてくれます。ポーズ中のプレイヤーはやられません。(Paused, PlayerDied) は (same, _) に当てはまるからです。Bevyにも同じ考え方が States という名前で組み込まれています。

  • Rustはゲーム開発の本当の選択肢です。「もう少し」の段階ですが、強力なエンジン(Bevy)、シンプルなライブラリ(Macroquad、ggez)、エディタを使える選択肢(Fyrox、Godot + gdext)、そしてたくさんの部品があります。
  • どのゲームもループを回しています。入力、更新、描画です。デルタタイムか固定タイムステップを使えば、速さがフレームレートに左右されません。
  • ECSはゲームを、エンティティ(ID)、コンポーネント(ただのデータ)、システム(特定のコンポーネントを持つエンティティに対して実行される関数)に分けます。
  • Bevyは隅から隅までECSです。opt-level のプロファイル設定を追加し、dynamic_linking は開発中だけ使いましょう。
  • Macroquadは2Dゲームをいちばん早く始められます。ループは自分で書き、シンプルな関数で描画します。
  • どちらも wasm32-unknown-unknown ターゲットでブラウザ向けにビルドできます。

理解度チェック

1. ECSで、エンティティとは何ですか?

2. 固定タイムステップを使うと、どのパソコンでもゲームが同じように動くのはなぜですか?

3. 完成したゲームを配布するときに、オンにしたままにしては「いけない」Bevyの設定はどれですか?

4. ビルド時間がとても短い、はじめての小さな2Dゲームを作りたいとき、このページがすすめているクレートはどれですか?

スコア: 0 / 4

  • Are We Game Yet?(英語):Rustのゲームエンジン、物理演算・オーディオ・ネットワークのライブラリ、Rustで作られたゲームをまとめたコミュニティのサイトです。
  • Bevy Quick Start: Setup(英語):Bevyのインストール、コンパイルを速くする設定、リリース用とWasm用のプロファイルについての公式ガイドです。
  • Game development in Rust with Macroquad(英語):Macroquadで本格的なシューティングゲームを1ステップずつ作っていく、無料のオンラインブックです。
  • The godot-rust book(英語):gdextを使って、Godot 4のゲームロジックをRustで書く方法。
  • Game Loop — Game Programming Patterns(英語):ゲームループ、デルタタイム、固定タイムステップを、親しみやすく詳しく説明しています。