30 天快接近尾聲了,該準備進到收尾以及調整了,這篇的重點是整理左側 HUD。把原本一大串文字、除錯快捷鍵通通整理成乾淨的介面,並用圖示呈現攻擊、防禦、狀態,讓玩家專注在遊戲本身。另外也補上基本的操作提示,避免新玩家不知道怎麼上手。
這回的重點分成:
icons/sword.png
、icons/shield.png
、icons/skull.png
,並在面板內以圖示取代純文字欄位。之前面板裡塞滿了測試時用的按鍵說明,甚至還顯示耐力數值和攻擊成本,這些在實際操作時會造成視覺混亂:
因此這波改版的策略是減量、視覺化、只留下必要提示。操作提示改成放在血條下方的細體橫幅,平時只留下 Space/ESC 功能,狀態異常時再額外說明就好。
new_demo/src/constants.rs
增加了統一字型與圖示的常數:
pub const PLAYER_DEATH_FONT_PATH: &str = "fonts/Kenney-Future-Square.ttf";
pub const MENU_FONT_PATH: &str = "fonts/Kenney-Future-Square.ttf";
pub const PLAYER_STATS_FONT_PATH: &str = "fonts/Kenney-Future-Square.ttf";
pub const PLAYER_STATS_ICON_SIZE: f32 = 28.0;
pub const PLAYER_STATS_ATTACK_ICON_PATH: &str = "icons/sword.png";
pub const PLAYER_STATS_DEFENSE_ICON_PATH: &str = "icons/shield.png";
pub const PLAYER_STATS_POISON_ICON_PATH: &str = "icons/skull.png";
assets/icons/
,讓面板用 icon 顯示而非一堆縮寫。後續只要改常數就能套用到所有 UI 節點,不用再逐一修改。
player_stats.rs
原本只有一行 Text
,現在改成完整的 Flex Column 結構,每個指標都拆成獨立元件:
commands
.spawn((
PlayerStatsPanel,
Node {
width: Val::Px(PLAYER_STATS_PANEL_WIDTH),
flex_direction: FlexDirection::Column,
row_gap: Val::Px(8.0),
..Default::default()
},
BackgroundColor(Color::srgba(0.05, 0.05, 0.08, 0.92)),
))
.with_children(|parent| {
parent.spawn((PlayerStatsTitleText, Text::new("PLAYER"), font.clone(), title_color));
parent
.spawn((
Node {
width: Val::Percent(100.0),
display: Display::Flex,
flex_direction: FlexDirection::Row,
align_items: AlignItems::Center,
column_gap: Val::Px(8.0),
..Default::default()
},
Name::new("PlayerStatsAttackRow"),
))
.with_children(|row| {
row.spawn((
ImageNode::new(sword_icon.clone()),
Node {
width: Val::Px(PLAYER_STATS_ICON_SIZE),
height: Val::Px(PLAYER_STATS_ICON_SIZE),
..Default::default()
},
));
row.spawn((
PlayerStatsAttackText,
Text::new(""),
TextFont { font: font.clone(), font_size: PLAYER_STATS_FONT_SIZE, ..Default::default() },
TextColor(Color::srgb(0.95, 0.93, 0.9)),
));
});
// DEF 列同理...
});
攻擊、防禦欄位不再塞滿符號,而是以「總值 + base + bonus + 倍率」格式呈現。耐力列則簡化為 regen 25.0/s
,把當下細節交給上方綠色耐力條呈現。
為了避免一次借用多個 Text
造成 Bevy 的 B0001
借用衝突,更新函式改用 ParamSet
:
mut text_queries: ParamSet<(
Query<&mut Text, With<PlayerStatsLevelText>>,
Query<&mut Text, With<PlayerStatsAttackText>>,
Query<&mut Text, With<PlayerStatsDefenseText>>,
Query<&mut Text, With<PlayerStatsStaminaText>>,
)>;
每個欄位輪流 iter_mut().next()
取值,就能在同一幀內安全更新四個 Text
。
ui.rs
的 update_player_status_text
改成固定顯示按鍵說明,再視狀態追加資訊:
match poison_state {
Some(_) => {
*text = Text::new(
"Space: Attack / Interact | Esc: Pause\nPoisoned: HP -3 per tick",
);
color.0 = Color::srgb(0.95, 0.38, 0.32);
}
None => {
*text = Text::new(
"Space: Attack / Interact | Esc: Pause\nRelease Space to recover stamina",
);
color.0 = Color::srgb(0.78, 0.78, 0.72);
}
}
玩家進入遊戲就能立刻知道核心操作,中毒時也會看到明顯的提示。
PlayerPlugin
把 player_attribute_debug_input_system
、player_status_debug_shortcuts_system
從 Update 排程移除,遊戲中不再接受 1/2/3/4、Q/W/A/S/R、T/G/Y 的輸入。input_system
保留 Space 與門/傳送門互動,但 log 文字改為 Door interaction event dispatched
、Advancing to level …
,整體輸出更一致。現在的遊戲操作流程完全只面向玩家設計,測試用快捷鍵就不需要了。
整理 UI 還蠻快的,因為一切都是資料驅動。把圖示、字型、提示文字集中在常數與 ECS 節點後,未來要替換應該不會太難。
今日程式碼同步至 repo