diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-21 01:41:05 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-21 01:41:05 +0800 |
| commit | fc77481196aaea817eec991bdcf4dc22bb1d245c (patch) | |
| tree | 95df2d0bff79a742c7f3637fbec680f2e6945316 /src | |
| parent | b6b95988e525a68ea7426ecc9690b18a1b3bbfe8 (diff) | |
| download | living-village-fc77481196aaea817eec991bdcf4dc22bb1d245c.tar.gz | |
feat(desktop): 江南美术改为真实 PNG 图集
- scripts/make-jiangnan-art.py 生成三张原创透明 PNG:世界 256x32、角色 1024x48、内景 392x96
- VillageArt.fs 移除进程内像素烘焙,改为 BaseDirectory 加载图集并校验尺寸
- 内景渲染改用图集(地板/墙/窗/桌/床/屏/毯/柜),新增玩家专属 StrawHat 变体
- 内景新增地毯与柜子装饰,角色按 FeetPosition 定位
- fsproj 随包复制三张 PNG;m6c-package.sh 校验三张 PNG 进入交付包
Diffstat (limited to 'src')
| -rw-r--r-- | src/LivingVillage.Desktop.Tests/PrototypeTests.fs | 13 | ||||
| -rw-r--r-- | src/LivingVillage.Desktop/Assets/jiangnan-characters.png | bin | 0 -> 1892 bytes | |||
| -rw-r--r-- | src/LivingVillage.Desktop/Assets/jiangnan-interior.png | bin | 0 -> 1613 bytes | |||
| -rw-r--r-- | src/LivingVillage.Desktop/Assets/jiangnan-world.png | bin | 0 -> 1098 bytes | |||
| -rw-r--r-- | src/LivingVillage.Desktop/Game.fs | 9 | ||||
| -rw-r--r-- | src/LivingVillage.Desktop/LivingVillage.Desktop.fsproj | 3 | ||||
| -rw-r--r-- | src/LivingVillage.Desktop/VillageArt.fs | 305 |
7 files changed, 164 insertions, 166 deletions
diff --git a/src/LivingVillage.Desktop.Tests/PrototypeTests.fs b/src/LivingVillage.Desktop.Tests/PrototypeTests.fs index 842ab4a..c5b127f 100644 --- a/src/LivingVillage.Desktop.Tests/PrototypeTests.fs +++ b/src/LivingVillage.Desktop.Tests/PrototypeTests.fs @@ -416,3 +416,16 @@ type PrototypeTests () = Assert.IsTrue(manifestLines |> Array.forall (fun line -> line.Length = 1), "The CJK manifest must contain exactly one character per line.") CollectionAssert.AreEqual(characters, manifestLines |> Array.map (fun line -> line.[0])) Assert.IsTrue(File.Exists(runtimeAssetPath ()), sprintf "Missing atlas PNG: %s" (runtimeAssetPath ())) + + [<TestMethod>] + member _.JiangnanArtAssetsArePackagedAsRealPngFiles () = + let requiredAssets = + [ "Assets/jiangnan-world.png" + "Assets/jiangnan-characters.png" + "Assets/jiangnan-interior.png" ] + + let missing = + requiredAssets + |> List.filter (fun relativePath -> not (File.Exists(Path.Combine(AppContext.BaseDirectory, relativePath)))) + + Assert.AreEqual<string list>([], missing, sprintf "Missing Jiangnan PNG assets: %s" (String.concat ", " missing)) diff --git a/src/LivingVillage.Desktop/Assets/jiangnan-characters.png b/src/LivingVillage.Desktop/Assets/jiangnan-characters.png Binary files differnew file mode 100644 index 0000000..ffe6f66 --- /dev/null +++ b/src/LivingVillage.Desktop/Assets/jiangnan-characters.png diff --git a/src/LivingVillage.Desktop/Assets/jiangnan-interior.png b/src/LivingVillage.Desktop/Assets/jiangnan-interior.png Binary files differnew file mode 100644 index 0000000..d23f6b7 --- /dev/null +++ b/src/LivingVillage.Desktop/Assets/jiangnan-interior.png diff --git a/src/LivingVillage.Desktop/Assets/jiangnan-world.png b/src/LivingVillage.Desktop/Assets/jiangnan-world.png Binary files differnew file mode 100644 index 0000000..75dc906 --- /dev/null +++ b/src/LivingVillage.Desktop/Assets/jiangnan-world.png diff --git a/src/LivingVillage.Desktop/Game.fs b/src/LivingVillage.Desktop/Game.fs index dd04e26..514928f 100644 --- a/src/LivingVillage.Desktop/Game.fs +++ b/src/LivingVillage.Desktop/Game.fs @@ -387,7 +387,7 @@ type LivingVillageGame() as this = override _.LoadContent() = spriteBatch <- new SpriteBatch(this.GraphicsDevice) - artTextures <- VillageArt.buildTextures this.GraphicsDevice + artTextures <- VillageArt.loadTextures this.GraphicsDevice cjkAtlas <- CjkGlyphAtlas.load this.GraphicsDevice pixel <- new Texture2D(this.GraphicsDevice, 1, 1) pixel.SetData([| Color.White |]) @@ -395,6 +395,7 @@ type LivingVillageGame() as this = override _.UnloadContent() = if not (isNull artTextures.TileAtlas) then artTextures.TileAtlas.Dispose() if not (isNull artTextures.CharacterAtlas) then artTextures.CharacterAtlas.Dispose() + if not (isNull artTextures.InteriorAtlas) then artTextures.InteriorAtlas.Dispose() if not (isNull cjkAtlas) then cjkAtlas.Dispose() if not (isNull pixel) then pixel.Dispose() if not (isNull spriteBatch) then spriteBatch.Dispose() @@ -527,7 +528,9 @@ type LivingVillageGame() as this = spriteBatch.Begin() match m5View.HomeMode with | Inside _ -> - VillageArt.drawInterior spriteBatch pixel viewport.Width viewport.Height renderPlan.Interior + VillageArt.drawInterior spriteBatch pixel artTextures viewport.Width viewport.Height renderPlan.Interior Color.White + let interiorAvatarSpec = VillageArt.avatarSpriteSpec avatarFacing world.Tick + VillageArt.drawInteriorCharacter spriteBatch artTextures viewport.Width viewport.Height world.Avatar.Pos interiorAvatarSpec Color.White | Outside -> VillageArt.drawWorld spriteBatch @@ -538,7 +541,7 @@ type LivingVillageGame() as this = renderPlan profile.WorldTint - let avatarSpec = VillageArt.npcSpriteSpec (NpcId 0) avatarFacing world.Tick + let avatarSpec = VillageArt.avatarSpriteSpec avatarFacing world.Tick VillageArt.drawCharacter spriteBatch artTextures camera world.Avatar.Pos avatarSpec profile.WorldTint for npc in world.Npcs do diff --git a/src/LivingVillage.Desktop/LivingVillage.Desktop.fsproj b/src/LivingVillage.Desktop/LivingVillage.Desktop.fsproj index 4a1b483..b6b619f 100644 --- a/src/LivingVillage.Desktop/LivingVillage.Desktop.fsproj +++ b/src/LivingVillage.Desktop/LivingVillage.Desktop.fsproj @@ -28,6 +28,9 @@ <ItemGroup> <None Include="Assets\cjk-glyph-atlas.png" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="PreserveNewest" /> <None Include="Assets\cjk-glyphs.txt" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="PreserveNewest" /> + <None Include="Assets\jiangnan-world.png" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="PreserveNewest" /> + <None Include="Assets\jiangnan-characters.png" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="PreserveNewest" /> + <None Include="Assets\jiangnan-interior.png" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="PreserveNewest" /> </ItemGroup> </Project> diff --git a/src/LivingVillage.Desktop/VillageArt.fs b/src/LivingVillage.Desktop/VillageArt.fs index e46d85c..03cd22e 100644 --- a/src/LivingVillage.Desktop/VillageArt.fs +++ b/src/LivingVillage.Desktop/VillageArt.fs @@ -66,6 +66,7 @@ module VillageArt = | IndigoRobe | OchreVest | JadeSash + | StrawHat type FacingDirection = | NorthFacing @@ -84,7 +85,8 @@ module VillageArt = type ArtTextures = { TileAtlas: Texture2D - CharacterAtlas: Texture2D } + CharacterAtlas: Texture2D + InteriorAtlas: Texture2D } type private TileSprite = | GrassSprite @@ -222,6 +224,7 @@ module VillageArt = | IndigoRobe -> 0 | OchreVest -> 1 | JadeSash -> 2 + | StrawHat -> 3 let directionIndex = match spec.Direction with | NorthFacing -> 0 @@ -235,151 +238,41 @@ module VillageArt = let cellIndex = (variantIndex * 4 + directionIndex) * 2 + frameIndex Microsoft.Xna.Framework.Rectangle(cellIndex * 32, 0, 32, 48) - let private setPixel (pixels: XnaColor[]) (width: int) (x: int) (y: int) (color: XnaColor) = - let height = pixels.Length / width - if x >= 0 && x < width && y >= 0 && y < height then - pixels.[y * width + x] <- color + let private rgba (r: int) (g: int) (b: int) (a: int) : XnaColor = XnaColor(r, g, b, a) - let private fillRect (pixels: XnaColor[]) (width: int) (x: int) (y: int) (rectWidth: int) (rectHeight: int) (color: XnaColor) = - for row in y .. y + rectHeight - 1 do - for column in x .. x + rectWidth - 1 do - setPixel pixels width column row color + let avatarSpriteSpec (direction: FacingDirection) (tick: int64) : NpcSpriteSpec = + { Variant = StrawHat + Direction = direction + Frame = animationFrame tick } - let private rgba (r: int) (g: int) (b: int) (a: int) : XnaColor = XnaColor(r, g, b, a) + let worldAtlasRelativePath = "Assets/jiangnan-world.png" + let characterAtlasRelativePath = "Assets/jiangnan-characters.png" + let interiorAtlasRelativePath = "Assets/jiangnan-interior.png" + + let worldAtlasWidth = Sim.tilePixels * 8 + let worldAtlasHeight = Sim.tilePixels + let characterAtlasWidth = 32 * 4 * 4 * 2 + let characterAtlasHeight = 48 + let interiorAtlasWidth = 392 + let interiorAtlasHeight = 96 + + let private loadTexture (device: GraphicsDevice) (relativePath: string) (expectedWidth: int) (expectedHeight: int) : Texture2D = + let fullPath = System.IO.Path.Combine(System.AppContext.BaseDirectory, relativePath) + if not (System.IO.File.Exists fullPath) then + raise (System.IO.FileNotFoundException(sprintf "Jiangnan art atlas is missing: %s" fullPath, fullPath)) + + use stream = System.IO.File.OpenRead fullPath + let texture = Texture2D.FromStream(device, stream) + if texture.Width <> expectedWidth || texture.Height <> expectedHeight then + texture.Dispose() + invalidOp (sprintf "Jiangnan art atlas %s has dimensions %dx%d; expected %dx%d." fullPath texture.Width texture.Height expectedWidth expectedHeight) + else + texture - let private buildTileAtlas (device: GraphicsDevice) : Texture2D = - let atlasWidth = Sim.tilePixels * 8 - let atlasHeight = Sim.tilePixels - let pixels = Array.create (atlasWidth * atlasHeight) (rgba 0 0 0 0) - let fillSlot slot color = fillRect pixels atlasWidth (slot * Sim.tilePixels) 0 Sim.tilePixels Sim.tilePixels color - let setSlotPixel slot x y color = setPixel pixels atlasWidth (slot * Sim.tilePixels + x) y color - let grass = rgba 66 112 70 255 - let grassLight = rgba 92 139 82 255 - let water = rgba 54 116 145 255 - let waterLight = rgba 105 174 184 255 - let path = rgba 170 153 123 255 - let pathLight = rgba 201 183 145 255 - let roof = rgba 45 49 57 255 - let roofLight = rgba 76 80 85 255 - let wall = rgba 225 216 195 255 - let wallShadow = rgba 166 147 119 255 - let wood = rgba 119 76 47 255 - let woodLight = rgba 164 111 61 255 - let bamboo = rgba 51 101 61 255 - let bambooLight = rgba 107 153 81 255 - let soil = rgba 122 78 49 255 - let sprout = rgba 86 139 68 255 - - fillSlot 0 grass - for y in 0 .. Sim.tilePixels - 1 do - for x in 0 .. Sim.tilePixels - 1 do - if (x * 13 + y * 7) % 29 = 0 then - setSlotPixel 0 x y grassLight - - fillSlot 1 water - for y in [ 5; 16; 27 ] do - for x in 3 .. Sim.tilePixels - 4 do - if (x + y) % 5 <> 0 then - setSlotPixel 1 x y waterLight - for x in [ 8; 23 ] do - fillRect pixels atlasWidth (x + Sim.tilePixels) 2 2 26 (rgba 44 93 124 255) - - fillSlot 2 path - for y in [ 0; 31 ] do - for x in 0 .. Sim.tilePixels - 1 do - setSlotPixel 2 x y pathLight - for x in [ 7; 24 ] do - for y in 4 .. 27 do - if y % 3 <> 0 then - setSlotPixel 2 x y pathLight - - fillSlot 3 roof - for y in [ 5; 13; 21; 29 ] do - for x in 0 .. Sim.tilePixels - 1 do - if (x + y) % 6 < 5 then - setSlotPixel 3 x y roofLight - - fillSlot 4 wall - fillRect pixels atlasWidth (4 * Sim.tilePixels) 0 2 Sim.tilePixels wallShadow - fillRect pixels atlasWidth (4 * Sim.tilePixels + 15) 0 2 Sim.tilePixels wallShadow - fillRect pixels atlasWidth (4 * Sim.tilePixels + 30) 0 2 Sim.tilePixels wallShadow - fillRect pixels atlasWidth (4 * Sim.tilePixels) 27 Sim.tilePixels 3 wallShadow - - fillSlot 5 wood - for y in [ 6; 15; 24 ] do - fillRect pixels atlasWidth (5 * Sim.tilePixels) y Sim.tilePixels 2 woodLight - - fillSlot 6 (rgba 0 0 0 0) - for stemX in [ 6; 16; 26 ] do - fillRect pixels atlasWidth (6 * Sim.tilePixels + stemX) 4 3 25 bamboo - for leafY in [ 8; 17; 25 ] do - fillRect pixels atlasWidth (6 * Sim.tilePixels + stemX - 4) leafY 5 2 bambooLight - fillRect pixels atlasWidth (6 * Sim.tilePixels + stemX + 2) (leafY + 2) 5 2 bambooLight - - fillSlot 7 (rgba 0 0 0 0) - for row in [ 6; 15; 24 ] do - fillRect pixels atlasWidth (7 * Sim.tilePixels + 2) row 28 3 soil - for sproutX in [ 6; 15; 24 ] do - fillRect pixels atlasWidth (7 * Sim.tilePixels + sproutX) (row - 3) 2 3 sprout - - let texture = new Texture2D(device, atlasWidth, atlasHeight, false, SurfaceFormat.Color) - texture.SetData pixels - texture - - let private buildCharacterAtlas (device: GraphicsDevice) : Texture2D = - let cellWidth = 32 - let cellHeight = 48 - let columns = 3 * 4 * 2 - let atlasWidth = columns * cellWidth - let pixels = Array.create (atlasWidth * cellHeight) (rgba 0 0 0 0) - let variants = [| IndigoRobe; OchreVest; JadeSash |] - let directions = [| NorthFacing; SouthFacing; WestFacing; EastFacing |] - let frames = [| FrameOne; FrameTwo |] - - for variantIndex in 0 .. variants.Length - 1 do - for directionIndex in 0 .. directions.Length - 1 do - for frameIndex in 0 .. frames.Length - 1 do - let variant = variants.[variantIndex] - let direction = directions.[directionIndex] - let frame = frames.[frameIndex] - let spec = { Variant = variant; Direction = direction; Frame = frame } - let source = characterSourceRectangle spec - let offsetX = source.X - let robe, sash = - match variant with - | IndigoRobe -> rgba 46 57 108 255, rgba 104 145 183 255 - | OchreVest -> rgba 141 91 45 255, rgba 205 163 76 255 - | JadeSash -> rgba 46 113 91 255, rgba 121 185 139 255 - let skin = rgba 232 180 139 255 - let hair = rgba 42 36 37 255 - let shadow = rgba 23 31 34 120 - let legShift = if frame = FrameOne then 0 else 2 - fillRect pixels atlasWidth (offsetX + 7) 42 18 3 shadow - fillRect pixels atlasWidth (offsetX + 8 + legShift) 35 6 10 robe - fillRect pixels atlasWidth (offsetX + 18 - legShift) 35 6 10 robe - fillRect pixels atlasWidth (offsetX + 7) 22 18 16 robe - fillRect pixels atlasWidth (offsetX + 9) 32 14 4 sash - fillRect pixels atlasWidth (offsetX + 10) 12 12 10 skin - fillRect pixels atlasWidth (offsetX + 7) 8 18 4 hair - fillRect pixels atlasWidth (offsetX + 5) 7 22 3 sash - match direction with - | NorthFacing -> - fillRect pixels atlasWidth (offsetX + 9) 13 14 8 hair - | SouthFacing -> - fillRect pixels atlasWidth (offsetX + 12) 17 2 2 hair - fillRect pixels atlasWidth (offsetX + 18) 17 2 2 hair - | WestFacing -> - fillRect pixels atlasWidth (offsetX + 9) 16 3 5 hair - | EastFacing -> - fillRect pixels atlasWidth (offsetX + 20) 16 3 5 hair - - let texture = new Texture2D(device, atlasWidth, cellHeight, false, SurfaceFormat.Color) - texture.SetData pixels - texture - - let buildTextures (device: GraphicsDevice) : ArtTextures = - { TileAtlas = buildTileAtlas device - CharacterAtlas = buildCharacterAtlas device } + let loadTextures (device: GraphicsDevice) : ArtTextures = + { TileAtlas = loadTexture device worldAtlasRelativePath worldAtlasWidth worldAtlasHeight + CharacterAtlas = loadTexture device characterAtlasRelativePath characterAtlasWidth characterAtlasHeight + InteriorAtlas = loadTexture device interiorAtlasRelativePath interiorAtlasWidth interiorAtlasHeight } let private tileSourceRectangle sprite : XnaRectangle = let index = @@ -494,30 +387,116 @@ module VillageArt = 48) spriteBatch.Draw(textures.CharacterAtlas, destination, characterSourceRectangle spec, tint) - let drawInterior (spriteBatch: SpriteBatch) (pixel: Texture2D) (viewportWidth: int) (viewportHeight: int) (plan: InteriorPlan) = - let roomX = 40 - let roomY = 40 - let roomWidth = max 320 (viewportWidth - 80) - let roomHeight = max 240 (viewportHeight - 80) + type InteriorLayout = + { RoomX: int + RoomY: int + RoomWidth: int + RoomHeight: int } + + let private interiorWallBandHeight = 64 + + let private floorCellSource = XnaRectangle(0, 64, Sim.tilePixels, Sim.tilePixels) + let private wallCellSource = XnaRectangle(32, 64, Sim.tilePixels, Sim.tilePixels) + let private rugSource = XnaRectangle(256, 32, 96, 64) + let private chestSource = XnaRectangle(352, 60, 40, 36) + + let interiorSourceRectangle (kind: InteriorElementKind) : Microsoft.Xna.Framework.Rectangle = + match kind with + | Window -> XnaRectangle(64, 56, 48, 40) + | Table -> XnaRectangle(112, 48, 64, 48) + | Bed -> XnaRectangle(176, 0, 48, 96) + | Screen -> XnaRectangle(224, 0, 32, 96) + + let interiorLayout (viewportWidth: int) (viewportHeight: int) : InteriorLayout = + { RoomX = 40 + RoomY = 40 + RoomWidth = max 320 (viewportWidth - 80) + RoomHeight = max 240 (viewportHeight - 80) } + + let interiorColumns (layout: InteriorLayout) : int = + max 1 (layout.RoomWidth / Sim.tilePixels) + + let interiorRows (layout: InteriorLayout) : int = + max 1 ((layout.RoomHeight - interiorWallBandHeight) / Sim.tilePixels) + + let interiorFloorY (layout: InteriorLayout) : int = + layout.RoomY + interiorWallBandHeight + + let private clampInt (minimum: int) (maximum: int) (value: int) : int = + if value < minimum then minimum + elif value > maximum then maximum + else value + + let interiorCharacterScreenPosition (layout: InteriorLayout) (worldPosition: Vec2) : PixelPosition = + let sceneTile = sceneTileFromPixel { PixelPosition.X = worldPosition.X; Y = worldPosition.Y } + let tileX = clampInt 1 (interiorColumns layout - 2) sceneTile.X + let tileY = clampInt 1 (interiorRows layout - 2) sceneTile.Y + let floorY = interiorFloorY layout + { PixelPosition.X = float32 (layout.RoomX + tileX * Sim.tilePixels + Sim.tilePixels / 2) + Y = float32 (floorY + (tileY + 1) * Sim.tilePixels) } + + let drawInterior + (spriteBatch: SpriteBatch) + (pixel: Texture2D) + (textures: ArtTextures) + (viewportWidth: int) + (viewportHeight: int) + (plan: InteriorPlan) + (tint: XnaColor) = + let layout = interiorLayout viewportWidth viewportHeight + let floorY = interiorFloorY layout + let columns = interiorColumns layout + let rows = interiorRows layout + let partialRows = (layout.RoomHeight - interiorWallBandHeight) % Sim.tilePixels + let totalRows = 2 + rows + (if partialRows > 0 then 1 else 0) + spriteBatch.Draw(pixel, XnaRectangle(0, 0, viewportWidth, viewportHeight), rgba 18 25 42 255) - spriteBatch.Draw(pixel, XnaRectangle(roomX, roomY, roomWidth, roomHeight), rgba 188 163 126 255) - spriteBatch.Draw(pixel, XnaRectangle(roomX, roomY, roomWidth, 18), rgba 65 57 59 255) - spriteBatch.Draw(pixel, XnaRectangle(roomX, roomY + roomHeight - 18, roomWidth, 18), rgba 99 70 50 255) - for element in plan.Elements do - let x = roomX + element.Position.X * Sim.tilePixels - let y = roomY + element.Position.Y * Sim.tilePixels + let drawCell (source: XnaRectangle) (screenX: int) (screenY: int) = + let width = min Sim.tilePixels (layout.RoomX + layout.RoomWidth - screenX) + let height = min Sim.tilePixels (layout.RoomY + layout.RoomHeight - screenY) + if width > 0 && height > 0 then + spriteBatch.Draw(textures.InteriorAtlas, XnaRectangle(screenX, screenY, width, height), source, tint) + + for row in 0 .. totalRows - 1 do + for column in 0 .. columns - 1 do + let screenX = layout.RoomX + column * Sim.tilePixels + let screenY = layout.RoomY + row * Sim.tilePixels + let source = if row < 2 then wallCellSource else floorCellSource + drawCell source screenX screenY + + let rugX = layout.RoomX + (layout.RoomWidth - 96) / 2 + let rugY = floorY + 96 + spriteBatch.Draw(textures.InteriorAtlas, XnaRectangle(rugX, rugY, 96, 64), rugSource, tint) + + let elementDestination (element: InteriorElement) : XnaRectangle = + let baseY = floorY + (element.Position.Y + 1) * Sim.tilePixels match element.Kind with | Window -> - spriteBatch.Draw(pixel, XnaRectangle(x, y, 48, 30), rgba 86 143 170 255) - spriteBatch.Draw(pixel, XnaRectangle(x + 22, y, 4, 30), rgba 225 216 195 255) + XnaRectangle(layout.RoomX + element.Position.X * Sim.tilePixels - 8, layout.RoomY + 24, 48, 40) | Table -> - spriteBatch.Draw(pixel, XnaRectangle(x, y, 64, 32), rgba 119 76 47 255) - spriteBatch.Draw(pixel, XnaRectangle(x + 8, y + 28, 8, 20), rgba 83 52 39 255) - spriteBatch.Draw(pixel, XnaRectangle(x + 48, y + 28, 8, 20), rgba 83 52 39 255) + XnaRectangle(layout.RoomX + element.Position.X * Sim.tilePixels - 16, baseY - 48, 64, 48) | Bed -> - spriteBatch.Draw(pixel, XnaRectangle(x, y, 48, 80), rgba 114 62 67 255) - spriteBatch.Draw(pixel, XnaRectangle(x + 4, y + 4, 40, 24), rgba 224 211 185 255) + XnaRectangle(layout.RoomX + element.Position.X * Sim.tilePixels - 8, baseY - 96, 48, 96) | Screen -> - spriteBatch.Draw(pixel, XnaRectangle(x, y, 16, 80), rgba 61 45 49 255) - spriteBatch.Draw(pixel, XnaRectangle(x + 12, y + 4, 8, 72), rgba 142 102 72 255) + XnaRectangle(layout.RoomX + element.Position.X * Sim.tilePixels, baseY - 96, 32, 96) + + for element in plan.Elements |> List.sortBy (fun element -> element.Position.Y, element.Position.X) do + spriteBatch.Draw(textures.InteriorAtlas, elementDestination element, interiorSourceRectangle element.Kind, tint) + + let chestX = layout.RoomX + layout.RoomWidth - 44 + let chestY = layout.RoomY + layout.RoomHeight - 36 + spriteBatch.Draw(textures.InteriorAtlas, XnaRectangle(chestX, chestY, 40, 36), chestSource, tint) + + let drawInteriorCharacter + (spriteBatch: SpriteBatch) + (textures: ArtTextures) + (viewportWidth: int) + (viewportHeight: int) + (position: Vec2) + (spec: NpcSpriteSpec) + (tint: XnaColor) = + let layout = interiorLayout viewportWidth viewportHeight + let screenPosition = interiorCharacterScreenPosition layout position + let destination = XnaRectangle(int screenPosition.X - 16, int screenPosition.Y - 48, 32, 48) + spriteBatch.Draw(textures.CharacterAtlas, destination, characterSourceRectangle spec, tint) |
