summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop/HudLayout.fs
blob: d943cec55b64908aa04f5a6f47105e893d9d637b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
namespace LivingVillage.Desktop

open Microsoft.Xna.Framework
open LivingVillage.Kernel
open LivingVillage.Kernel.Sim

/// 顶部窄信息条 HUD 的纯布局/配色模型:只做确定性计算,实际绘制在 Game.fs。
/// 常驻状态(时段/时间/倍速/体力/钱币)压进一条窄带,绝不用整屏纯色或大黑块。
module HudLayout =

    let barHeight = 36
    let accentHeight = 3
    let paddingX = 16
    let segmentGap = 20
    let textScale = 2

    type Segment =
        { Label: string
          Value: string }

    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 } ]

    /// 段文本(含标签)的像素宽度。
    let segmentWidth (segment: Segment) : int =
        FloatingPrompt.measureWidth (segmentText segment) textScale

    /// 左对齐排布,返回 (起点 x, 宽度, 分段);纯函数,便于布局回归断言。
    let layout (segments: Segment list) : (int * int * Segment) list =
        let _, placed =
            segments
            |> List.fold
                (fun (x, acc) segment ->
                    let width = segmentWidth segment
                    x + width + segmentGap, (x, width, segment) :: acc)
                (paddingX, [])
        List.rev placed

    type Palette =
        { BarTop: Color
          BarBottom: Color
          Accent: Color
          Label: Color
          Value: Color }

    /// 白天暖色 / 夜晚(冬夜)冷色微调;均为半透明渐变窄条,无大黑块。
    let palette (mode: M6DayNight) : Palette =
        match mode with
        | Day ->
            { BarTop = Color(40, 56, 62, 200)
              BarBottom = Color(22, 34, 40, 200)
              Accent = Color(212, 168, 96)
              Label = Color(206, 220, 208)
              Value = Color(242, 248, 234) }
        | Night ->
            { BarTop = Color(22, 30, 48, 205)
              BarBottom = Color(13, 19, 33, 205)
              Accent = Color(120, 168, 196)
              Label = Color(176, 196, 214)
              Value = Color(228, 238, 246) }