Skip to content

Instantly share code, notes, and snippets.

@mattj1
Last active September 28, 2020 18:13
Show Gist options
  • Save mattj1/367612d16bb8ede88a0e75ae6ea25f06 to your computer and use it in GitHub Desktop.
Save mattj1/367612d16bb8ede88a0e75ae6ea25f06 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml;
using System.Xml.Serialization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MonoGame.Extended.Tiled.Serialization;
namespace MonoGame.Extended.Tiled
{
public class TMXLoader
{
private readonly string _fileName;
public delegate Texture2D TextureLoader(string source);
public delegate Stream XmlLoader(string source);
private TextureLoader _textureLoader;
private XmlLoader _xmlLoader;
private TMXLoader(string path, TextureLoader textureLoader, XmlLoader xmlLoader)
{
_fileName = path;
_textureLoader = textureLoader;
_xmlLoader = xmlLoader;
Console.WriteLine($"TMX Loader: {path}");
}
private TiledMapObjectLayer ConvertTiledMapObjectLayer(TiledMap tiledMap
, TiledMapObjectLayerContent lc)
{
List<TiledMapObject> objects = new List<TiledMapObject>();
for (int i = 0; i < lc.Objects.Count; i++)
{
TiledMapObjectContent c = lc.Objects[i];
if (c.Ellipse != null)
{
// Not supported
}
else if (c.Polygon != null)
{
// TODO
// List<Point2> points = new List<Point2>();
// var ob = new TiledMapPolygonObject(c.Identifier, c.Name, null, new Size2(c.Width, c.Height), new Vector2(c.X, c.Y), c.Rotation, 1.0f, c.Visible, c.Type );
// objects.Add(ob);
}
else if (c.Polyline != null)
{
// TODO
}
else
{
TiledMapTileset tileSet = tiledMap.GetTilesetByTileGlobalIdentifier((int) c.GlobalIdentifier);
if (tileSet != null)
{
var fgi = tiledMap.GetTilesetFirstGlobalIdentifier(tileSet);
int localIdentifier = (int) (c.GlobalIdentifier - fgi);
TiledMapTilesetTile tile = null;
foreach (var t in tileSet.Tiles)
{
if (t.LocalTileIdentifier == localIdentifier)
{
tile = t;
break;
}
}
// Copy properties
var tmo = new TiledMapTileObject(c.Identifier, c.Name, tileSet, tile,
new Vector2(c.Width, c.Height), new Vector2(c.X, c.Y), c.Rotation
, 1.0f, c.Visible, c.Type);
foreach (var prop in c.Properties)
{
tmo.Properties.Add(prop.Name, prop.Value);
}
objects.Add(tmo);
}
else
{
Console.WriteLine($"Warning: no tileset for object gid {c.GlobalIdentifier}");
}
}
}
TiledMapObjectLayer layer = new TiledMapObjectLayer(lc.Name, objects.ToArray(),
ColorHelper.FromHex(lc.Color),
(TiledMapObjectDrawOrder) lc.DrawOrder,
new Vector2(lc.OffsetX, lc.OffsetY), lc.Opacity, lc.Visible);
return layer;
}
private TiledMapTileLayer ConvertTiledMapTileLayer(TiledMap tiledMap, TiledMapTileLayerContent lc)
{
TiledMapTileLayer layer = new TiledMapTileLayer(lc.Name, lc.Width, lc.Height, tiledMap.TileWidth,
tiledMap.TileHeight, null, lc.Opacity, lc.Visible);
// Copy properties
foreach (var prop in lc.Properties)
{
layer.Properties.Add(prop.Name, prop.Value);
}
// Copy tiles
if (lc.Data.Encoding == "csv")
{
string[] tileIds = lc.Data.Value.Split(",");
int offs = 0;
for (ushort y = 0; y < layer.Height; y++)
{
for (ushort x = 0; x < layer.Width; x++)
{
layer.Tiles[offs] = new TiledMapTile(uint.Parse(tileIds[offs]), x, y);
offs++;
}
}
}
return layer;
}
private TiledMapTileset ConvertTiledMapTileset(TiledMapTilesetContent tsc)
{
var texture = _textureLoader(tsc.Image.Source);
var ts = new TiledMapTileset(texture, tsc.TileWidth, tsc.TileHeight, tsc.TileCount, tsc.Spacing, tsc.Margin,
tsc.Columns);
foreach (var t in tsc.Tiles)
{
// TODO: Objects?
TiledMapTilesetTile tile;
if (t.Frames.Count == 0)
{
tile = new TiledMapTilesetTile(t.LocalIdentifier, t.Type, null);
}
else
{
// Animation frames
TiledMapTilesetTileAnimationFrame[] frames = new TiledMapTilesetTileAnimationFrame[t.Frames.Count];
for (int i = 0; i < t.Frames.Count; i++)
{
var frameContent = t.Frames[i];
BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
object[] parameters = {ts, frameContent.TileIdentifier, frameContent.Duration};
object instantiatedType =
Activator.CreateInstance(typeof(TiledMapTilesetTileAnimationFrame),
bindingFlags,
null, parameters, null);
frames[i] = (TiledMapTilesetTileAnimationFrame) instantiatedType;
}
tile = new TiledMapTilesetAnimatedTile(t.LocalIdentifier, frames, t.Type, null);
}
// Copy properties
foreach (var prop in t.Properties)
{
tile.Properties[prop.Name] = prop.Value;
}
ts.Tiles.Add(tile);
}
foreach (var prop in tsc.Properties)
{
ts.Properties[prop.Name] = prop.Value;
}
return ts;
}
private TiledMap ConvertTiledMap()
{
var xmlSerializer = new XmlSerializer(typeof(TiledMapContent));
var stream = _xmlLoader(_fileName);
TiledMapContent tiledMapContent = (TiledMapContent) xmlSerializer.Deserialize(XmlReader.Create(stream));
TiledMap tiledMap = new TiledMap(tiledMapContent.Name, tiledMapContent.Width, tiledMapContent.Height,
tiledMapContent.TileWidth, tiledMapContent.TileHeight,
(TiledMapTileDrawOrder) tiledMapContent.RenderOrder,
TiledMapOrientation.Orthogonal, ColorHelper.FromHex(tiledMapContent.BackgroundColor));
foreach (var prop in tiledMapContent.Properties)
{
tiledMap.Properties[prop.Name] = prop.Value;
}
foreach (var tileSetContent in tiledMapContent.Tilesets)
{
TiledMapTilesetContent content = tileSetContent;
if (tileSetContent.Source != null)
{
Stream stream1 = _xmlLoader(tileSetContent.Source);
// load content from file
content =
(TiledMapTilesetContent) new XmlSerializer(typeof(TiledMapTilesetContent)).Deserialize(
XmlReader.Create(stream1));
stream1.Close();
}
TiledMapTileset tileSet = ConvertTiledMapTileset(content);
tiledMap.AddTileset(tileSet, tileSetContent.FirstGlobalIdentifier);
}
foreach (var layerContent in tiledMapContent.Layers)
{
switch (layerContent.Type)
{
case TiledMapLayerType.TileLayer:
TiledMapTileLayer layer =
ConvertTiledMapTileLayer(tiledMap, (TiledMapTileLayerContent) layerContent);
tiledMap.AddLayer(layer);
break;
case TiledMapLayerType.ObjectLayer:
var objectLayer =
ConvertTiledMapObjectLayer(tiledMap, (TiledMapObjectLayerContent) layerContent);
tiledMap.AddLayer(objectLayer);
break;
}
}
stream.Close();
return tiledMap;
}
public static TiledMap LoadTiledMap(string path, TextureLoader textureLoader, XmlLoader xmlLoader)
{
var loader = new TMXLoader(path, textureLoader, xmlLoader);
return loader.ConvertTiledMap();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment