iT邦幫忙

2025 iThome 鐵人賽

DAY 16
1

繼續把隨機資源做更完整的互動流程,也就是開寶箱的環節。開寶箱就像抽盲盒一樣,同一個寶箱可能放補給道具,但也有可能是偽裝成寶箱的敵人(芙莉蓮應該最了解)。當玩家按下空白鍵後,究竟是賺到一瓶藥水,還是被寶箱怪追著跑,這是本篇預計要完成的功能。

預計達成的目標:

  • 在地圖上隨機擺放寶箱,並接上玩家的互動輸入。
  • 寶箱若藏著道具,會顯示對應的圖示 2 秒並自動套用效果。
  • 偽裝成寶箱的敵人會甦醒、追擊與造成傷害。

寶箱互動全流程

首先一樣需要新增圖片的資源,放進 /assets/items/chests 中,分別有四張圖片。

寶箱圖片

個別代表的是未開啟、開啟中、已開啟,跟偽裝的寶箱怪。

核心邏輯寫在 new_demo/src/systems/chest.rs,主要拆成三段:

  1. 隨機擺放spawn_random_chests 會掃描所有 RoomTile,挑選地板與戶外地板,隨機挑出四個位置產生 Chest Component。內容物以 25% 機率是 Mimic,否則就是隨機道具。
commands.spawn((
    Chest::new(contents),
    Sprite::from_image(asset_server.load("items/chests/chest_closed.png")),
    Transform::from_translation(Vec3::new(base_position.x, base_position.y, CHEST_Z))
        .with_scale(Vec3::splat(CHEST_SCALE)),
    Name::new("Chest"),
));
  1. 玩家互動input_system 會先搜尋距離玩家最近的關閉寶箱,只要小於 CHEST_INTERACTION_RADIUS 就送出 ChestInteractionEvent,比門或攻擊的優先還要高。
if let Some((entity, _)) = nearest_chest {
    chest_events.write(ChestInteractionEvent { chest: entity });
    return;
}
  1. 開箱反應chest_interaction_system 依內容物分兩路:
    • 道具:切換為 chest_open.png、加掛 ChestItemReveal 計時器,並生成一個子節點 sprite。
    • Mimic:換成 chest_mimic.png、轉成 Enemy + Mimic,直接進入追擊狀態。

顯示道具再自動使用

道具寶箱的視覺與效果由 chest_item_reveal_system 控制:

  • 每個寶箱帶著 ChestItemReveal,timer 結束後觸發 apply_pickup_effect,補血、回耐力、解除中毒都走同一支函式。
  • 道具 sprite 掛在寶箱子節點上,顯示 2 秒後會自動被 commands.entity(child).despawn() 清掉。
  • 為了貼合場景,CHEST_ITEM_DISPLAY_SCALE 從 2.2 調整成 1.25,避免覆蓋整個寶箱。
let item_visual = commands
    .spawn((
        ChestItemVisual,
        Sprite::from_image(asset_server.load(sprite_path)),
        Transform::from_translation(Vec3::new(0.0, CHEST_ITEM_DISPLAY_OFFSET, 0.1))
            .with_scale(Vec3::splat(CHEST_ITEM_DISPLAY_SCALE)),
    ))
    .id();

玩家不需要額外去按任何鍵,計時器跑完就立即套用效果並換上 chest_empty.png,同一個寶箱不會再次觸發。


偽裝的寶箱怪

寶箱怪走的是敵人管線:

  • ChestContents::Mimic 被開啟時,會把原本的寶箱 entity 加上 Enemy, Mimic, Health, Attack, EnemyPatrol, EnemyAlert 等 component,初始狀態直接設為 Chasing
  • EnemyPlugin 新增 mimic_ai_system,重用原本的 process_enemy_ai,讓 Mimic 追擊玩家但仍遵守觸發/牽制半徑。
  • enemy_contact_attack_system 的查詢條件改為同時處理 Slime 與 Mimic,玩家若靠太近就會吃到 CHEST_MIMIC_ATTACK 的傷害,Log 也會顯示「寶箱怪攻擊造成 X 傷害」。
for (attacker_transform, mut attack, attack_stat, _is_slime, is_mimic) in &mut attacker_query {
    if distance <= attack.radius && attack.cooldown.finished() {
        let attacker_name = if is_mimic.is_some() { "寶箱怪" } else { "史萊姆" };
        info!(
            "{}攻擊造成 {} 傷害,玩家剩餘 HP: {}",
            attacker_name, damage, health.current
        );
    }
}

這樣的安排有兩個好處:

  1. 寶箱怪使用相同的傷害事件,UI 和音效可以沿用既有流程。
  2. 偏移量與追擊速度都讀自 constants.rs,之後要調整平衡只要改數值。

實際遊玩

開啟寶箱流程

開啟寶箱流程

與寶箱怪戰鬥

與寶箱怪戰鬥

  • 開箱前需要先確認附近有沒有敵人,否則被寶箱怪偷襲會直接掉血。
  • 道具顯示僅 2 秒,如果當下忙著閃躲,可以記得補完效果後會變成空箱。
  • 寶箱怪的牽制半徑設得比較短,所以還是有辦法甩掉,只是最好先把走位空間清乾淨。

小結

目前隨機擺放的寶箱讓房間探索更有期待感,多了一些樂趣在場上,另外也有偽裝的寶箱怪會隨機出現在場上,這也增加了一些不安定的要素,讓玩家在開寶箱的同時也不只是只有好處。

之後想要嘗試的部分,可能可以在寶箱上方放提示圖示,來提醒玩家這個房間還有未開的寶箱。

今日程式碼同步至 repo


上一篇
打怪掉落道具
下一篇
裝備系統與武器定位
系列文
Bevy Rogue-lite 勇者冒險篇 × Rust 遊戲開發筆記18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言