summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-21 20:22:28 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-21 20:22:28 +0800
commita16d0cd0c079530385b53026133c93af69be5628 (patch)
tree57af594df24e173fc3a03c42b328e2ae21ef75cf /src/LivingVillage.Desktop
parent63e9741816ce3717cfda4cc3354ff3a0860a3ddc (diff)
downloadliving-village-a16d0cd0c079530385b53026133c93af69be5628.tar.gz
feat(desktop): 接入角色走路/待机动画并参数化录帧
- 新增 avatarMoving(比较前后位置)驱动走路/待机帧切换, 覆盖采样、地图巡游与手动输入三条路径 - 录帧目录与间隔改为环境变量 LV_RECORD_DIR / LV_RECORD_EVERY (默认 /tmp/lv-p5-prompt、25),便于证据落到指定目录
Diffstat (limited to 'src/LivingVillage.Desktop')
-rw-r--r--src/LivingVillage.Desktop/Game.fs25
1 files changed, 21 insertions, 4 deletions
diff --git a/src/LivingVillage.Desktop/Game.fs b/src/LivingVillage.Desktop/Game.fs
index cbe2b9d..c91fe6e 100644
--- a/src/LivingVillage.Desktop/Game.fs
+++ b/src/LivingVillage.Desktop/Game.fs
@@ -130,6 +130,7 @@ type LivingVillageGame() as this =
let mutable world = createInitialWorld ()
let mutable camera = Vector2.Zero
let mutable avatarFacing = VillageArt.SouthFacing
+ let mutable avatarMoving = false
let mutable fpsFrames = 0
let mutable fpsSeconds = 0.0
let mutable prevKb = Unchecked.defaultof<KeyboardState>
@@ -148,6 +149,14 @@ type LivingVillageGame() as this =
let mutable hudStatusAt = 0L
let mutable pauseHelpControl: SimulationControl option = None
let recordMode = Environment.GetEnvironmentVariable("LV_AUTOPLAY_RECORD") = "1"
+ let recordDirectory =
+ match Environment.GetEnvironmentVariable("LV_RECORD_DIR") with
+ | null | "" -> "/tmp/lv-p5-prompt"
+ | v -> v
+ let recordEvery = int (
+ match Environment.GetEnvironmentVariable("LV_RECORD_EVERY") with
+ | null | "" -> 25
+ | v -> match Int32.TryParse v with (true, value) -> max 1 value | _ -> 25)
let mutable recordIndex = 0
let mutable scale = int (
match Environment.GetEnvironmentVariable("LV_MAP_SCALE") with
@@ -191,6 +200,7 @@ type LivingVillageGame() as this =
relationView <- false
relationSnapshot <- None
avatarFacing <- VillageArt.SouthFacing
+ avatarMoving <- false
m5View <- M5Interaction.refreshPrompt world M5Interaction.initial
this.CenterCamera()
@@ -280,6 +290,7 @@ type LivingVillageGame() as this =
let nextWorld, nextView, nextState = SampleScript.runFrame world m5View sampleState
if nextWorld.Avatar.Pos <> positionBefore then
avatarFacing <- VillageArt.facingAfterMovement positionBefore nextWorld.Avatar.Pos avatarFacing
+ avatarMoving <- nextWorld.Avatar.Pos <> positionBefore
world <- nextWorld
m5View <- nextView
sampleState <- nextState
@@ -300,6 +311,7 @@ type LivingVillageGame() as this =
for _ in 0 .. 7 do
world <- Sim.step { Input = { MoveX = 0.0f; MoveY = 0.0f } } world
avatarFacing <- VillageArt.SouthFacing
+ avatarMoving <- false
m5View <- M5Interaction.refreshPrompt world m5View
this.CenterCamera()
tourFrame <- tourFrame + 1
@@ -413,10 +425,15 @@ type LivingVillageGame() as this =
let ts = { Input = input }
let stepCount = SimulationControl.stepsPerFrameWithLegacy legacyStepsPerFrame simulationControl
if stepCount > 0 then
+ let mutable moved = false
for _ in 1 .. stepCount do
let previousPosition = world.Avatar.Pos
world <- Sim.step ts world
avatarFacing <- VillageArt.facingAfterMovement previousPosition world.Avatar.Pos avatarFacing
+ moved <- moved || world.Avatar.Pos <> previousPosition
+ avatarMoving <- moved
+ else
+ avatarMoving <- false
this.CenterCamera()
m5View <- M5Interaction.refreshPrompt world m5View
@@ -577,8 +594,8 @@ type LivingVillageGame() as this =
this.DrawWorldView()
if recordMode && sampleMode then
recordIndex <- recordIndex + 1
- if recordIndex % 25 = 0 then
- let directory = "/tmp/lv-p5-prompt"
+ if recordIndex % recordEvery = 0 then
+ let directory = recordDirectory
System.IO.Directory.CreateDirectory directory |> ignore
let width, height =
this.GraphicsDevice.PresentationParameters.BackBufferWidth,
@@ -710,7 +727,7 @@ type LivingVillageGame() as this =
match m5View.HomeMode with
| Inside _ ->
VillageArt.drawInterior spriteBatch pixel artTextures viewport.Width viewport.Height renderPlan.Interior profile.WorldTint
- let interiorAvatarSpec = VillageArt.avatarSpriteSpec avatarFacing world.Tick
+ let interiorAvatarSpec = VillageArt.avatarSpriteSpec avatarFacing avatarMoving world.Tick
VillageArt.drawInteriorCharacter spriteBatch artTextures viewport.Width viewport.Height world.Avatar.Pos interiorAvatarSpec profile.WorldTint
| Outside ->
VillageArt.drawWorld
@@ -742,7 +759,7 @@ type LivingVillageGame() as this =
spriteBatch.Draw(pixel, Rectangle(screenX - 12, screenY - 12, 40, 40), Color(255, 226, 168, haloAlpha))
| _ -> ()
- let avatarSpec = VillageArt.avatarSpriteSpec avatarFacing world.Tick
+ let avatarSpec = VillageArt.avatarSpriteSpec avatarFacing avatarMoving world.Tick
VillageArt.drawCharacter spriteBatch artTextures camera world.Avatar.Pos avatarSpec profile.WorldTint
for npc in world.Npcs do