summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop/Game.fs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-21 10:12:20 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-21 10:12:20 +0800
commit9df2da41289f4d0852f86e86eae81ca7f7e7b598 (patch)
treebca1a071e3369a9e2ebbf5e424da3dd45547f2be /src/LivingVillage.Desktop/Game.fs
parentc932969539b00a42937f0aa5ed1e10b4e94932a3 (diff)
downloadliving-village-9df2da41289f4d0852f86e86eae81ca7f7e7b598.tar.gz
fix(desktop): 修复 HUD 缺字并统一轻量面板与情境提示
字符表扩充至 197 字(补 间/门/谈/体/屋/返/×/,/:等全部 UI 用字),用 Noto Sans CJK 重新生成图集并逐字校验;新增字符表覆盖全部 UI 文案、瞬态状态 2.5 秒过期、对话完成后回到轻量面板等回归测试;户外与室内统一左下角轻量 HUD,互动日志改为短暂反馈;样例脚本保留 E 交谈 提示与对话菜单停留帧。
Diffstat (limited to 'src/LivingVillage.Desktop/Game.fs')
-rw-r--r--src/LivingVillage.Desktop/Game.fs49
1 files changed, 34 insertions, 15 deletions
diff --git a/src/LivingVillage.Desktop/Game.fs b/src/LivingVillage.Desktop/Game.fs
index 62102a7..a5049f3 100644
--- a/src/LivingVillage.Desktop/Game.fs
+++ b/src/LivingVillage.Desktop/Game.fs
@@ -142,6 +142,9 @@ type LivingVillageGame() as this =
let mutable autoplayFrames = 0
let mutable flowStep = 0
let mutable sampleState = SampleScript.initial
+ let mutable hudClock = 0L
+ let mutable hudStatus = ""
+ let mutable hudStatusAt = 0L
do
graphics.PreferredBackBufferWidth <- 1280
@@ -179,12 +182,12 @@ type LivingVillageGame() as this =
member private this.SaveWorld (prefix: string) : bool =
try
WorldSave.saveToFile savePath world
- m5View <- { m5View with Status = "save succeeded" }
+ m5View <- { m5View with Status = "save succeeded"; StatusTick = Some world.Tick }
printfn $"{prefix}=ok path={savePath} tick={world.Tick}"
true
with
| ex ->
- m5View <- { m5View with Status = "save failed" }
+ m5View <- { m5View with Status = "save failed"; StatusTick = Some world.Tick }
printfn $"{prefix}=error path={savePath} message={ex.Message}"
false
@@ -440,6 +443,10 @@ type LivingVillageGame() as this =
this.UpdatePlaying gameTime kb pressed pressedAny
else
this.UpdateMenu pressed
+ hudClock <- hudClock + 1L
+ if m5View.Status <> hudStatus then
+ hudStatus <- m5View.Status
+ hudStatusAt <- hudClock
fpsFrames <- fpsFrames + 1
fpsSeconds <- fpsSeconds + gameTime.ElapsedGameTime.TotalSeconds
if fpsSeconds >= 1.0 then
@@ -582,23 +589,35 @@ type LivingVillageGame() as this =
member private this.DrawM5Overlay() =
let viewport = this.GraphicsDevice.Viewport
- let panelWidth = min 460 (max 1 (viewport.Width - 32))
- let panelHeight = min 520 (max 1 (viewport.Height - 32))
- let panelX = max 16 (viewport.Width - panelWidth - 16)
- let panelY = 16
- let panel = Rectangle(panelX, panelY, panelWidth, panelHeight)
- let innerX = panelX + 16
- let innerWidth = panelWidth - 32
let textScale = 2
let lineHeight = 18
- let maxChars = max 1 (innerWidth / (6 * textScale))
- let maxLines = max 1 ((panelHeight - 32) / lineHeight)
let profile = M6Presentation.profileAtTick world.Tick
- let m6Lines = [ sprintf "时间 %s %s" (M6Presentation.dayNightLabel profile.Mode) (M6Presentation.clockLabel simulationControl) ]
- let lines = (m6Lines @ M5Interaction.panelLines world m5View) |> List.truncate maxLines
+ let timeLine = sprintf "时间 %s %s" (M6Presentation.dayNightLabel profile.Mode) (M6Presentation.clockLabel simulationControl)
+ let persistentLines =
+ timeLine :: (m5View.Prompt |> Option.toList)
+ let dialogueLines =
+ match m5View.Panel, m5View.Menu with
+ | DialoguePanel, Some menu ->
+ menu.Options
+ |> List.mapi (fun index intent -> sprintf "%d %s" (index + 1) (M5Interaction.intentLine intent))
+ |> fun options -> [ sprintf "互动:村民 %d" (M5Interaction.menuNpcNumber menu) ] @ options
+ | _ -> []
+ let statusView = { m5View with StatusTick = Some hudStatusAt }
+ let statusLine = M5Interaction.transientStatusLine hudClock statusView |> Option.toList
+ let allLines = persistentLines @ dialogueLines @ statusLine
+ let panelWidth = min 360 (max 1 (viewport.Width - 32))
+ let maxLines = max 1 ((viewport.Height - 48) / lineHeight)
+ let lines = allLines |> List.truncate maxLines
+ let panelHeight = lines.Length * lineHeight + 24
+ let panelX = 16
+ let panelY = max 16 (viewport.Height - panelHeight - 16)
+ let panel = Rectangle(panelX, panelY, panelWidth, panelHeight)
+ let innerX = panelX + 12
+ let innerWidth = max 1 (panelWidth - 24)
+ let maxChars = max 1 (innerWidth / (6 * textScale))
spriteBatch.Begin()
- spriteBatch.Draw(pixel, panel, Color(15, 19, 25, 220))
- spriteBatch.Draw(pixel, Rectangle(panelX, panelY, panelWidth, 4), Color(92, 180, 190))
+ spriteBatch.Draw(pixel, panel, Color(15, 19, 25, 160))
+ spriteBatch.Draw(pixel, Rectangle(panelX, panelY, panelWidth, 3), Color(92, 180, 190))
lines
|> List.iteri (fun index line ->
let visible = if line.Length > maxChars then line.Substring(0, maxChars) else line