summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop/Game.fs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-28 20:58:24 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-28 20:58:24 +0800
commite46f1ddda07fc9c3d2617663ed28a3d1391c198b (patch)
tree01c5b074622a8d5ea58f6b11308165145c71b8d8 /src/LivingVillage.Desktop/Game.fs
parentf571b56359e4bb152b414a61527c4e9c6ef4cd53 (diff)
downloadliving-village-e46f1ddda07fc9c3d2617663ed28a3d1391c198b.tar.gz
p47: 整改 — 倒影改暖色垂直光柱(gap-skip穿桥面落水面,最长≥3格)+近景接入倒影+近景屋顶受光/背光双档luma
Diffstat (limited to 'src/LivingVillage.Desktop/Game.fs')
-rw-r--r--src/LivingVillage.Desktop/Game.fs127
1 files changed, 83 insertions, 44 deletions
diff --git a/src/LivingVillage.Desktop/Game.fs b/src/LivingVillage.Desktop/Game.fs
index a187cc4..05afdc2 100644
--- a/src/LivingVillage.Desktop/Game.fs
+++ b/src/LivingVillage.Desktop/Game.fs
@@ -1004,60 +1004,98 @@ type LivingVillageGame() as this =
| None -> this.Exit()
| Some map ->
let riverside =
- // 取第一处「光源正下方有水面」的倒影点,相机对准其光源格,倒影落在正下方。
- match SceneDetail.reflectionStreaks map with
- | (rx, ry, _) :: _ -> (rx, ry - 1)
- | [] ->
- match VillageArt.cc0LanternTiles map 12 with
- | (lx, ly) :: _ -> (lx, ly)
- | [] ->
- match map.Bridges |> List.sortBy (fun (x, y) -> (x, y)) |> List.tryHead with
- | Some (bx, by) -> (bx, by)
- | None -> (map.Core.MinX, map.Core.MinY)
+ // 取倒影长度最长、优先桥头/红灯笼的光源,相机对准其光源格,倒影落在正下方。
+ let ranked =
+ SceneDetail.lightSources map
+ |> List.map (fun (x, y, kind) ->
+ let length = SceneDetail.reflectionLength map x y
+ let kindRank =
+ match kind with
+ | SceneDetail.RedLantern -> 2
+ | SceneDetail.BridgeLantern -> 1
+ | SceneDetail.RoadLantern -> 0
+ x, y, kind, length, kindRank)
+ let deep = ranked |> List.filter (fun (_, _, _, length, _) -> length >= 3)
+ let pick =
+ (if List.isEmpty deep then ranked else deep)
+ |> List.sortByDescending (fun (_, _, _, length, kindRank) -> kindRank, length)
+ |> List.tryHead
+ match pick with
+ | Some (x, y, _, _, _) -> (x, y)
+ | None ->
+ match SceneDetail.reflectionStreaks map with
+ | (rx, ry, _, _) :: _ -> (rx, ry - 1)
+ | [] -> (map.Core.MinX, map.Core.MinY)
let closeup =
- match SceneDetail.floatingProps map with
- | (fx, fy, _) :: _ -> (fx, fy)
+ // 近景:优先倒影更长、且离漂浮元素更近的光源,保证近景同时有倒影与漂浮元素。
+ let waterSources =
+ SceneDetail.lightSources map
+ |> List.filter (fun (x, y, _) -> SceneDetail.reflectionLength map x y >= 1)
+ let floatTiles = SceneDetail.floatingProps map |> List.map (fun (x, y, _) -> x, y)
+ let distToFloat (sx: int) (sy: int) =
+ if List.isEmpty floatTiles then 0
+ else floatTiles |> List.map (fun (fx, fy) -> abs (fx - sx) + abs (fy - sy)) |> List.min
+ match waterSources with
| [] -> riverside
- let reportVisibleReflections () =
+ | _ ->
+ waterSources
+ |> List.map (fun (x, y, _) -> x, y, SceneDetail.reflectionLength map x y, distToFloat x y)
+ |> List.sortBy (fun (_, _, length, distance) -> -length, distance)
+ |> List.head
+ |> fun (x, y, _, _) -> (x, y)
+ let reportVisibleReflections (shotName: string) =
let vw = this.GraphicsDevice.Viewport.Width
let vh = this.GraphicsDevice.Viewport.Height
- for (lx, ly) in SceneDetail.lightSourceTiles map do
- for d in 1 .. SceneDetail.reflectionRange do
- let ry = ly + d
- if SceneDetail.isWater map lx ry then
- let ssx = lx * Sim.tilePixels - int camera.X
- let ssy = ly * Sim.tilePixels - int camera.Y
- let rsx = lx * Sim.tilePixels - int camera.X
- let rsy = ry * Sim.tilePixels - int camera.Y
- if ssx >= 0 && ssx + Sim.tilePixels <= vw && ssy >= 0 && ssy + Sim.tilePixels <= vh
- && rsy + Sim.tilePixels <= vh then
+ for (lx, ly, kind) in SceneDetail.lightSources map do
+ for (rx, ry, alpha, _) in SceneDetail.reflectionStreakFor map lx ly kind do
+ let ssx = lx * Sim.tilePixels - int camera.X
+ let ssy = ly * Sim.tilePixels - int camera.Y
+ let rsx = rx * Sim.tilePixels - int camera.X
+ let rsy = ry * Sim.tilePixels - int camera.Y
+ // 空白对照:同排最近的非倒影水面格。
+ let control =
+ [ (2, 0); (-2, 0); (4, 0); (-4, 0); (0, 1); (0, -1) ]
+ |> List.map (fun (ox, oy) -> rx + ox, ry + oy)
+ |> List.tryFind (fun (cx, cy) -> SceneDetail.isWaterSurface map cx cy)
+ if ssx >= 0 && ssx + Sim.tilePixels <= vw && ssy >= 0 && ssy + Sim.tilePixels <= vh
+ && rsy + Sim.tilePixels <= vh then
+ match control with
+ | Some (cx, cy) ->
printfn
- "p47-reflection src=%d,%d dst=%d,%d alpha=%d"
- ssx ssy rsx rsy (SceneDetail.reflectionAlphaAt d)
+ "p47-reflection %s src=%d,%d dst=%d,%d ctrl=%d,%d alpha=%d"
+ shotName ssx ssy rsx rsy (cx * Sim.tilePixels - int camera.X) (cy * Sim.tilePixels - int camera.Y) alpha
+ | None ->
+ printfn "p47-reflection %s src=%d,%d dst=%d,%d ctrl=-1,-1 alpha=%d" shotName ssx ssy rsx rsy alpha
+ for (rx, ry, rw) in SceneDetail.foregroundRooftops vw vh world.Tick do
+ if rx + rw > 0 && rx < vw then
+ printfn "p47-roof %s x=%d y=%d w=%d" shotName rx ry rw
printfn
- "p47-elements reeds=%d floats=%d reflections=%d sources=%d"
+ "p47-elements reeds=%d floats=%d reflections=%d sources=%d maxstreak=%d"
(List.length (SceneDetail.bankReedTiles map))
(List.length (SceneDetail.floatingProps map))
(List.length (SceneDetail.reflectionStreaks map))
- (List.length (SceneDetail.lightSourceTiles map))
+ (List.length (SceneDetail.lightSources map))
+ (SceneDetail.lightSources map
+ |> List.map (fun (x, y, _) -> SceneDetail.reflectionLength map x y)
+ |> List.fold max 0)
match p47Step with
| 0 ->
setHour 12.0
placeCameraOn (fst riverside) (snd riverside)
- reportVisibleReflections ()
p47PendingName <- "p47-day"
+ reportVisibleReflections "p47-day"
p47Pending <- true
| 1 ->
setHour 23.5
placeCameraOn (fst riverside) (snd riverside)
- reportVisibleReflections ()
p47PendingName <- "p47-night"
+ reportVisibleReflections "p47-night"
p47Pending <- true
| 2 ->
setHour 12.0
placeCameraOn (fst closeup) (snd closeup)
- reportVisibleReflections ()
p47PendingName <- "p47-close"
+ reportVisibleReflections "p47-close"
p47Pending <- true
| _ ->
printfn "p47-shot=done"
@@ -2144,20 +2182,6 @@ type LivingVillageGame() as this =
world.Tick
profile.WorldTint
- // P47 场景细节:河道倒影 + 岸边芦苇加密度 + 漂浮元素 + 近景楼层层错落(统一光源阴影)。
- match riverscapeMap with
- | Some map ->
- SceneDetailRender.draw
- spriteBatch
- artTextures
- pixel
- camera
- viewport.Width
- viewport.Height
- map
- world.Tick
- | None -> ()
-
// Warm lantern / window glows strengthen as night falls (pure function of tick phase).
// Concentric premultiplied circles follow a quadratic radial falloff (radius 3-4 tiles),
// so the core stays a soft warm disc instead of saturating to a white block and no glow
@@ -2196,6 +2220,21 @@ type LivingVillageGame() as this =
VillageArt.drawCc0BoatOverlay spriteBatch artTextures camera map profile.WorldTint
| _ -> ()
+ // P47 场景细节:河道倒影 + 岸边芦苇加密度 + 漂浮元素 + 近景楼层层错落。
+ // 画在夜光/船之后,保证倒影不被灯笼呼吸光晕盖掉、仍可辨认。
+ match riverscapeMap with
+ | Some map ->
+ SceneDetailRender.draw
+ spriteBatch
+ artTextures
+ pixel
+ camera
+ viewport.Width
+ viewport.Height
+ map
+ world.Tick
+ | None -> ()
+
VillageArt.drawGroundShadow spriteBatch pixel camera world.Avatar.Pos
let avatarSpec = VillageArt.avatarSpriteSpec avatarFacing avatarMoving world.Tick
VillageArt.drawCharacter spriteBatch artTextures camera world.Avatar.Pos avatarSpec profile.WorldTint