diff options
Diffstat (limited to 'src/LivingVillage.Desktop')
| -rw-r--r-- | src/LivingVillage.Desktop/Assets/cc0-tiles.png | bin | 388 -> 816 bytes | |||
| -rw-r--r-- | src/LivingVillage.Desktop/VillageArt.fs | 95 |
2 files changed, 81 insertions, 14 deletions
diff --git a/src/LivingVillage.Desktop/Assets/cc0-tiles.png b/src/LivingVillage.Desktop/Assets/cc0-tiles.png Binary files differindex 204eba2..afa46a4 100644 --- a/src/LivingVillage.Desktop/Assets/cc0-tiles.png +++ b/src/LivingVillage.Desktop/Assets/cc0-tiles.png diff --git a/src/LivingVillage.Desktop/VillageArt.fs b/src/LivingVillage.Desktop/VillageArt.fs index 9a034aa..80eed07 100644 --- a/src/LivingVillage.Desktop/VillageArt.fs +++ b/src/LivingVillage.Desktop/VillageArt.fs @@ -553,7 +553,20 @@ module VillageArt = let cc0TileAtlasRelativePath = "Assets/cc0-tiles.png" // Source ground tiles are 16x16, upscaled exactly 2x to one Sim.tilePixels cell. let cc0TileSourcePixels = 16 - let cc0TileAtlasWidth = Sim.tilePixels * 4 + // P34 structure slice: indices into cc0-tiles.png. Kenney Tiny Farm ships no + // water / roof / wall / railing / door art, so indices 4-11 are self-drawn + // (provenance in docs/素材来源.md), laid out by this fixed contract. + let cc0TileCount = 12 + let cc0TileIndexWaterA = 4 + let cc0TileIndexWaterB = 5 + let cc0TileIndexRoofRidge = 6 + let cc0TileIndexRoofEave = 7 + let cc0TileIndexWallWood = 8 + let cc0TileIndexWallWindow = 9 + let cc0TileIndexRailing = 10 + let cc0TileIndexDoor = 11 + let cc0WaterFrameCount = 2 + let cc0TileAtlasWidth = Sim.tilePixels * cc0TileCount let cc0TileAtlasHeight = Sim.tilePixels let cc0CharacterAtlasRelativePath = "Assets/cc0-characters.png" // Source Puny band is 16x24, upscaled exactly 2x to a 32x48 cell; atlas packs @@ -568,6 +581,16 @@ module VillageArt = let cc0CharacterAtlasWidth = cc0CharacterCellWidth * cc0CharacterVariantCount * cc0CharacterDirectionCount * cc0CharacterFrameCount + /// Deterministic 2-phase water per tile: `(tick/32 + x + 2y) mod 2`, so one frame + /// shows both ripple phases across the river. Mirrors the 3-phase Jiangnan + /// `waterFrameTickAt`, but only two self-drawn CC0 frames exist. + let cc0WaterTileIndexAt (tick: int64) (tileX: int) (tileY: int) : int = + let phase = int ((tick / 32L + int64 (tileX + 2 * tileY)) % 2L) + if phase = 0 then cc0TileIndexWaterA else cc0TileIndexWaterB + + let cc0TileRect (index: int) : XnaRectangle = + XnaRectangle(index * Sim.tilePixels, 0, Sim.tilePixels, Sim.tilePixels) + /// Ground atlas selection: `Some cc0-tiles.png` when the pack is on, else `None` /// so the renderer keeps its procedural Jiangnan ground as the fallback. let selectedGroundAtlasRelativePath () : string option = @@ -792,6 +815,20 @@ module VillageArt = let draw position sprite = drawWorldTile spriteBatch textures camera viewportWidth viewportHeight position sprite tint + // P34: with the CC0 pack on, individual sample structures draw from the + // real/self-drawn cc0-tiles atlas; otherwise every draw falls back to jiangnan. + let drawCc0At (position: TilePosition) (index: int) = + match textures.Cc0TileAtlas with + | Some cc0 -> + drawCc0Tile + spriteBatch + cc0 + tint + (cc0TileRect index) + (position.X * Sim.tilePixels - int camera.X) + (position.Y * Sim.tilePixels - int camera.Y) + | None -> () + // Each water tile picks its phase from its own world coordinates, so a single // frame shows the three ripple phases across the river instead of one global frame. let waterSpriteAt (position: TilePosition) = @@ -800,15 +837,41 @@ module VillageArt = | 1 -> WaterSpriteB | _ -> WaterSpriteC + // P34 water: the self-drawn CC0 atlas only has two frames, so it picks the + // 2-phase index; the jiangnan atlas keeps its 3-phase ripple. + let drawWater (position: TilePosition) = + match textures.Cc0TileAtlas with + | Some _ -> drawCc0At position (cc0WaterTileIndexAt tick position.X position.Y) + | None -> draw position (waterSpriteAt position) + + // P34 structures: real/self-drawn roof, wall, window and door cells replace + // the jiangnan house tiles only when the CC0 pack is on. + let houseSpriteAt (position: TilePosition) (sprite: TileSprite) = + let cc0Index = + match textures.Cc0TileAtlas with + | Some _ -> + match sprite with + | RoofRidgeSprite -> Some cc0TileIndexRoofRidge + | RoofEaveSprite -> Some cc0TileIndexRoofEave + | WallWoodSprite -> Some cc0TileIndexWallWood + | WallWindowSprite -> Some cc0TileIndexWallWindow + | DoorSprite -> Some cc0TileIndexDoor + | _ -> None + | None -> None + match cc0Index with + | Some index -> drawCc0At position index + | None -> draw position sprite + // 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) + | 1 -> drawWater position | 2 -> draw position StonePathSprite - // P30 乡村空区:水田(4)走静态水面素材、菜畦(5)走菜地素材;均为成熟 tile。 - | 4 -> draw position WaterSprite + // P30 乡村空区:水田(4)走水波动画、菜畦(5)走菜地素材;均为成熟 tile。 + // P34:水田/水网在 CC0 包下同样走自绘 2 相位水面。 + | 4 -> drawWater position | 5 -> draw position GardenSprite | _ -> draw position GrassSprite @@ -851,7 +914,7 @@ module VillageArt = for localPosition, kind in planGrounds do let position = worldTile plan localPosition match kind with - | Water -> draw position (waterSpriteAt position) + | Water -> drawWater position | StonePath -> match textures.Cc0TileAtlas with | Some cc0 -> drawCc0Tile spriteBatch cc0 tint cc0PathRect (position.X * Sim.tilePixels - int camera.X) (position.Y * Sim.tilePixels - int camera.Y) @@ -860,18 +923,22 @@ module VillageArt = let drawHouse doorTile = let position = worldTile plan doorTile for dx in -2 .. 1 do - draw (offsetTile position dx -2) RoofRidgeSprite - draw (offsetTile position dx -1) RoofEaveSprite - draw (offsetTile position -2 0) WallWoodSprite - draw (offsetTile position -1 0) WallWindowSprite - draw (offsetTile position 0 0) DoorSprite - draw (offsetTile position 1 0) WallWoodSprite + houseSpriteAt (offsetTile position dx -2) RoofRidgeSprite + houseSpriteAt (offsetTile position dx -1) RoofEaveSprite + houseSpriteAt (offsetTile position -2 0) WallWoodSprite + houseSpriteAt (offsetTile position -1 0) WallWindowSprite + houseSpriteAt (offsetTile position 0 0) DoorSprite + houseSpriteAt (offsetTile position 1 0) WallWoodSprite let drawBridge localPosition = let position = worldTile plan localPosition - draw position BridgeSprite - draw (offsetTile position 0 1) BridgeSprite - draw (offsetTile position 0 2) BridgeSprite + let bridgeTile p = + match textures.Cc0TileAtlas with + | Some _ -> drawCc0At p cc0TileIndexRailing + | None -> draw p BridgeSprite + bridgeTile position + bridgeTile (offsetTile position 0 1) + bridgeTile (offsetTile position 0 2) let drawBamboo localPosition = let position = worldTile plan localPosition |
