diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-28 20:58:24 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-28 20:58:24 +0800 |
| commit | e46f1ddda07fc9c3d2617663ed28a3d1391c198b (patch) | |
| tree | 01c5b074622a8d5ea58f6b11308165145c71b8d8 /src/LivingVillage.Desktop/Game.fs | |
| parent | f571b56359e4bb152b414a61527c4e9c6ef4cd53 (diff) | |
| download | living-village-e46f1ddda07fc9c3d2617663ed28a3d1391c198b.tar.gz | |
p47: 整改 — 倒影改暖色垂直光柱(gap-skip穿桥面落水面,最长≥3格)+近景接入倒影+近景屋顶受光/背光双档luma
Diffstat (limited to 'src/LivingVillage.Desktop/Game.fs')
| -rw-r--r-- | src/LivingVillage.Desktop/Game.fs | 127 |
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 |
