diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj | 1 | ||||
| -rw-r--r-- | src/LivingVillage.Desktop.Tests/P75HudStripTests.fs | 59 | ||||
| -rw-r--r-- | src/LivingVillage.Desktop/Game.fs | 8 | ||||
| -rw-r--r-- | src/LivingVillage.Desktop/HudLayout.fs | 25 |
4 files changed, 81 insertions, 12 deletions
diff --git a/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj b/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj index fb7ecb7..dc2cb23 100644 --- a/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj +++ b/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj @@ -46,6 +46,7 @@ <Compile Include="P72CharacterWalkTests.fs" /> <Compile Include="P73LightingTierTests.fs" /> <Compile Include="P74LaunchTransitionTests.fs" /> + <Compile Include="P75HudStripTests.fs" /> <Compile Include="SampleTests.fs" /> </ItemGroup> diff --git a/src/LivingVillage.Desktop.Tests/P75HudStripTests.fs b/src/LivingVillage.Desktop.Tests/P75HudStripTests.fs new file mode 100644 index 0000000..e80d91f --- /dev/null +++ b/src/LivingVillage.Desktop.Tests/P75HudStripTests.fs @@ -0,0 +1,59 @@ +namespace LivingVillage.Desktop.Tests + +open Microsoft.VisualStudio.TestTools.UnitTesting +open LivingVillage.Desktop +open LivingVillage.Kernel +open LivingVillage.Kernel.Sim + +/// P75 回归:HUD 顶部条改为紧凑半透明药丸(去整宽深色带),信息不遮挡、文字可读。 +[<TestClass>] +type P75HudStripTests () = + + let world = Sim.initialWorldN 42UL 4 + let control = SimulationControl.initial + let placed = HudLayout.layout (HudLayout.segments world control) + + [<TestMethod>] + member _.TopBandIsRemovedForDayAndNight () = + for mode in [ Day; Night ] do + let palette = HudLayout.palette mode + Assert.AreEqual<byte>(0uy, palette.BarTop.A) + Assert.AreEqual<byte>(0uy, palette.BarBottom.A) + Assert.AreEqual<byte>(0uy, HudLayout.bandAlpha) + + [<TestMethod>] + member _.PillsAreCompactInsideTheStrip () = + Assert.IsTrue(HudLayout.pillHeight < HudLayout.barHeight, "药丸须比窄条矮,留出上下留白") + for (x, width, _) in placed do + let pill = HudLayout.segmentBackdrop x width + Assert.IsTrue(pill.Y >= 0 && pill.Y + pill.Height <= HudLayout.barHeight, "药丸须在窄条内") + let hair = HudLayout.pillHairline x width + Assert.IsTrue(hair.Height = 1, "发丝线为 1px") + Assert.IsTrue(hair.X >= pill.X && hair.X + hair.Width <= pill.X + pill.Width, "发丝线须在药丸内") + Assert.AreEqual<int>(max 1 (pill.Width - 2), hair.Width) + + [<TestMethod>] + member _.StripLeavesWhitespaceAndDoesNotOverlapDateCard () = + Assert.IsTrue(placed.Length > 0) + let firstX = placed |> List.head |> fun (x, _, _) -> x + Assert.AreEqual<int>(HudLayout.paddingX, firstX) + let lastEnd = placed |> List.last |> fun (x, width, _) -> x + width + // 药丸总跨度远小于通栏宽度,右侧留白充足(不再铺满整宽)。 + Assert.IsTrue(lastEnd < 1280 / 2, sprintf "HUD 只占左半,右侧留白;lastEnd=%d" lastEnd) + let reading = HudLayout.calendarReading world.Tick + let cal = HudLayout.calendarCardRect 1280 reading + Assert.IsTrue(cal.Y >= HudLayout.barHeight + HudLayout.accentHeight, "日历卡不压顶部条") + + [<TestMethod>] + member _.TextStaysReadableOnTranslucentPills () = + for mode in [ Day; Night ] do + let palette = HudLayout.palette mode + Assert.IsTrue(palette.SegmentBackdrop.A > 0uy && palette.SegmentBackdrop.A < 255uy, "药丸半透明") + let valueLuma = int palette.Value.R + int palette.Value.G + int palette.Value.B + let outlineLuma = int palette.Outline.R + int palette.Outline.G + int palette.Outline.B + Assert.IsTrue(valueLuma > 600, "数值色须够亮") + Assert.IsTrue(valueLuma > outlineLuma + 400, "亮字 vs 深描边对比须足够") + // 图标与数值并排:文本起始在图标右侧。 + for (x, _, segment) in placed do + Assert.AreEqual<int>(x + HudLayout.iconWidth + HudLayout.iconGap, HudLayout.textOrigin x) + Assert.IsFalse(System.String.IsNullOrEmpty segment.Value) diff --git a/src/LivingVillage.Desktop/Game.fs b/src/LivingVillage.Desktop/Game.fs index a4f994b..c6408aa 100644 --- a/src/LivingVillage.Desktop/Game.fs +++ b/src/LivingVillage.Desktop/Game.fs @@ -3405,17 +3405,14 @@ type LivingVillageGame() as this = /// 顶部窄信息条:时段/时间/倍速/体力/钱币,半透明渐变 + 强调线,绝非大黑块。 member private this.DrawHudBar() = - let viewport = this.GraphicsDevice.Viewport let profile = M6Presentation.profileAtTick world.Tick let palette = HudLayout.palette profile.Mode let placed = HudLayout.layout (HudLayout.segments world simulationControl) let barHeight = HudLayout.barHeight let textY = (barHeight - 8 * HudLayout.textScale) / 2 spriteBatch.Begin() - // 竖向渐变:上半略亮、下半压暗,避免整条纯色。 - spriteBatch.Draw(pixel, Rectangle(0, 0, viewport.Width, barHeight / 2), palette.BarTop) - spriteBatch.Draw(pixel, Rectangle(0, barHeight / 2, viewport.Width, barHeight - barHeight / 2), palette.BarBottom) - spriteBatch.Draw(pixel, Rectangle(0, barHeight, viewport.Width, HudLayout.accentHeight), palette.Accent) + // P75:去掉整宽深色渐变带(palette 的 BarTop/BarBottom alpha=0),信息只靠各段的 + // 半透明药丸承载——紧凑的图标+数值并排、留白充足,HUD 区域黑块面积大幅下降。 // 图标用 pixel 贴图按 7x7 点阵绘制(无外部素材),先描边后填充,保证昼夜可读。 let drawIcon (iconX: int) (iconY: int) (color: Color) (icon: HudLayout.HudIcon) = HudLayout.iconRows icon @@ -3434,6 +3431,7 @@ type LivingVillageGame() as this = let iconY = (barHeight - HudLayout.iconHeight) / 2 for (x, width, segment) in placed do spriteBatch.Draw(pixel, HudLayout.segmentBackdrop x width, palette.SegmentBackdrop) + spriteBatch.Draw(pixel, HudLayout.pillHairline x width, palette.Accent) let textX = HudLayout.textOrigin x let labelAdvanced = FloatingPrompt.measureWidth (segment.Label + " ") HudLayout.textScale let isEnergy = segment.Icon = HudLayout.EnergyIcon diff --git a/src/LivingVillage.Desktop/HudLayout.fs b/src/LivingVillage.Desktop/HudLayout.fs index b19df4b..cd06224 100644 --- a/src/LivingVillage.Desktop/HudLayout.fs +++ b/src/LivingVillage.Desktop/HudLayout.fs @@ -122,6 +122,17 @@ module HudLayout = let y = (barHeight - height) / 2 Microsoft.Xna.Framework.Rectangle(x - 6, y, width + 12, height) + /// P75:药丸底部 1px 强调发丝线(取代整条铺满的 accent 带,让留白更足)。 + let pillHairline (x: int) (width: int) : Microsoft.Xna.Framework.Rectangle = + let pill = segmentBackdrop x width + Microsoft.Xna.Framework.Rectangle(pill.X + 1, pill.Y + pill.Height - 2, max 1 (pill.Width - 2), 1) + + /// P75:顶部不再铺整宽深色带(0 = 仅靠半透明药丸承载信息,去掉「整块深色底」)。 + let bandAlpha : byte = 0uy + + /// P75:药丸高度的紧凑上界(须 < barHeight 以留出上下留白)。 + let pillHeight : int = 8 * textScale + 10 + type Palette = { BarTop: Color BarBottom: Color @@ -131,25 +142,25 @@ module HudLayout = SegmentBackdrop: Color Outline: Color } - /// 白天暖色 / 夜晚(冬夜)冷色微调;均为半透明渐变窄条,无大黑块。 - /// 每个常驻片段再叠一层半透明底色 + 1px 深色描边,双时段都能读清。 + /// 白天暖色 / 夜晚(冬夜)冷色微调;半透明药丸承载信息,无整宽深色带、无大黑块。 + /// P75 起 `BarTop/BarBottom` 保留字段但 alpha=0(不再铺整条底色)。 let palette (mode: M6DayNight) : Palette = match mode with | Day -> - { BarTop = Color(40, 56, 62, 200) - BarBottom = Color(22, 34, 40, 200) + { BarTop = Color(40, 56, 62, 0) + BarBottom = Color(22, 34, 40, 0) Accent = Color(212, 168, 96) Label = Color(206, 220, 208) Value = Color(242, 248, 234) SegmentBackdrop = Color(8, 14, 20, 150) Outline = Color(6, 10, 14, 255) } | Night -> - { BarTop = Color(22, 30, 48, 205) - BarBottom = Color(13, 19, 33, 205) + { BarTop = Color(22, 30, 48, 0) + BarBottom = Color(13, 19, 33, 0) Accent = Color(120, 168, 196) Label = Color(176, 196, 214) Value = Color(228, 238, 246) - SegmentBackdrop = Color(4, 8, 16, 160) + SegmentBackdrop = Color(4, 8, 16, 170) Outline = Color(3, 6, 12, 255) } // ---- P43:右上日历钟卡(纯模型;季节/天数/时段/时钟全部由真实 tick 导出)---- |
