diff options
Diffstat (limited to 'src/LivingVillage.Desktop/SceneDetail.fs')
| -rw-r--r-- | src/LivingVillage.Desktop/SceneDetail.fs | 74 |
1 files changed, 57 insertions, 17 deletions
diff --git a/src/LivingVillage.Desktop/SceneDetail.fs b/src/LivingVillage.Desktop/SceneDetail.fs index c51c47a..50313ac 100644 --- a/src/LivingVillage.Desktop/SceneDetail.fs +++ b/src/LivingVillage.Desktop/SceneDetail.fs @@ -17,14 +17,24 @@ module SceneDetail = x >= 0 && x < map.Width && y >= 0 && y < map.Height && map.Tiles.[y * map.Width + x] = int MapGen.GroundTile.Water + /// 可倒影水面:河面(Water)与水田(PaddyField,同样走水面动画渲染)。 + let isWaterSurface (map: MapGen.Result) (x: int) (y: int) : bool = + x >= 0 && x < map.Width && y >= 0 && y < map.Height + && (map.Tiles.[y * map.Width + x] = int MapGen.GroundTile.Water + || map.Tiles.[y * map.Width + x] = int MapGen.GroundTile.PaddyField) + // ---------------- 河道水面倒影 ---------------- - let reflectionMaxAlpha = 128 - let reflectionRange = 3 + let reflectionMaxAlpha = 200 + let reflectionRange = 4 + /// 倒影射线允许穿过的非水面格数(如灯笼所立的桥面/岸沿),使「桥下红灯笼」的倒影 + /// 仍落在其正下方的河面,而不是被桥面格截断。 + let reflectionGap = 3 - /// 倒影 alpha 随离光源距离递减;到 0 即止,绝不留下硬块。 + /// 倒影 alpha 随离光源距离递减;最低仍保持 96,保证整条暖色光柱在蓝灰水面上 + /// 始终可辨(不会淡到被水面波纹吞掉)。 let reflectionAlphaAt (distance: int) : int = - max 0 (reflectionMaxAlpha - distance * 34) + max 96 (reflectionMaxAlpha - (distance - 1) * 26) /// 倒影微抖:复用 waterFrameTickAt 的 3 相位,映射到 -1 / 0 / +1 像素水平位移。 let reflectionWobbleAt (tick: int64) (x: int) (y: int) : int = @@ -33,20 +43,50 @@ module SceneDetail = | 1 -> 0 | _ -> 1 - /// 岸上光源:桥头灯笼 + 主路石灯笼 + 门口红灯笼,去重后即倒影源。 + /// 光源类型:桥头灯笼 / 主路石灯笼 / 门口红灯笼。倒影按类型着色。 + type LightKind = + | BridgeLantern + | RoadLantern + | RedLantern + + /// 岸上光源(含类型),按位置去重。 + let lightSources (map: MapGen.Result) : (int * int * LightKind) list = + let bridge = VillageArt.bridgeLanternTiles map |> List.map (fun (x, y) -> x, y, BridgeLantern) + let road = VillageArt.cc0LanternTiles map 12 |> List.map (fun (x, y) -> x, y, RoadLantern) + let red = VillageArt.cc0RedLanternTiles map |> List.map (fun (x, y) -> x, y, RedLantern) + (bridge @ road @ red) + |> List.distinctBy (fun (x, y, _) -> x, y) + let lightSourceTiles (map: MapGen.Result) : (int * int) list = - (VillageArt.bridgeLanternTiles map - @ VillageArt.cc0LanternTiles map 12 - @ VillageArt.cc0RedLanternTiles map) - |> List.distinct - - /// 每个光源在其正下方连续水面格生成一条垂直倒影 (x, y, alpha)。 - let reflectionStreaks (map: MapGen.Result) : (int * int * int) list = - lightSourceTiles map - |> List.collect (fun (sx, sy) -> - [ for d in 1 .. reflectionRange do - let y = sy + d - if isWater map sx y then yield (sx, y, reflectionAlphaAt d) ]) + lightSources map |> List.map (fun (x, y, _) -> x, y) + + /// 某个光源向下的倒影:先穿过至多 reflectionGap 格非水面(桥面/岸沿),落到正下方 + /// 水面上,再沿连续水面画最多 reflectionRange 格;返回 (x, y, alpha, kind)。 + let reflectionStreakFor (map: MapGen.Result) (sx: int) (sy: int) (kind: LightKind) : (int * int * int * LightKind) list = + let mutable start = sy + 1 + let mutable gap = 0 + while gap <= reflectionGap && start < map.Height && not (isWaterSurface map sx start) do + start <- start + 1 + gap <- gap + 1 + if start >= map.Height || gap > reflectionGap || not (isWaterSurface map sx start) then + [] + else + [ for d in 0 .. reflectionRange - 1 do + let y = start + d + if isWaterSurface map sx y then yield (sx, y, reflectionAlphaAt (d + 1), kind) ] + + /// 光源正下方倒影的格数(用于挑选倒影长度足够的取证机位)。 + let reflectionLength (map: MapGen.Result) (x: int) (sy: int) : int = + lightSources map + |> List.filter (fun (sx, syy, _) -> sx = x && syy = sy) + |> List.tryHead + |> Option.map (fun (sx, syy, kind) -> reflectionStreakFor map sx syy kind |> List.length) + |> Option.defaultValue 0 + + /// 每个光源在其正下方连续水面格生成一条垂直倒影 (x, y, alpha, kind),最长 4 格。 + let reflectionStreaks (map: MapGen.Result) : (int * int * int * LightKind) list = + lightSources map + |> List.collect (fun (sx, sy, kind) -> reflectionStreakFor map sx sy kind) // ---------------- 岸边植被加密度 ---------------- |
