Now featuring the messy tilemap code! (Tomorrow is refactor day)
parent
c280a688dc
commit
9ec55c4c7e
@ -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;
|
||||
// }
|
||||
// }
|
||||
}
|
@ -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<string> GetTilesetNames() {
|
||||
return Map.GetTilesetNames();
|
||||
}
|
||||
|
||||
public void Draw(Camera viewport, SpriteBatch spritebatch, IDictionary<string, Texture2D> this_sucks) {
|
||||
IEnumerable<TileLocation> 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -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<uint, Tile>();
|
||||
|
||||
public bool Infinite {get; set;}
|
||||
public IEnumerable<MapLayer> Layers {get; set;}
|
||||
public IEnumerable<TileSet> TileSets {get; set;}
|
||||
public int TileHeight {get; set;}
|
||||
public int TileWidth {get; set;}
|
||||
private Dictionary<uint, Tile> TileCache {get; set;}
|
||||
|
||||
public IEnumerable<TileLocation> DrawView(Camera viewport) {
|
||||
Dictionary<string, IEnumerable<DataCoordinate>> layerData = new Dictionary<string, IEnumerable<DataCoordinate>>();
|
||||
Layers.Where(layer => layer.Type == "tilelayer").ToList()
|
||||
.ForEach(layer => {
|
||||
layerData.Add(layer.Name, layer.GetVisibleTiles(viewport, TileHeight, TileWidth));
|
||||
});
|
||||
HashSet<uint> gids = layerData.Aggregate(new HashSet<uint>(),
|
||||
(tiles, layer) => {
|
||||
layer.Value.ToList().ForEach(tile => tiles.Add(tile.gid));
|
||||
return tiles;
|
||||
});
|
||||
IDictionary<uint, Tile> tiles = GetTilesetTiles(gids);
|
||||
// return layerData.Aggregate(new List<TileLocation>(),
|
||||
// (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<TileLocation>(),
|
||||
(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<string> GetTilesetNames() =>
|
||||
TileSets.Aggregate(new List<string>(),
|
||||
(names, tileset) => {
|
||||
names.Add(tileset.GetContentName());
|
||||
return names;
|
||||
});
|
||||
|
||||
private IDictionary<uint, Tile> GetTilesetTiles(HashSet<uint> tiles) {
|
||||
Dictionary<uint, Tile> loadedTiles = new Dictionary<uint, Tile>();
|
||||
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<uint, Tile> 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<uint, Tile>();
|
||||
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<uint> Data {get; set;}
|
||||
public string Type {get; set;}
|
||||
public IEnumerable<DataCoordinate> DataCoordinates {get; set;}
|
||||
public bool BuiltCoordinates {get; private set;}
|
||||
|
||||
public IEnumerable<DataCoordinate> 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<DataCoordinate> coordinates = new List<DataCoordinate>();
|
||||
Data.ToList().ForEach(gid => {
|
||||
coordinates.Add(new DataCoordinate(column, row, gid));
|
||||
if(column == Width-1) {
|
||||
row++;
|
||||
column = 0;
|
||||
} else column++;
|
||||
});
|
||||
DataCoordinates = coordinates;
|
||||
BuiltCoordinates = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -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<TiledMap>(text, options);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue