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