summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop
diff options
context:
space:
mode:
Diffstat (limited to 'src/LivingVillage.Desktop')
-rw-r--r--src/LivingVillage.Desktop/MapGen.fs35
1 files changed, 30 insertions, 5 deletions
diff --git a/src/LivingVillage.Desktop/MapGen.fs b/src/LivingVillage.Desktop/MapGen.fs
index 7c7059a..ce9bccf 100644
--- a/src/LivingVillage.Desktop/MapGen.fs
+++ b/src/LivingVillage.Desktop/MapGen.fs
@@ -72,6 +72,15 @@ module MapGen =
SpawnColumns = 5
SpawnRows = 6 }
+ /// P23 尺寸自适应参数:河道数量随高度增长(约每 96 行一条),其余沿用默认。
+ /// 64x48 / 256x192 仍得到 2 条河道,与既有输出逐字节一致;512x384 得到 4 条。
+ let paramsForSize (width: int) (height: int) (seed: uint64) : Params =
+ let base_ = defaultParams seed
+ { base_ with
+ Width = width
+ Height = height
+ RiverCount = max base_.RiverCount (max 1 (height / 96)) }
+
// ---- splitmix64 与 value noise(无外部依赖、无时钟) ----
let private splitmix (state: uint64) : uint64 * uint64 =
@@ -104,6 +113,10 @@ module MapGen =
(v00 * (1.0f - sx) + v10 * sx) * (1.0f - sy) + (v01 * (1.0f - sx) + v11 * sx) * sy
/// 2-3 octave 叠加;特征尺度随地图宽度等比缩放,保证小图/大图观感一致。
+ /// P23:特征尺度封顶(<=4x),避免 512x384 退化成过于平滑的「放大图」。
+ let private noiseWidthScale (width: int) : float32 =
+ min 4.0f (float32 width / 64.0f)
+
let private multiOctave (widthScale: float32) (x: int) (y: int) (seed: uint64) : float32 =
let xf = float32 x
let yf = float32 y
@@ -138,7 +151,7 @@ module MapGen =
x >= core.MinX && x <= core.MaxX && y >= core.MinY && y <= core.MaxY
// 1) 多八度噪声:低洼草地转泥炭(跳过核心区)。
- let widthScale = float32 w / 64.0f
+ let widthScale = noiseWidthScale w
for y in 0 .. h - 1 do
for x in 0 .. w - 1 do
if multiOctave widthScale x y p.Seed < 0.18f && not (inCore x y) then
@@ -148,14 +161,26 @@ module MapGen =
let riverWidth = max 3 p.RiverWidth
let riverBands =
[ for i in 0 .. max 0 p.RiverCount - 1 do
- if i % 2 = 0 then
+ if i = 0 then
let centerY = max 1 (min (h - 1 - riverWidth) (min (core.MinY - riverWidth - 2) (h / 4)))
if centerY + riverWidth - 1 < core.MinY then
yield { CenterY = centerY; Width = riverWidth }
- else
+ elif i = 1 then
let centerY = max 1 (min (h - 1 - riverWidth) (max (core.MaxY + 2) (3 * h / 4)))
if centerY > core.MaxY then
- yield { CenterY = centerY; Width = riverWidth } ]
+ yield { CenterY = centerY; Width = riverWidth }
+ else
+ // P23:第 3 条起在核心上/下方逐层外扩堆叠,互不重叠、不压核心。
+ let layer = (i - 1) / 2
+ let offset = if i % 2 = 1 then layer - 1 else layer
+ if i % 2 = 0 then
+ let centerY = core.MinY - riverWidth - 2 - offset * (riverWidth + 3)
+ if centerY >= 1 then
+ yield { CenterY = centerY; Width = riverWidth }
+ else
+ let centerY = core.MaxY + 2 + offset * (riverWidth + 3)
+ if centerY + riverWidth - 1 <= h - 2 then
+ yield { CenterY = centerY; Width = riverWidth } ]
for river in riverBands do
for x in 1 .. w - 2 do
for dy in 0 .. river.Width - 1 do
@@ -310,7 +335,7 @@ module MapGen =
BridgeCrossingsOk = crossingsOk }
let generateWithSize (width: int) (height: int) (seed: uint64) : Result =
- generate { defaultParams seed with Width = width; Height = height }
+ generate (paramsForSize width height seed)
/// 生成结果的确定性序列化(同 seed 逐字节一致),供回归测试与跨机核对。
let serialize (map: Result) : string =