小時候在大型機台玩《雷電》時,總覺得能自己做出一個射擊遊戲一定很酷。最近我正好在研究 Rust 的遊戲引擎 Bevy,挑戰做出一個簡化版的經典射擊遊戲 雷電 (Raiden)

這個 Demo 包含以下功能:

  • 玩家可以用 WASD / 方向鍵 移動飛機

  • 按 空白鍵 發射子彈

  • 敵人會自動生成並從上方往下移動

  • 子彈擊中敵人 → 敵人與子彈同時消失

  • 超出畫面的物件會自動清理

最終效果大概是這樣:

demo

Bevy 為什麼適合這個題材?

Bevy 採用 ECS(Entity Component System) 架構,把遊戲物件拆成三個元素:

  • Entity(實體):玩家、敵人、子彈

  • Component(元件):位置、速度、角色類型

  • System(系統):移動、生成、碰撞、清理

對「射擊遊戲」來說,這個架構超直觀:敵人就是一個 entity,子彈也是,給它一個 velocity component,它們就會自己動起來。

玩家控制

玩家飛機的操作就是 方向鍵 / WASD。這裡我加了一個小細節:玩家不能飛出螢幕邊界。

transform.translation.x = transform.translation.x
    .clamp(-WINDOW_WIDTH / 2.0 + 25.0, WINDOW_WIDTH / 2.0 - 25.0);

這行程式碼就是用來「把你擋在畫面裡」。我一開始還忘了加,結果飛機直接飛出視窗消失XD

射擊

只要按空白鍵,玩家就能發射一顆黃色小子彈往上飛。

commands.spawn((
    Sprite {
        color: Color::srgb(1.0, 1.0, 0.0),
        custom_size: Some(Vec2::new(5.0, 10.0)),
        ..default()
    },
    Transform::from_xyz(player_x, player_y + 30.0, 0.0),
    Bullet,
    Velocity(Vec3::new(0.0, BULLET_SPEED, 0.0)),
));

子彈就是一個矩形精靈,加上 Velocity,剩下交給移動系統就好。 第一次按下空白鍵,看到畫面裡飛出黃色子彈的瞬間,彷彿夢回童年。

產生敵人

敵人每隔兩秒會在隨機位置生成,然後慢慢往下移動:

let x = (rand::random::<f32>() - 0.5) * (WINDOW_WIDTH - 100.0);
commands.spawn((
    Sprite::from_image(asset_server.load("player2.png")),
    Transform::from_xyz(x, WINDOW_HEIGHT / 2.0 + 50.0, 0.0),
    Enemy,
    Velocity(Vec3::new(0.0, -ENEMY_SPEED, 0.0)),
));

當我第一次看到敵人真的「一架一架掉下來」時,瞬間覺得好像真的可以玩了 😎。

碰撞檢測

子彈跟敵人碰到就同歸於盡,這裡我用了最直白的寫法:算距離。

if bullet_transform.translation.distance(enemy_transform.translation) < 30.0 {
    commands.entity(bullet_entity).despawn();
    commands.entity(enemy_entity).despawn();
}

完全沒有物理引擎,單純距離小於 30 就消失。但就算這麼陽春,打掉第一架敵機的瞬間還是很讚。

自動清理

最後一件必須要處理的是,子彈飛出畫面、敵人掉下去,都要刪掉。不然遊戲跑久了會 lag。

if transform.translation.y > WINDOW_HEIGHT / 2.0 + 100.0
    || transform.translation.y < -WINDOW_HEIGHT / 2.0 - 100.0 {
    commands.entity(entity).despawn();
}

記得把這段加上去,不然最後會卡QQ

小結

總之,這是一個運用 Bevy 就能寫出來的一個遊戲,雖然很簡單,但是應該可以有很多可能性,例如可以再加上特效、聲音,可能還可以加上計分系統。

這篇文章只是我用 Bevy 寫遊戲的一個小實驗。其實我還在寫一個完整的 Bevy 系列文,會一步一步帶大家從 ECS 入門,到做出一個 Rogue-lite 小遊戲。 如果你對 Rust 遊戲開發有興趣,歡迎看一下鐵人賽系列