summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop/VillageArt.fs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-22 12:41:06 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-22 12:41:06 +0800
commit92bcc9b9fc4eeea4f11913a0de2a34811b262dfd (patch)
tree7fa25b2a3fc2ebeea7b2fe2cbc6285848d7c0a26 /src/LivingVillage.Desktop/VillageArt.fs
parent4034f55ee0b9cbd8c9db5f850e10e21e15fb7274 (diff)
downloadliving-village-92bcc9b9fc4eeea4f11913a0de2a34811b262dfd.tar.gz
feat(desktop): P30 512 民居增密 + 乡村空区填充 + 主路柔化
- MapGen(仅大图尺寸自适应分支,默认 64x48/256x192 不进入、不消费额外 RNG): ① ExtraRiversideHouses 16 -> 30,组团 2-5 座;含基础岸屋的路段优先布组并为每座孤立 基础民居贴格配对,placeGroup 试排后按「与既有/同组民居足迹间隙 <=2」过滤,孤立单屋不落地。 512 seed4242:组团民居 24 -> 45,规模 [5;4x6;3x2;2x3],0 组 <2 座。 ② 新增 GroundTile.PaddyField=4/VegetablePlot=5(成熟 tile;非水可通行)+ Result.Groves (纯视觉)+ Result.Farmhouses(门贴院落路、计入 BFS);18x14 确定性网格铺田块/树丛/农舍, 离水 >=3 格、避开路网/核心/民居。草地瓦片 96.3% -> 83.9%,水田 11595 + 菜畦 12877 格。 ③ Result.MainRoadCenter 逐列中心线,value noise(scale 130、幅度 ±3)确定性缓弯, 相邻列步长 <=1、遇弯补格保证 4 连通;默认图主街仍笔直。 - VillageArt:水田/菜畦/树丛/农舍渲染(复用成熟 sprite 与同一立面纯函数)、农舍门窗计入夜光、 新增 drawMapRegion 局部真实离屏渲染。 - Game:P30 证据钩子 LV_MAPGEN_P30_SHOT=1(整图 3072x2304 day/night + 田块/主路 512x256@4px)。 - 回归 +5:组团规模/空区填充/田块合规/农舍可达确定性/主路确定性弯曲。 Kernel 92 / Desktop 156 全绿;Release 0 警告 0 错误; final_digest=953775FAEB2F… 3 次一致、performance_determinism=PASS; 64x48=6042052、256x192=1284656962 锁定不变。
Diffstat (limited to 'src/LivingVillage.Desktop/VillageArt.fs')
-rw-r--r--src/LivingVillage.Desktop/VillageArt.fs59
1 files changed, 57 insertions, 2 deletions
diff --git a/src/LivingVillage.Desktop/VillageArt.fs b/src/LivingVillage.Desktop/VillageArt.fs
index 3e52546..4faa886 100644
--- a/src/LivingVillage.Desktop/VillageArt.fs
+++ b/src/LivingVillage.Desktop/VillageArt.fs
@@ -656,7 +656,7 @@ module VillageArt =
spriteBatch.Draw(textures.TileAtlas, XnaRectangle(tileX x, tileY y, cell, cell), tileSourceRectangle sprite, XnaColor.White)
for (x, y) in map.Bridges do
spriteBatch.Draw(textures.TileAtlas, XnaRectangle(tileX x, tileY y, cell, cell), bridgeSource, XnaColor.White)
- for building in map.Buildings do
+ let drawHouse (building: MapGen.Building) =
let left = building.Left
let right = building.Left + building.Width - 1
match houseFacadeVariant building with
@@ -690,6 +690,11 @@ module VillageArt =
let wallSprite =
if x = building.DoorX then CourtyardDoorSprite else WallLatticeSprite
drawCell wallSprite x building.DoorY
+ for building in map.Buildings do
+ drawHouse building
+ // P30 散落农舍与沿河民居共用同一套立面纯函数。
+ for farmhouse in map.Farmhouses do
+ drawHouse farmhouse
// P26 河岸装饰:护岸石垒 / 芦苇 / 垂柳(垂柳占上下两格),只在大图生成。
for decoration in map.Decorations do
match decoration.Kind with
@@ -698,6 +703,11 @@ module VillageArt =
| MapGen.RiverDecorationKind.Willow ->
drawCell WillowTopSprite decoration.X decoration.Y
drawCell WillowBaseSprite decoration.X (decoration.Y + 1)
+ // P30 乡村树丛:竹丛 / 灌木丛(纯视觉,不写瓦片、不影响通行)。
+ for grove in map.Groves do
+ match grove.Kind with
+ | MapGen.BambooClump -> drawCell BambooSprite grove.X grove.Y
+ | MapGen.ShrubClump -> drawCell ShrubSprite grove.X grove.Y
/// 桥头灯笼瓦片:每座桥每列的最上/最下一格(桥两端),用于挂灯笼与夜间暖光。
let bridgeLanternTiles (map: MapGen.Result) : (int * int) list =
@@ -710,10 +720,11 @@ module VillageArt =
/// P29 夜景灯光源瓦片:桥头灯笼 + 民居门窗暖光(确定性纯函数,便于单测)。
/// 每户至少门格发光;变体 A 再取第一扇横向窗,变体 B(整面格栅窗)与门同格故不另加。
+ /// P30:散落农舍的门窗暖光一并计入。
let nightLightTiles (map: MapGen.Result) : (int * int) list =
let lanterns = bridgeLanternTiles map
let houseLights =
- map.Buildings
+ (map.Buildings @ map.Farmhouses)
|> List.collect (fun building ->
let windowTiles =
if houseFacadeVariant building = 0 then
@@ -772,6 +783,9 @@ module VillageArt =
match code with
| 1 -> draw position (waterSpriteAt position)
| 2 -> draw position StonePathSprite
+ // P30 乡村空区:水田(4)走静态水面素材、菜畦(5)走菜地素材;均为成熟 tile。
+ | 4 -> draw position WaterSprite
+ | 5 -> draw position GardenSprite
| _ -> draw position GrassSprite
let drawBaseTile (position: TilePosition) =
@@ -907,6 +921,9 @@ module VillageArt =
match code with
| 1 -> WaterSprite
| 2 -> StonePathSprite
+ // P30 乡村空区:水田走静态水面、菜畦走菜地素材。
+ | 4 -> WaterSprite
+ | 5 -> GardenSprite
| _ -> GrassSprite
for y in 0 .. map.Height - 1 do
for x in 0 .. map.Width - 1 do
@@ -942,6 +959,8 @@ module VillageArt =
| 1 -> WaterSpriteB
| _ -> WaterSpriteC
| 2 -> StonePathSprite
+ | 4 -> WaterSprite
+ | 5 -> GardenSprite
| _ -> GrassSprite
let mutable drawn = 0
for y in y0 .. y1 do
@@ -954,6 +973,42 @@ module VillageArt =
drawNightGlows spriteBatch pixel map (4 * Sim.tilePixels) (int (150.0f * glowScale)) tileX tileY Sim.tilePixels
drawn
+ /// P30 证据用:把地图的任意 tile 矩形 [tileX0,tileY0,tilesW,tilesH] 以 cell px/tile 真实
+ /// 离屏渲染到 target(含民居/田块/树丛/桥/河岸装饰与可选夜光),返回绘制瓦片数。
+ /// 与 drawMapFitted/drawMapViewport 共用 drawMapStructures / drawNightGlows 纯函数。
+ let drawMapRegion
+ (spriteBatch: SpriteBatch)
+ (textures: ArtTextures)
+ (pixel: Texture2D)
+ (tileX0: int)
+ (tileY0: int)
+ (tilesW: int)
+ (tilesH: int)
+ (cell: int)
+ (map: MapGen.Result)
+ (tint: XnaColor)
+ (glowScale: float32) : int =
+ let tileX x = (x - tileX0) * cell
+ let tileY y = (y - tileY0) * cell
+ let spriteOf code =
+ match code with
+ | 1 -> WaterSprite
+ | 2 -> StonePathSprite
+ | 4 -> WaterSprite
+ | 5 -> GardenSprite
+ | _ -> GrassSprite
+ let mutable drawn = 0
+ for y in tileY0 .. tileY0 + tilesH - 1 do
+ for x in tileX0 .. tileX0 + tilesW - 1 do
+ if x >= 0 && x < map.Width && y >= 0 && y < map.Height then
+ let code = map.Tiles.[y * map.Width + x]
+ spriteBatch.Draw(textures.TileAtlas, XnaRectangle(tileX x, tileY y, cell, cell), tileSourceRectangle (spriteOf code), tint)
+ drawn <- drawn + 1
+ drawMapStructures spriteBatch textures pixel tileX tileY cell map
+ if glowScale > 0.0f then
+ drawNightGlows spriteBatch pixel map (4 * cell) (int (150.0f * glowScale)) tileX tileY cell
+ drawn
+
let drawCharacter
(spriteBatch: SpriteBatch)
(textures: ArtTextures)