summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop/VillageArt.fs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-22 03:13:42 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-22 03:13:42 +0800
commit2dd5ef0c5489f8fd656888f7d749a541101d5ad1 (patch)
tree4adeb67b100fc2bdc3b63d93633161f53b9c1331 /src/LivingVillage.Desktop/VillageArt.fs
parentd06656aa968ccb2769ba7c90c97f57f2818bb828 (diff)
downloadliving-village-2dd5ef0c5489f8fd656888f7d749a541101d5ad1.tar.gz
feat(mapgen): 默认可玩世界接入生成器 + 河景细节(P20 第三步 B)
- Game:默认 256x192 生成器世界(核心可达区站位),LV_LEGACY_MAP=1 / LV_MAP_SCALE>1 / LV_MAP_TOUR=1 回退旧路径;StartNewGame 走同一站位。 - VillageArt.drawWorld 新增 pixel 与 mapGen option:Some 时按生成器瓦片绘地面 并叠加桥面/沿河民居/门,跳过 64x48 样例平面与道具;水波沿用 waterFrameTickAt。 - 新增 bridgeLanternTiles;夜间 LanternGlow 沿用既有预乘同心圆(无过曝白芯), 生成器世界用桥头灯笼。 - 新增 LV_RIVERSCAPE_TOUR 真走位巡游与 LV_RECORD_NAME 录屏前缀(证据用)。
Diffstat (limited to 'src/LivingVillage.Desktop/VillageArt.fs')
-rw-r--r--src/LivingVillage.Desktop/VillageArt.fs108
1 files changed, 67 insertions, 41 deletions
diff --git a/src/LivingVillage.Desktop/VillageArt.fs b/src/LivingVillage.Desktop/VillageArt.fs
index 19c9aa6..3ad5b19 100644
--- a/src/LivingVillage.Desktop/VillageArt.fs
+++ b/src/LivingVillage.Desktop/VillageArt.fs
@@ -600,13 +600,48 @@ module VillageArt =
let private offsetTile (position: TilePosition) dx dy : TilePosition =
tilePosition (position.X + dx) (position.Y + dy)
+ let private fillRect (spriteBatch: SpriteBatch) (pixel: Texture2D) (color: XnaColor) (x: int) (y: int) (w: int) (h: int) =
+ spriteBatch.Draw(pixel, XnaRectangle(x, y, max 1 w, max 1 h), color)
+
+ /// 生成器世界里的桥面与沿河民居(白墙黑瓦色块 + 门);坐标由调用方按相机换算。
+ let private drawMapStructures
+ (spriteBatch: SpriteBatch)
+ (textures: ArtTextures)
+ (pixel: Texture2D)
+ (tileX: int -> int)
+ (tileY: int -> int)
+ (cell: int)
+ (map: MapGen.Result) =
+ let bridgeSource = tileSourceRectangle BridgeSprite
+ 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
+ for row in building.Top .. building.Top + building.Height - 1 do
+ // 白墙朝向道路一行(门所在行),其余为黑瓦屋顶,两侧河岸朝向一致。
+ let color =
+ if row = building.DoorY then XnaColor(236, 232, 220)
+ else XnaColor(48, 52, 60)
+ fillRect spriteBatch pixel color (tileX building.Left) (tileY row) (building.Width * cell) (cell)
+ fillRect spriteBatch pixel (XnaColor(96, 60, 42)) (tileX building.DoorX) (tileY building.DoorY) cell cell
+
+ /// 桥头灯笼瓦片:每座桥每列的最上/最下一格(桥两端),用于挂灯笼与夜间暖光。
+ let bridgeLanternTiles (map: MapGen.Result) : (int * int) list =
+ map.Bridges
+ |> List.groupBy fst
+ |> List.collect (fun (x, entries) ->
+ let ys = entries |> List.map snd
+ [ (x, List.min ys); (x, List.max ys) ])
+ |> List.distinct
+
let drawWorld
(spriteBatch: SpriteBatch)
(textures: ArtTextures)
+ (pixel: Texture2D)
(camera: XnaVector2)
(viewportWidth: int)
(viewportHeight: int)
(plan: JiangnanRenderPlan)
+ (mapGen: MapGen.Result option)
(tick: int64)
(tint: XnaColor) =
let draw position sprite =
@@ -622,26 +657,30 @@ module VillageArt =
// Procedural terrain for the 512x384 large world: water/pebble/peat codes map
// onto the jiangnan atlas sprites with deterministic ripple continuity.
+ // 生成器世界:1 水 / 2 石板路 / 3 泥炭 / 0 草地。泥炭按草地渲染,路走石板贴图。
let drawTerrainTile (position: TilePosition) (code: int) =
match code with
| 1 -> draw position (waterSpriteAt position)
| 2 -> draw position StonePathSprite
- | 3 -> draw position StonePathSprite
| _ -> draw position GrassSprite
let drawBaseTile (position: TilePosition) =
- match ProceduralMap.terrainOption, ProceduralMap.bigWorldActive with
- | (Some terrain, true) ->
- let tx, ty = position.X, position.Y
- let code = terrain.Tiles.[ty * ProceduralMap.width + tx]
- drawTerrainTile position code
- | _ ->
+ match mapGen with
+ | Some map ->
+ drawTerrainTile position map.Tiles.[position.Y * map.Width + position.X]
+ | None ->
+ match ProceduralMap.terrainOption, ProceduralMap.bigWorldActive with
+ | (Some terrain, true) ->
+ let tx, ty = position.X, position.Y
+ let code = terrain.Tiles.[ty * ProceduralMap.width + tx]
+ drawTerrainTile position code
+ | _ ->
+ match textures.Cc0TileAtlas with
+ | Some cc0 -> drawCc0Tile spriteBatch cc0 tint (cc0GroundRect position) (position.X * Sim.tilePixels - int camera.X) (position.Y * Sim.tilePixels - int camera.Y)
+ | None -> draw position GrassSprite
match textures.Cc0TileAtlas with
| Some cc0 -> drawCc0Tile spriteBatch cc0 tint (cc0GroundRect position) (position.X * Sim.tilePixels - int camera.X) (position.Y * Sim.tilePixels - int camera.Y)
| None -> draw position GrassSprite
- match textures.Cc0TileAtlas with
- | Some cc0 -> drawCc0Tile spriteBatch cc0 tint (cc0GroundRect position) (position.X * Sim.tilePixels - int camera.X) (position.Y * Sim.tilePixels - int camera.Y)
- | None -> draw position GrassSprite
let tx0, ty0, tx1, ty1 =
MapGen.visibleTileRange Sim.mapWidthTiles Sim.mapHeightTiles (int camera.X) (int camera.Y) viewportWidth viewportHeight
@@ -649,7 +688,19 @@ module VillageArt =
for x in tx0 .. tx1 do
drawBaseTile (tilePosition x y)
- for localPosition, kind in plan.Grounds do
+ // 生成器世界:叠加桥面、沿河民居、桥头灯笼;不再绘制 64x48 样例平面与道具。
+ match mapGen with
+ | Some map ->
+ let mapTileX x = x * Sim.tilePixels - int camera.X
+ let mapTileY y = y * Sim.tilePixels - int camera.Y
+ drawMapStructures spriteBatch textures pixel mapTileX mapTileY Sim.tilePixels map
+ for (lanternX, lanternY) in bridgeLanternTiles map do
+ draw (tilePosition lanternX lanternY) LanternSprite
+ | None -> ()
+
+ // 回退(64x48 样例世界)或 LV_MAP_SCALE 大世界时仍绘制样例地面/道具。
+ let planGrounds = match mapGen with Some _ -> [] | None -> plan.Grounds
+ for localPosition, kind in planGrounds do
let position = worldTile plan localPosition
match kind with
| Water -> draw position (waterSpriteAt position)
@@ -693,7 +744,8 @@ module VillageArt =
let drawSingleTile localPosition sprite =
draw (worldTile plan localPosition) sprite
- for prop in plan.Props do
+ let planProps = match mapGen with Some _ -> [] | None -> plan.Props
+ for prop in planProps do
match prop.Kind with
| House -> drawHouse prop.Position
| Bridge -> drawBridge prop.Position
@@ -717,37 +769,13 @@ module VillageArt =
| 0 -> SmokeSpriteA
| 1 -> SmokeSpriteB
| _ -> SmokeSpriteC
- for prop in plan.Props do
+ for prop in planProps do
match prop.Kind with
| House -> draw (offsetTile (worldTile plan prop.Position) 0 -3) smokeSprite
| _ -> ()
/// P20 证据用:把整张 MapGen 地图等比缩放到视口内绘制,返回绘制的瓦片数。
/// 仅用于 `LV_MAPGEN_SHOT` 整图取证,不参与正常游戏循环。
- let private fillRect (spriteBatch: SpriteBatch) (pixel: Texture2D) (color: XnaColor) (x: int) (y: int) (w: int) (h: int) =
- spriteBatch.Draw(pixel, XnaRectangle(x, y, max 1 w, max 1 h), color)
-
- /// 整图证据里叠加桥面与沿河民居(白墙黑瓦色块 + 门)。
- let private drawMapStructures
- (spriteBatch: SpriteBatch)
- (textures: ArtTextures)
- (pixel: Texture2D)
- (tileX: int -> int)
- (tileY: int -> int)
- (cell: int)
- (map: MapGen.Result) =
- let bridgeSource = tileSourceRectangle BridgeSprite
- 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
- for row in building.Top .. building.Top + building.Height - 1 do
- // 白墙朝向道路一行(门所在行),其余为黑瓦屋顶,两侧河岸朝向一致。
- let color =
- if row = building.DoorY then XnaColor(236, 232, 220)
- else XnaColor(48, 52, 60)
- fillRect spriteBatch pixel color (tileX building.Left) (tileY row) (building.Width * cell) (cell)
- fillRect spriteBatch pixel (XnaColor(96, 60, 42)) (tileX building.DoorX) (tileY building.DoorY) cell cell
-
let drawMapFitted
(spriteBatch: SpriteBatch)
(textures: ArtTextures)
@@ -767,8 +795,7 @@ module VillageArt =
let spriteOf code =
match code with
| 1 -> WaterSprite
- | 2
- | 3 -> StonePathSprite
+ | 2 -> StonePathSprite
| _ -> GrassSprite
for y in 0 .. map.Height - 1 do
for x in 0 .. map.Width - 1 do
@@ -799,8 +826,7 @@ module VillageArt =
| 0 -> WaterSprite
| 1 -> WaterSpriteB
| _ -> WaterSpriteC
- | 2
- | 3 -> StonePathSprite
+ | 2 -> StonePathSprite
| _ -> GrassSprite
let mutable drawn = 0
for y in y0 .. y1 do