summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop/HudLayout.fs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-28 09:27:14 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-28 09:27:14 +0800
commit70394b3e4ded4811b1f482e6d036b23b7dcb1765 (patch)
treeb9b5057f1b6a5dd4ac5975ce5c7733a1232a86cd /src/LivingVillage.Desktop/HudLayout.fs
parente73bc80ba8237ab71e32f75613e7441e0fbceecf (diff)
downloadliving-village-70394b3e4ded4811b1f482e6d036b23b7dcb1765.tar.gz
feat(desktop): P38 HUD 图标化升级(时段/时间/倍速/体力/钱币)
顶部常驻条每个状态段前加 7x7 原创点阵图标(用 pixel 贴图绘制,无外部素材): 时段=太阳、时间=钟、倍速=双箭头、体力=心形、钱币=圆形钱眼。图标占 iconWidth+iconGap 后接文本,段总宽含图标;底色药丸与 1px 描边同覆盖图标与文本, 昼夜两套调色板均可读;仍为半透明窄条(barHeight 不变,非大黑块)。
Diffstat (limited to 'src/LivingVillage.Desktop/HudLayout.fs')
-rw-r--r--src/LivingVillage.Desktop/HudLayout.fs85
1 files changed, 77 insertions, 8 deletions
diff --git a/src/LivingVillage.Desktop/HudLayout.fs b/src/LivingVillage.Desktop/HudLayout.fs
index f3e4c12..05fce33 100644
--- a/src/LivingVillage.Desktop/HudLayout.fs
+++ b/src/LivingVillage.Desktop/HudLayout.fs
@@ -14,32 +14,101 @@ module HudLayout =
let segmentGap = 20
let textScale = 2
+ /// 常驻段的像素图标(7x7 点阵,按 iconScale 放大),全部用 pixel 贴图绘制、无外部素材。
+ type HudIcon =
+ | PeriodIcon
+ | ClockIcon
+ | SpeedIcon
+ | EnergyIcon
+ | MoneyIcon
+
type Segment =
{ Label: string
- Value: string }
+ Value: string
+ Icon: HudIcon }
let segmentText (segment: Segment) : string = sprintf "%s %s" segment.Label segment.Value
/// 常驻状态片段,数值全部取自世界真实状态,绝不编造。
let segments (world: World) (control: SimulationControl) : Segment list =
let needs = world.Avatar.Mind.Needs
- [ { Label = "时段"; Value = M6Presentation.timePeriodLabel world.Tick }
- { Label = "时间"; Value = M6Presentation.clockTimeLabel world.Tick }
- { Label = "倍速"; Value = M6Presentation.speedLabel control }
- { Label = "体力"; Value = sprintf "%.0f" needs.Energy }
- { Label = "钱币"; Value = sprintf "%.0f" needs.Money } ]
+ [ { Label = "时段"; Value = M6Presentation.timePeriodLabel world.Tick; Icon = PeriodIcon }
+ { Label = "时间"; Value = M6Presentation.clockTimeLabel world.Tick; Icon = ClockIcon }
+ { Label = "倍速"; Value = M6Presentation.speedLabel control; Icon = SpeedIcon }
+ { Label = "体力"; Value = sprintf "%.0f" needs.Energy; Icon = EnergyIcon }
+ { Label = "钱币"; Value = sprintf "%.0f" needs.Money; Icon = MoneyIcon } ]
+
+ // ---- 图标几何与点阵(纯数据/纯函数,Game 与回归测试共用)----
+
+ let iconGrid = 7
+ let iconScale = textScale
+ let iconWidth = iconGrid * iconScale
+ let iconHeight = iconGrid * iconScale
+ let iconGap = 6
+
+ /// 7x7 点阵,'1' 为实心。全部原创点阵,仅用现有像素贴图绘制。
+ let iconRows (icon: HudIcon) : string list =
+ match icon with
+ | PeriodIcon ->
+ [ "0001000"
+ "1010101"
+ "0011100"
+ "0111110"
+ "0011100"
+ "1010101"
+ "0001000" ]
+ | ClockIcon ->
+ [ "0011100"
+ "0100010"
+ "1001001"
+ "1001000"
+ "1001000"
+ "0100010"
+ "0011100" ]
+ | SpeedIcon ->
+ [ "0100010"
+ "0110011"
+ "0011011"
+ "0001110"
+ "0011011"
+ "0110011"
+ "0100010" ]
+ | EnergyIcon ->
+ [ "0000000"
+ "0101010"
+ "1111111"
+ "1111111"
+ "0111110"
+ "0011100"
+ "0001000" ]
+ | MoneyIcon ->
+ [ "0011100"
+ "0111110"
+ "1110111"
+ "1100011"
+ "1110111"
+ "0111110"
+ "0011100" ]
+
+ /// 文本起始 x(图标占 iconWidth + iconGap)。
+ let textOrigin (segmentX: int) : int = segmentX + iconWidth + iconGap
/// 段文本(含标签)的像素宽度。
let segmentWidth (segment: Segment) : int =
FloatingPrompt.measureWidth (segmentText segment) textScale
- /// 左对齐排布,返回 (起点 x, 宽度, 分段);纯函数,便于布局回归断言。
+ /// 段总宽(图标 + 间隙 + 文本)。
+ let segmentSpan (segment: Segment) : int =
+ iconWidth + iconGap + segmentWidth segment
+
+ /// 左对齐排布,返回 (起点 x, 总宽, 分段);段内 x 起为图标,textOrigin 起为文本。
+ /// 纯函数,便于布局回归断言。
let layout (segments: Segment list) : (int * int * Segment) list =
let _, placed =
segments
|> List.fold
(fun (x, acc) segment ->
- let width = segmentWidth segment
+ let width = segmentSpan segment
x + width + segmentGap, (x, width, segment) :: acc)
(paddingX, [])
List.rev placed