diff --git a/SeeNoEvil/Level/Camera.cs b/SeeNoEvil/Level/Camera.cs new file mode 100644 index 0000000..2894720 --- /dev/null +++ b/SeeNoEvil/Level/Camera.cs @@ -0,0 +1,21 @@ +namespace SeeNoEvil.Level { + public struct Camera { + public int width; + public int height; + public int x; + public int y; + } + + // public class Camera { + // private Viewport m_dimension; + + // public Camera(int x, int y) { + // m_dimension.x = x; + // m_dimension.y = x; + // } + + // public Viewport GetDimension() { + // return m_dimension; + // } + // } +} \ No newline at end of file diff --git a/SeeNoEvil/Level/Level.cs b/SeeNoEvil/Level/Level.cs new file mode 100644 index 0000000..1ec7695 --- /dev/null +++ b/SeeNoEvil/Level/Level.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Linq; +using SeeNoEvil.Tiled; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace SeeNoEvil.Level { + public class TilemapLevel { + private readonly string MapName; + private TiledMap Map; + + public TilemapLevel(string tilemapName) { + MapName = tilemapName; + } + + public void LoadMap() { + Map = TiledParser.ReadMapJson(MapName); + } + + public IEnumerable GetTilesetNames() { + return Map.GetTilesetNames(); + } + + public void Draw(Camera viewport, SpriteBatch spritebatch, IDictionary this_sucks) { + IEnumerable locations = Map.DrawView(viewport); + locations.ToList().ForEach(tile => { + Texture2D this_one; + if(tile.tile.gid > 0 && this_sucks.TryGetValue(tile.tile.setName, out this_one)) { + spritebatch.Draw(this_one, tile.location, tile.tile.srcRectangle, Color.White); + } + }); + } + } +} \ No newline at end of file diff --git a/SeeNoEvil/Tiled/TiledMap.cs b/SeeNoEvil/Tiled/TiledMap.cs new file mode 100644 index 0000000..2139fd6 --- /dev/null +++ b/SeeNoEvil/Tiled/TiledMap.cs @@ -0,0 +1,234 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using System.Linq; +using SeeNoEvil.Level; +using System.Text.Json.Serialization; + +namespace SeeNoEvil.Tiled { + public class TiledMap { + public TiledMap() => TileCache = new Dictionary(); + + public bool Infinite {get; set;} + public IEnumerable Layers {get; set;} + public IEnumerable TileSets {get; set;} + public int TileHeight {get; set;} + public int TileWidth {get; set;} + private Dictionary TileCache {get; set;} + + public IEnumerable DrawView(Camera viewport) { + Dictionary> layerData = new Dictionary>(); + Layers.Where(layer => layer.Type == "tilelayer").ToList() + .ForEach(layer => { + layerData.Add(layer.Name, layer.GetVisibleTiles(viewport, TileHeight, TileWidth)); + }); + HashSet gids = layerData.Aggregate(new HashSet(), + (tiles, layer) => { + layer.Value.ToList().ForEach(tile => tiles.Add(tile.gid)); + return tiles; + }); + IDictionary tiles = GetTilesetTiles(gids); + // return layerData.Aggregate(new List(), + // (locations, layer) => { + // layer.Value.ToList().ForEach(coord => { + // Tile currTile; + // if(!tiles.TryGetValue(coord.gid, out currTile)) { + // currTile = new Tile(); + // } + // Vector2 pxLocation = new Vector2(coord.x*TileWidth, coord.y*TileHeight); + // locations.Add(new TileLocation(currTile, pxLocation)); + // }); + // return locations; + // }); + int column = 0, row = 0, columnPx = 0, rowPx = 0; + int viewportRows = viewport.height / TileHeight; + int viewportColumns = viewport.width / TileWidth; + return layerData.Aggregate(new List(), + (locations, layer) => { + layer.Value.ToList().ForEach(coord => { + Tile currTile; + if(!tiles.TryGetValue(coord.gid, out currTile)) { + currTile = new Tile(); + } + Vector2 pxLocation = new Vector2(columnPx, rowPx); + locations.Add(new TileLocation(currTile, pxLocation)); + if(column == viewportColumns) { + row++; + rowPx += TileHeight; + column = columnPx = 0; + } else { + column++; + columnPx += TileWidth; + } + }); + return locations; + }); + } + + public IEnumerable GetTilesetNames() => + TileSets.Aggregate(new List(), + (names, tileset) => { + names.Add(tileset.GetContentName()); + return names; + }); + + private IDictionary GetTilesetTiles(HashSet tiles) { + Dictionary loadedTiles = new Dictionary(); + tiles.ToList().ForEach(gid => { + TileSet tileset = TileSets.FirstOrDefault(set => set.ContainsTile(gid)); + Tile tile = tileset == null ? new Tile() : tileset.GetTile(gid); + loadedTiles.Add(gid, tile); + }); + return loadedTiles; + } + } + + public struct TileLocation { + public TileLocation(Tile tile, Vector2 location) { + this.tile = tile; + this.location = location; + } + + public Tile tile; + public Vector2 location; + } + + public struct Tile { + public Tile(long _gid, Rectangle _srcRectangle, string _setName) { + gid = (uint)_gid; + srcRectangle = _srcRectangle; + setName = _setName; + } + public uint gid; + public Rectangle srcRectangle; + public string setName; + } + + public class TileSet { + public TileSet() { + TilesLoaded = false; + } + + public string Image {get; set;} + public string Name {get; set;} + public int ImageHeight {get; set;} + public int ImageWidth {get; set;} + public int TileHeight {get; set;} + public int TileWidth {get; set;} + public int Spacing {get; set;} + public int Columns {get; set;} + public int FirstGid {get; set;} + public int TileCount {get; set;} + private IDictionary Tiles {get; set;} + private bool TilesLoaded {get; set;} + + public Tile GetTile(uint gid) { + if(!TilesLoaded) { + LoadTiles(); + } + Tile result; + Tiles.TryGetValue(gid, out result); + return result; + } + + public bool ContainsTile(uint gid) { + return !(gid < FirstGid || + gid > (FirstGid + TileCount - 1)); + } + + public string GetContentName() { + return Name; + } + + private void LoadTiles() { + Tiles = new Dictionary(); + int row = 0; + int rowPx = 0; + int column = 0; + int columnPx = 0; + for(int i = 0; i < TileCount; i++) { + Rectangle rectangle = new Rectangle( + columnPx, + rowPx, + TileWidth, + TileHeight + ); + uint gid = (uint)(i + FirstGid); + Tiles.Add(gid, new Tile(gid, rectangle, Name)); + if(column == Columns-1) { + row++; + rowPx += Spacing + TileHeight; + column = 0; + columnPx = 0; + } else { + column++; + columnPx += Spacing + TileWidth; + } + } + + TilesLoaded = true; + } + } + + public struct DataCoordinate { + public DataCoordinate(int _x, int _y, uint _gid) { + x = _x; + y = _y; + gid = _gid; + } + + public int x; + public int y; + public uint gid; + } + + public class MapLayer { + public MapLayer() { } + + public string Name {get; set;} + public int Width {get; set;} + public int Height {get; set;} + public IEnumerable Data {get; set;} + public string Type {get; set;} + public IEnumerable DataCoordinates {get; set;} + public bool BuiltCoordinates {get; private set;} + + public IEnumerable GetVisibleTiles(Camera viewport, int tileHeight, int tileWidth) { + if(!BuiltCoordinates) { + BuildCoordinates(); + } + int startColumn = viewport.x / tileWidth; + int endColumn = startColumn + (viewport.width / tileWidth); + int startRow = viewport.y / tileHeight; + int endRow = startRow + (viewport.height / tileHeight); + + var coords = DataCoordinates.Where(coord => + startRow <= coord.y && + endRow >= coord.y && + startColumn <= coord.x && + endColumn >= coord.x + ).ToList(); + + return DataCoordinates.Where(coord => + startRow <= coord.y && + endRow >= coord.y && + startColumn <= coord.x && + endColumn >= coord.x + ); + } + + private void BuildCoordinates() { + int row = 0; + int column = 0; + List coordinates = new List(); + Data.ToList().ForEach(gid => { + coordinates.Add(new DataCoordinate(column, row, gid)); + if(column == Width-1) { + row++; + column = 0; + } else column++; + }); + DataCoordinates = coordinates; + BuiltCoordinates = true; + } + } +} diff --git a/SeeNoEvil/Tiled/TiledParser.cs b/SeeNoEvil/Tiled/TiledParser.cs new file mode 100644 index 0000000..2c28c4b --- /dev/null +++ b/SeeNoEvil/Tiled/TiledParser.cs @@ -0,0 +1,15 @@ +using System.IO; +using System.Text.Json; + +namespace SeeNoEvil.Tiled { + public static class TiledParser { + public static TiledMap ReadMapJson(string fileName) { + StreamReader streamReader = File.OpenText(fileName); + string text = streamReader.ReadToEnd(); + var options = new JsonSerializerOptions { + PropertyNameCaseInsensitive = true, + }; + return JsonSerializer.Deserialize(text, options); + } + } +} \ No newline at end of file