almost finished making tiled maps creatable from code

This commit is contained in:
Dylan Wilson
2017-11-16 00:31:20 +10:00
parent 33759382f7
commit cd8f6ea6df
17 changed files with 401 additions and 389 deletions
@@ -1,19 +0,0 @@
using Microsoft.Xna.Framework.Content;
namespace MonoGame.Extended.Tiled
{
public static class ContentReaderExtensions
{
public static void ReadTiledMapProperties(this ContentReader reader, TiledMapProperties properties)
{
var count = reader.ReadInt32();
for (var i = 0; i < count; i++)
{
var key = reader.ReadString();
var value = reader.ReadString();
properties[key] = value;
}
}
}
}
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MonoGame.Extended.Tiled.Graphics.Effects;
@@ -7,82 +9,84 @@ namespace MonoGame.Extended.Tiled.Graphics
{
public class TiledMapRenderer : IDisposable
{
private readonly TiledMap _map;
private readonly TiledMapEffect _defaultEffect;
private Matrix _worldMatrix = Matrix.Identity;
private readonly GraphicsDevice _graphicsDevice;
/// <summary>
/// Gets the <see cref="Microsoft.Xna.Framework.Graphics.GraphicsDevice" /> associated with this <see cref="TiledMapRenderer" />.
/// </summary>
/// <value>
/// The <see cref="Microsoft.Xna.Framework.Graphics.GraphicsDevice" /> associated with this <see cref="TiledMapRenderer" />.
/// </value>
public GraphicsDevice GraphicsDevice { get; }
private readonly Dictionary<TiledMapTileset, List<TiledMapTilesetAnimatedTile>> _animatedTilesByTileset;
public TiledMapRenderer(GraphicsDevice graphicsDevice)
public TiledMapRenderer(GraphicsDevice graphicsDevice, TiledMap map)
{
if (graphicsDevice == null)
throw new ArgumentNullException(nameof(graphicsDevice));
GraphicsDevice = graphicsDevice;
if (graphicsDevice == null) throw new ArgumentNullException(nameof(graphicsDevice));
if (map == null) throw new ArgumentNullException(nameof(map));
_map = map;
_graphicsDevice = graphicsDevice;
_defaultEffect = new TiledMapEffect(graphicsDevice);
_animatedTilesByTileset = _map.Tilesets.ToDictionary(i => i, i => i.Tiles.OfType<TiledMapTilesetAnimatedTile>().ToList());
}
public void Update(TiledMap map, GameTime gameTime)
public void Dispose()
{
// ReSharper disable once ForCanBeConvertedToForeach
for (var tilesetIndex = 0; tilesetIndex < map.Tilesets.Count; tilesetIndex++)
_defaultEffect.Dispose();
}
public void Update(GameTime gameTime)
{
for (var tilesetIndex = 0; tilesetIndex < _map.Tilesets.Count; tilesetIndex++)
{
var tileset = map.Tilesets[tilesetIndex];
// ReSharper disable once ForCanBeConvertedToForeach
for (var animatedTileIndex = 0; animatedTileIndex < tileset.AnimatedTiles.Count; animatedTileIndex++)
var tileset = _map.Tilesets[tilesetIndex];
var animatedTiles = _animatedTilesByTileset[tileset];
for (var animatedTileIndex = 0; animatedTileIndex < animatedTiles.Count; animatedTileIndex++)
{
var animatedTilesetTile = tileset.AnimatedTiles[animatedTileIndex];
var animatedTilesetTile = animatedTiles[animatedTileIndex];
animatedTilesetTile.Update(gameTime);
}
}
// ReSharper disable once ForCanBeConvertedToForeach
for (var index = 0; index < map.TileLayers.Count; index++)
for (var index = 0; index < _map.TileLayers.Count; index++)
{
var layer = map.TileLayers[index];
var layer = _map.TileLayers[index];
UpdateAnimatedModels(layer.AnimatedModels);
}
}
public void Draw(TiledMap map, Matrix? viewMatrix = null, Matrix? projectionMatrix = null, Effect effect = null, float depth = 0.0f)
public void Draw(Matrix? viewMatrix = null, Matrix? projectionMatrix = null, Effect effect = null, float depth = 0.0f)
{
var viewMatrix1 = viewMatrix ?? Matrix.Identity;
var projectionMatrix1 = projectionMatrix ?? Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, -1);
Draw(map, ref viewMatrix1, ref projectionMatrix1, effect, depth);
var projectionMatrix1 = projectionMatrix ?? Matrix.CreateOrthographicOffCenter(0, _graphicsDevice.Viewport.Width, _graphicsDevice.Viewport.Height, 0, 0, -1);
Draw(ref viewMatrix1, ref projectionMatrix1, effect, depth);
}
public void Draw(TiledMap map, ref Matrix viewMatrix, ref Matrix projectionMatrix, Effect effect = null, float depth = 0.0f)
public void Draw(ref Matrix viewMatrix, ref Matrix projectionMatrix, Effect effect = null, float depth = 0.0f)
{
// ReSharper disable once ForCanBeConvertedToForeach
for (var index = 0; index < map.Layers.Count; index++)
{
var layer = map.Layers[index];
Draw(layer, ref viewMatrix, ref projectionMatrix, effect, depth);
}
for (var index = 0; index < _map.Layers.Count; index++)
Draw(index, ref viewMatrix, ref projectionMatrix, effect, depth);
}
public void Draw(TiledMapLayer layer, Matrix? viewMatrix = null, Matrix? projectionMatrix = null, Effect effect = null, float depth = 0.0f)
public void Draw(int layerIndex, Matrix? viewMatrix = null, Matrix? projectionMatrix = null, Effect effect = null, float depth = 0.0f)
{
var viewMatrix1 = viewMatrix ?? Matrix.Identity;
var projectionMatrix1 = projectionMatrix ?? Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, -1);
Draw(layer, ref viewMatrix1, ref projectionMatrix1, effect, depth);
var projectionMatrix1 = projectionMatrix ?? Matrix.CreateOrthographicOffCenter(0, _graphicsDevice.Viewport.Width, _graphicsDevice.Viewport.Height, 0, 0, -1);
Draw(layerIndex, ref viewMatrix1, ref projectionMatrix1, effect, depth);
}
public void Draw(TiledMapLayer layer, ref Matrix viewMatrix, ref Matrix projectionMatrix, Effect effect = null, float depth = 0.0f)
public void Draw(int layerIndex, ref Matrix viewMatrix, ref Matrix projectionMatrix, Effect effect = null, float depth = 0.0f)
{
var layer = _map.Layers[layerIndex];
if (!layer.IsVisible)
return;
if (layer is TiledMapObjectLayer)
return;
_worldMatrix.Translation = new Vector3(layer.OffsetX, layer.OffsetY, depth);
_worldMatrix.Translation = new Vector3(layer.Offset.X, layer.Offset.Y, depth);
var effect1 = effect ?? _defaultEffect;
var tiledMapEffect = effect1 as ITiledMapEffect;
@@ -103,8 +107,8 @@ namespace MonoGame.Extended.Tiled.Graphics
tiledMapEffect.Texture = model.Texture;
// bind the vertex and index buffer
GraphicsDevice.SetVertexBuffer(model.VertexBuffer);
GraphicsDevice.Indices = model.IndexBuffer;
_graphicsDevice.SetVertexBuffer(model.VertexBuffer);
_graphicsDevice.Indices = model.IndexBuffer;
// for each pass in our effect
foreach (var pass in effect1.CurrentTechnique.Passes)
@@ -113,7 +117,7 @@ namespace MonoGame.Extended.Tiled.Graphics
pass.Apply();
// draw the geometry from the vertex buffer / index buffer
GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, model.TrianglesCount);
_graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, model.TrianglesCount);
}
}
}
@@ -143,27 +147,5 @@ namespace MonoGame.Extended.Tiled.Graphics
animatedModel.VertexBuffer.SetData(animatedModel.Vertices, 0, animatedModel.Vertices.Length);
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="diposing">
/// <c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only
/// unmanaged resources.
/// </param>
protected virtual void Dispose(bool diposing)
{
if (diposing)
_defaultEffect.Dispose();
}
}
}
@@ -49,7 +49,6 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Graphics\Effects\TiledMapEffect.cs" />
<Compile Include="ContentReaderExtensions.cs" />
<Compile Include="Graphics\Effects\ITiledMapEffect.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Graphics\TiledMapLayerAnimatedModel.cs" />
+12 -18
View File
@@ -1,20 +1,18 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace MonoGame.Extended.Tiled
{
public sealed class TiledMap : IDisposable
{
private readonly List<TiledMapImageLayer> _imageLayers;
private readonly List<TiledMapLayer> _layers;
private readonly Dictionary<string, TiledMapLayer> _layersByName;
private readonly List<TiledMapObjectLayer> _objectLayers;
private readonly List<TiledMapTileLayer> _tileLayers;
private readonly List<TiledMapTileset> _tilesets;
private readonly List<TiledMapImageLayer> _imageLayers = new List<TiledMapImageLayer>();
private readonly List<TiledMapLayer> _layers = new List<TiledMapLayer>();
private readonly Dictionary<string, TiledMapLayer> _layersByName = new Dictionary<string, TiledMapLayer>();
private readonly List<TiledMapObjectLayer> _objectLayers = new List<TiledMapObjectLayer>();
private readonly List<TiledMapTileLayer> _tileLayers = new List<TiledMapTileLayer>();
private readonly List<TiledMapTileset> _tilesets = new List<TiledMapTileset>();
public string Name { get; }
public int Width { get; }
@@ -31,28 +29,20 @@ namespace MonoGame.Extended.Tiled
public ReadOnlyCollection<TiledMapObjectLayer> ObjectLayers { get; }
public Color? BackgroundColor { get; set; }
public int WidthInPixels => Width * TileWidth;
public int HeightInPixels => Height * TileHeight;
private TiledMap()
{
_layers = new List<TiledMapLayer>();
Layers = new ReadOnlyCollection<TiledMapLayer>(_layers);
_imageLayers = new List<TiledMapImageLayer>();
ImageLayers = new ReadOnlyCollection<TiledMapImageLayer>(_imageLayers);
_tileLayers = new List<TiledMapTileLayer>();
TileLayers = new ReadOnlyCollection<TiledMapTileLayer>(_tileLayers);
_objectLayers = new List<TiledMapObjectLayer>();
ObjectLayers = new ReadOnlyCollection<TiledMapObjectLayer>(_objectLayers);
_layersByName = new Dictionary<string, TiledMapLayer>();
_tilesets = new List<TiledMapTileset>();
Tilesets = new ReadOnlyCollection<TiledMapTileset>(_tilesets);
Properties = new TiledMapProperties();
}
public TiledMap(string name, int width, int height, int tileWidth, int tileHeight,
TiledMapTileDrawOrder renderOrder, TiledMapOrientation orientation)
public TiledMap(string name, int width, int height, int tileWidth, int tileHeight, TiledMapTileDrawOrder renderOrder, TiledMapOrientation orientation, Color? backgroundColor = null)
: this()
{
Name = name;
@@ -62,6 +52,7 @@ namespace MonoGame.Extended.Tiled
TileHeight = tileHeight;
RenderOrder = renderOrder;
Orientation = orientation;
BackgroundColor = backgroundColor;
}
public void Dispose()
@@ -110,9 +101,12 @@ namespace MonoGame.Extended.Tiled
{
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var tileset in _tilesets)
{
if (tileset.ContainsGlobalIdentifier(tileIdentifier))
return tileset;
}
return null;
}
}
}
}
@@ -1,20 +1,18 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
namespace MonoGame.Extended.Tiled
{
public sealed class TiledMapEllipseObject : TiledMapObject
{
public Vector2 Center { get; }
public float RadiusX { get; }
public float RadiusY { get; }
internal TiledMapEllipseObject(ContentReader input)
: base(input)
public TiledMapEllipseObject(int identifier, string name, Size2 size, Vector2 position, float rotation = 0, float opacity = 1, bool isVisible = true)
: base(identifier, name, size, position, rotation, opacity, isVisible)
{
RadiusX = Size.Width / 2.0f;
RadiusY = Size.Height / 2.0f;
Center = new Vector2(Position.X + RadiusX, Position.Y);
Radius = new Vector2(size.Width / 2.0f, size.Height / 2.0f);
Center = new Vector2(position.X + Radius.X, position.Y);
}
public Vector2 Center { get; }
public Vector2 Radius { get; }
public override TiledMapObjectType Type => TiledMapObjectType.Ellipse;
}
}
@@ -1,23 +1,18 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using MonoGame.Extended.Content;
namespace MonoGame.Extended.Tiled
{
public class TiledMapImageLayer : TiledMapLayer, IMovable
{
public Vector2 Position { get; set; }
public Texture2D Texture { get; }
internal TiledMapImageLayer(ContentReader input)
: base(input)
public TiledMapImageLayer(string name, Texture2D image, Vector2? position = null, Vector2? offset = null, float opacity = 1.0f, bool isVisible = true)
: base(name, offset, opacity, isVisible)
{
var textureAssetName = input.GetRelativeAssetName(input.ReadString());
Texture = input.ContentManager.Load<Texture2D>(textureAssetName);
var x = input.ReadSingle();
var y = input.ReadSingle();
Position = new Vector2(x, y);
Image = image;
Position = position ?? Vector2.Zero;
}
public Texture2D Image { get; }
public Vector2 Position { get; set; }
}
}
+11 -16
View File
@@ -1,5 +1,5 @@
using System;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
using MonoGame.Extended.Tiled.Graphics;
namespace MonoGame.Extended.Tiled
@@ -10,27 +10,20 @@ namespace MonoGame.Extended.Tiled
internal TiledMapLayerAnimatedModel[] AnimatedModels;
public string Name { get; }
public TiledMapProperties Properties { get; }
public bool IsVisible { get; set; }
public float Opacity { get; set; }
public float OffsetX { get; }
public float OffsetY { get; }
public Vector2 Offset { get; set; }
public TiledMapProperties Properties { get; }
internal TiledMapLayer(ContentReader input)
protected TiledMapLayer(string name, Vector2? offset = null, float opacity = 1.0f, bool isVisible = true)
{
Models = null;
AnimatedModels = null;
Name = input.ReadString();
Name = name;
Offset = offset ?? Vector2.Zero;
Opacity = opacity;
IsVisible = isVisible;
Properties = new TiledMapProperties();
IsVisible = input.ReadBoolean();
Opacity = input.ReadSingle();
OffsetX = input.ReadSingle();
OffsetY = input.ReadSingle();
input.ReadTiledMapProperties(Properties);
}
public void Dispose()
{
Dispose(true);
@@ -41,8 +34,10 @@ namespace MonoGame.Extended.Tiled
{
if (!diposing)
return;
if (Models == null)
return;
foreach (var model in Models)
model.Dispose();
}
@@ -1,35 +1,30 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
namespace MonoGame.Extended.Tiled
{
public abstract class TiledMapObject
{
protected TiledMapObject(int identifier, string name, Size2 size, Vector2 position, float rotation = 0, float opacity = 1, bool isVisible = true)
{
Identifier = identifier;
Name = name;
IsVisible = isVisible;
Rotation = rotation;
Position = position;
Size = size;
Opacity = opacity;
Properties = new TiledMapProperties();
}
public int Identifier { get; }
public string Name { get; set; }
public string Type { get; }
public TiledMapProperties Properties { get; }
public abstract TiledMapObjectType Type { get; }
public bool IsVisible { get; set; }
public float Opacity { get; set; }
public float Rotation { get; set; }
public Vector2 Position { get; }
public Size2 Size { get; set; }
internal TiledMapObject(ContentReader input)
{
Identifier = input.ReadInt32();
Name = input.ReadString();
Type = input.ReadString();
Position = new Vector2(input.ReadSingle(), input.ReadSingle());
var width = input.ReadSingle();
var height = input.ReadSingle();
Size = new Size2(width, height);
Rotation = input.ReadSingle();
IsVisible = input.ReadBoolean();
Properties = new TiledMapProperties();
input.ReadTiledMapProperties(Properties);
}
public TiledMapProperties Properties { get; }
public override string ToString()
{
@@ -1,53 +1,20 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
namespace MonoGame.Extended.Tiled
{
public class TiledMapObjectLayer : TiledMapLayer
{
public Color Color { get; }
public TiledMapObjectLayer(string name, TiledMapObject[] objects, Color? color = null, TiledMapObjectDrawOrder drawOrder = TiledMapObjectDrawOrder.TopDown,
Vector2? offset = null, float opacity = 1.0f, bool isVisible = true)
: base(name, offset, opacity, isVisible)
{
Color = color;
DrawOrder = drawOrder;
Objects = objects;
}
public Color? Color { get; }
public TiledMapObjectDrawOrder DrawOrder { get; }
public TiledMapObject[] Objects { get; }
internal TiledMapObjectLayer(ContentReader input, TiledMap map)
: base(input)
{
Color = input.ReadColor();
DrawOrder = (TiledMapObjectDrawOrder)input.ReadByte();
var objectCount = input.ReadInt32();
Objects = new TiledMapObject[objectCount];
for (var i = 0; i < objectCount; i++)
{
TiledMapObject @object;
var objectType = (TiledMapObjectType)input.ReadByte();
switch (objectType)
{
case TiledMapObjectType.Rectangle:
@object = new TiledMapRectangleObject(input);
break;
case TiledMapObjectType.Tile:
@object = new TiledMapTileObject(input, map);
break;
case TiledMapObjectType.Ellipse:
@object = new TiledMapEllipseObject(input);
break;
case TiledMapObjectType.Polygon:
@object = new TiledMapPolygonObject(input);
break;
case TiledMapObjectType.Polyline:
@object = new TiledMapPolylineObject(input);
break;
default:
throw new ArgumentOutOfRangeException();
}
Objects[i] = @object;
}
}
}
}
@@ -1,23 +1,16 @@
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
namespace MonoGame.Extended.Tiled
{
public sealed class TiledMapPolygonObject : TiledMapObject
{
public Point2[] Points { get; }
internal TiledMapPolygonObject(ContentReader input)
: base(input)
public TiledMapPolygonObject(int identifier, string name, Point2[] points, Size2 size, Vector2 position, float rotation = 0, float opacity = 1, bool isVisible = true)
: base(identifier, name, size, position, rotation, opacity, isVisible)
{
var pointCount = input.ReadInt32();
Points = new Point2[pointCount];
for (var i = 0; i < pointCount; i++)
{
var x = input.ReadSingle();
var y = input.ReadSingle();
Points[i] = new Point2(x, y);
}
Points = points;
}
public Point2[] Points { get; }
public override TiledMapObjectType Type => TiledMapObjectType.Polygon;
}
}
@@ -1,23 +1,16 @@
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
namespace MonoGame.Extended.Tiled
{
public sealed class TiledMapPolylineObject : TiledMapObject
{
public Point2[] Points { get; }
internal TiledMapPolylineObject(ContentReader input)
: base(input)
public TiledMapPolylineObject(int identifier, string name, Point2[] points, Size2 size, Vector2 position, float rotation = 0, float opacity = 1, bool isVisible = true)
: base(identifier, name, size, position, rotation, opacity, isVisible)
{
var pointCount = input.ReadInt32();
Points = new Point2[pointCount];
for (var i = 0; i < pointCount; i++)
{
var x = input.ReadSingle();
var y = input.ReadSingle();
Points[i] = new Point2(x, y);
}
Points = points;
}
public Point2[] Points { get; }
public override TiledMapObjectType Type => TiledMapObjectType.Polyline;
}
}
+232 -58
View File
@@ -1,91 +1,265 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using MonoGame.Extended.Content;
using MonoGame.Extended.Tiled.Graphics;
namespace MonoGame.Extended.Tiled
{
public class TiledMapReader : ContentTypeReader<TiledMap>
{
protected override TiledMap Read(ContentReader input, TiledMap existingInstance)
protected override TiledMap Read(ContentReader reader, TiledMap existingInstance)
{
if (existingInstance != null)
return existingInstance;
;
var value = ReadMetaData(input);
ReadTilesets(input, value);
ReadLayers(input, value);
return value;
}
private static TiledMap ReadMetaData(ContentReader input)
{
var name = input.AssetName;
var width = input.ReadInt32();
var height = input.ReadInt32();
var tileWidth = input.ReadInt32();
var tileHeight = input.ReadInt32();
var backgroundColor = input.ReadColor();
var renderOrder = (TiledMapTileDrawOrder)input.ReadByte();
var orientation = (TiledMapOrientation)input.ReadByte();
var map = new TiledMap(name, width, height, tileWidth, tileHeight, renderOrder, orientation)
{
BackgroundColor = backgroundColor
};
input.ReadTiledMapProperties(map.Properties);
var map = ReadTiledMap(reader);
ReadProperties(reader, map.Properties);
ReadTilesets(reader, map);
ReadLayers(reader, map);
return map;
}
private static void ReadTilesets(ContentReader input, TiledMap map)
private static void ReadProperties(ContentReader reader, TiledMapProperties properties)
{
var tilesetCount = input.ReadInt32();
var count = reader.ReadInt32();
for (var i = 0; i < count; i++)
{
var key = reader.ReadString();
var value = reader.ReadString();
properties[key] = value;
}
}
private static TiledMap ReadTiledMap(ContentReader reader)
{
var name = reader.AssetName;
var width = reader.ReadInt32();
var height = reader.ReadInt32();
var tileWidth = reader.ReadInt32();
var tileHeight = reader.ReadInt32();
var backgroundColor = reader.ReadColor();
var renderOrder = (TiledMapTileDrawOrder)reader.ReadByte();
var orientation = (TiledMapOrientation)reader.ReadByte();
return new TiledMap(name, width, height, tileWidth, tileHeight, renderOrder, orientation, backgroundColor);
}
private static void ReadTilesets(ContentReader reader, TiledMap map)
{
var tilesetCount = reader.ReadInt32();
for (var i = 0; i < tilesetCount; i++)
{
var tileset = new TiledMapTileset(input);
var tileset = ReadTileset(reader, map);
map.AddTileset(tileset);
}
}
private static void ReadLayers(ContentReader input, TiledMap map)
private static TiledMapTileset ReadTileset(ContentReader input, TiledMap map)
{
var layerCount = input.ReadInt32();
var textureAssetName = input.GetRelativeAssetName(input.ReadString());
var texture = input.ContentManager.Load<Texture2D>(textureAssetName);
var firstGlobalIdentifier = input.ReadInt32();
var tileWidth = input.ReadInt32();
var tileHeight = input.ReadInt32();
var tileCount = input.ReadInt32();
var spacing = input.ReadInt32();
var margin = input.ReadInt32();
var columns = input.ReadInt32();
var explicitTileCount = input.ReadInt32();
var tileset = new TiledMapTileset(texture, firstGlobalIdentifier, tileWidth, tileHeight, tileCount, spacing, margin, columns);
for (var tileIndex = 0; tileIndex < explicitTileCount; tileIndex++)
{
var localTileIdentifier = input.ReadInt32();
var animationFramesCount = input.ReadInt32();
var tilesetTile = animationFramesCount <= 0
? new TiledMapTilesetTile(localTileIdentifier, input)
: new TiledMapTilesetAnimatedTile(tileset, input, localTileIdentifier, animationFramesCount);
ReadProperties(input, tilesetTile.Properties);
tileset.Tiles.Add(tilesetTile);
}
ReadProperties(input, tileset.Properties);
return tileset;
}
private static void ReadLayers(ContentReader reader, TiledMap map)
{
var layerCount = reader.ReadInt32();
for (var i = 0; i < layerCount; i++)
{
TiledMapLayer layer;
var layerType = (TiledMapLayerType)input.ReadByte();
switch (layerType)
{
case TiledMapLayerType.ImageLayer:
layer = new TiledMapImageLayer(input);
break;
case TiledMapLayerType.TileLayer:
layer = new TiledMapTileLayer(input, map);
break;
case TiledMapLayerType.ObjectLayer:
layer = new TiledMapObjectLayer(input, map);
break;
default:
throw new ArgumentOutOfRangeException();
}
if (layerType != TiledMapLayerType.ObjectLayer)
ReadModels(input, layer, map);
var layer = ReadLayer(reader, map);
map.AddLayer(layer);
}
}
private static void ReadModels(ContentReader input, TiledMapLayer layer, TiledMap map)
private static TiledMapLayer ReadLayer(ContentReader reader, TiledMap map)
{
var modelCount = input.ReadInt32();
var animatedModelCount = input.ReadInt32();
var layerType = (TiledMapLayerType)reader.ReadByte();
var name = reader.ReadString();
var isVisible = reader.ReadBoolean();
var opacity = reader.ReadSingle();
var offsetX = reader.ReadSingle();
var offsetY = reader.ReadSingle();
var offset = new Vector2(offsetX, offsetY);
var properties = new TiledMapProperties();
ReadProperties(reader, properties);
TiledMapLayer layer;
switch (layerType)
{
case TiledMapLayerType.ImageLayer:
layer = ReadImageLayer(reader, name, offset, opacity, isVisible);
break;
case TiledMapLayerType.TileLayer:
layer = ReadTileLayer(reader, name, offset, opacity, isVisible, map);
break;
case TiledMapLayerType.ObjectLayer:
layer = ReadObjectLayer(reader, name, offset, opacity, isVisible, map);
break;
default:
throw new ArgumentOutOfRangeException();
}
if (layerType != TiledMapLayerType.ObjectLayer)
ReadModels(reader, layer, map);
foreach (var property in properties)
layer.Properties.Add(property.Key, property.Value);
return layer;
}
private static TiledMapLayer ReadObjectLayer(ContentReader reader, string name, Vector2 offset, float opacity, bool isVisible, TiledMap map)
{
var color = reader.ReadColor();
var drawOrder = (TiledMapObjectDrawOrder)reader.ReadByte();
var objectCount = reader.ReadInt32();
var objects = new TiledMapObject[objectCount];
for (var i = 0; i < objectCount; i++)
objects[i] = ReadTiledMapObject(reader, map);
return new TiledMapObjectLayer(name, objects, color, drawOrder, offset, opacity, isVisible);
}
private static TiledMapObject ReadTiledMapObject(ContentReader reader, TiledMap map)
{
var objectType = (TiledMapObjectType)reader.ReadByte();
var identifier = reader.ReadInt32();
var name = reader.ReadString();
var type = reader.ReadString();
var position = new Vector2(reader.ReadSingle(), reader.ReadSingle());
var width = reader.ReadSingle();
var height = reader.ReadSingle();
var size = new Size2(width, height);
var rotation = reader.ReadSingle();
var isVisible = reader.ReadBoolean();
var properties = new TiledMapProperties();
const float opacity = 1.0f;
ReadProperties(reader, properties);
TiledMapObject mapObject;
switch (objectType)
{
case TiledMapObjectType.Rectangle:
mapObject = new TiledMapRectangleObject(identifier, name, size, position, rotation, opacity, isVisible);
break;
case TiledMapObjectType.Tile:
var globalTileIdentifierWithFlags = reader.ReadUInt32();
var tile = new TiledMapTile(globalTileIdentifierWithFlags);
var tileset = map.GetTilesetByTileGlobalIdentifier(tile.GlobalIdentifier);
var localTileIdentifier = tile.GlobalIdentifier - tileset.FirstGlobalIdentifier;
var tilesetTile = tileset.Tiles.FirstOrDefault(x => x.LocalTileIdentifier == localTileIdentifier);
mapObject = new TiledMapTileObject(identifier, name, tileset, tilesetTile, size, position, rotation, opacity, isVisible);
break;
case TiledMapObjectType.Ellipse:
mapObject = new TiledMapEllipseObject(identifier, name, size, position, rotation, opacity, isVisible);
break;
case TiledMapObjectType.Polygon:
mapObject = new TiledMapPolygonObject(identifier, name, ReadPoints(reader), size, position, rotation, opacity, isVisible);
break;
case TiledMapObjectType.Polyline:
var points = ReadPoints(reader);
mapObject = new TiledMapPolylineObject(identifier, name, ReadPoints(reader), size, position, rotation, opacity, isVisible);
break;
default:
throw new ArgumentOutOfRangeException();
}
foreach (var property in properties)
mapObject.Properties.Add(property.Key, property.Value);
throw new ArgumentOutOfRangeException();
}
private static Point2[] ReadPoints(ContentReader reader)
{
var pointCount = reader.ReadInt32();
var points = new Point2[pointCount];
for (var i = 0; i < pointCount; i++)
{
var x = reader.ReadSingle();
var y = reader.ReadSingle();
points[i] = new Point2(x, y);
}
return points;
}
private static TiledMapImageLayer ReadImageLayer(ContentReader reader, string name, Vector2 offset, float opacity, bool isVisible)
{
var textureAssetName = reader.GetRelativeAssetName(reader.ReadString());
var texture = reader.ContentManager.Load<Texture2D>(textureAssetName);
var x = reader.ReadSingle();
var y = reader.ReadSingle();
var position = new Vector2(x, y);
return new TiledMapImageLayer(name, texture, position, offset, opacity, isVisible);
}
private static TiledMapTileLayer ReadTileLayer(ContentReader reader, string name, Vector2 offset, float opacity, bool isVisible, TiledMap map)
{
var width = reader.ReadInt32();
var height = reader.ReadInt32();
var tileWidth = map.TileWidth;
var tileHeight = map.TileHeight;
var tileCount = reader.ReadInt32();
var tiles = new TiledMapTile[width * height];
for (var i = 0; i < tileCount; i++)
{
var globalTileIdentifierWithFlags = reader.ReadUInt32();
var x = reader.ReadUInt16();
var y = reader.ReadUInt16();
tiles[x + y * width] = new TiledMapTile(globalTileIdentifierWithFlags);
}
return new TiledMapTileLayer(name, width, height, tileWidth, tileHeight, tiles, offset, opacity, isVisible);
}
private static void ReadModels(ContentReader reader, TiledMapLayer layer, TiledMap map)
{
var modelCount = reader.ReadInt32();
var animatedModelCount = reader.ReadInt32();
var models = layer.Models = new TiledMapLayerModel[modelCount];
var animatedModels = layer.AnimatedModels = new TiledMapLayerAnimatedModel[animatedModelCount];
@@ -94,8 +268,8 @@ namespace MonoGame.Extended.Tiled
for (var modelIndex = 0; modelIndex < modelCount; modelIndex++)
{
var isAnimated = input.ReadBoolean();
var model = isAnimated ? new TiledMapLayerAnimatedModel(input, map) : new TiledMapLayerModel(input);
var isAnimated = reader.ReadBoolean();
var model = isAnimated ? new TiledMapLayerAnimatedModel(reader, map) : new TiledMapLayerModel(reader);
models[modelIndex] = model;
if (isAnimated)
@@ -1,12 +1,14 @@
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
namespace MonoGame.Extended.Tiled
{
public sealed class TiledMapRectangleObject : TiledMapObject
{
internal TiledMapRectangleObject(ContentReader input)
: base(input)
public TiledMapRectangleObject(int identifier, string name, Size2 size, Vector2 position, float rotation = 0, float opacity = 1, bool isVisible = true)
: base(identifier, name, size, position, rotation, opacity, isVisible)
{
}
public override TiledMapObjectType Type => TiledMapObjectType.Rectangle;
}
}
@@ -1,45 +1,33 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
namespace MonoGame.Extended.Tiled
{
public class TiledMapTileLayer : TiledMapLayer
{
// immutable
public TiledMapTileLayer(string name, int width, int height, int tileWidth, int tileHeight, IList<TiledMapTile> tiles,
Vector2? offset = null, float opacity = 1, bool isVisible = true)
: base(name, offset, opacity, isVisible)
{
Width = width;
Height = height;
TileWidth = tileWidth;
TileHeight = tileHeight;
Tiles = new ReadOnlyCollection<TiledMapTile>(tiles);
}
public int Width { get; }
public int Height { get; }
public int TileWidth { get; }
public int TileHeight { get; }
public ReadOnlyCollection<TiledMapTile> Tiles { get; }
internal TiledMapTileLayer(ContentReader input, TiledMap map)
: base(input)
{
Width = input.ReadInt32();
Height = input.ReadInt32();
TileWidth = map.TileWidth;
TileHeight = map.TileHeight;
var tileCount = input.ReadInt32();
var tiles = new TiledMapTile[Width * Height];
Tiles = new ReadOnlyCollection<TiledMapTile>(tiles);
for (var i = 0; i < tileCount; i++)
{
var globalTileIdentifierWithFlags = input.ReadUInt32();
var x = input.ReadUInt16();
var y = input.ReadUInt16();
tiles[x + y * Width] = new TiledMapTile(globalTileIdentifierWithFlags);
}
}
public bool TryGetTile(int x, int y, out TiledMapTile? tile)
{
var index = x + y * Width;
if ((index < 0) || (index >= Tiles.Count))
if (index < 0 || index >= Tiles.Count)
{
tile = null;
return false;
@@ -1,23 +1,19 @@
using System.Linq;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
namespace MonoGame.Extended.Tiled
{
public sealed class TiledMapTileObject : TiledMapObject
{
public TiledMapTilesetTile TilesetTile { get; }
public TiledMapTileset Tileset { get; }
public TiledMapTileObject(ContentReader input, TiledMap map)
: base(input)
public TiledMapTileObject(int identifier, string name, TiledMapTileset tileset, TiledMapTilesetTile tile,
Size2 size, Vector2 position, float rotation = 0, float opacity = 1, bool isVisible = true)
: base(identifier, name, size, position, rotation, opacity, isVisible)
{
var globalTileIdentifierWithFlags = input.ReadUInt32();
var tile = new TiledMapTile(globalTileIdentifierWithFlags);
Tileset = map.GetTilesetByTileGlobalIdentifier(tile.GlobalIdentifier);
var localTileIdentifier = tile.GlobalIdentifier - Tileset.FirstGlobalIdentifier;
TilesetTile = Tileset.Tiles.FirstOrDefault(x => x.LocalTileIdentifier == localTileIdentifier);
Tileset = tileset;
Tile = tile;
}
public TiledMapTilesetTile Tile { get; }
public TiledMapTileset Tileset { get; }
public override TiledMapObjectType Type => TiledMapObjectType.Tile;
}
}
@@ -1,15 +1,25 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using MonoGame.Extended.Content;
namespace MonoGame.Extended.Tiled
{
public class TiledMapTileset
{
private readonly Dictionary<int, TiledMapTilesetAnimatedTile> _animatedTilesByLocalTileIdentifier;
public TiledMapTileset(Texture2D texture, int firstGlobalIdentifier, int tileWidth, int tileHeight, int tileCount, int spacing, int margin, int columns)
{
Texture = texture;
FirstGlobalIdentifier = firstGlobalIdentifier;
TileWidth = tileWidth;
TileHeight = tileHeight;
TileCount = tileCount;
Spacing = spacing;
Margin = margin;
Columns = columns;
Properties = new TiledMapProperties();
Tiles = new List<TiledMapTilesetTile>();
}
public string Name => Texture.Name;
public Texture2D Texture { get; }
@@ -20,60 +30,9 @@ namespace MonoGame.Extended.Tiled
public int Margin { get; }
public int TileCount { get; }
public int Columns { get; }
public ReadOnlyCollection<TiledMapTilesetTile> Tiles { get; private set; }
public ReadOnlyCollection<TiledMapTilesetAnimatedTile> AnimatedTiles { get; private set; }
public List<TiledMapTilesetTile> Tiles { get; }
public TiledMapProperties Properties { get; }
internal TiledMapTileset(ContentReader input)
{
var textureAssetName = input.GetRelativeAssetName(input.ReadString());
var animatedTiles = new List<TiledMapTilesetAnimatedTile>();
var tiles = new List<TiledMapTilesetTile>();
_animatedTilesByLocalTileIdentifier = new Dictionary<int, TiledMapTilesetAnimatedTile>();
Texture = input.ContentManager.Load<Texture2D>(textureAssetName);
FirstGlobalIdentifier = input.ReadInt32();
TileWidth = input.ReadInt32();
TileHeight = input.ReadInt32();
TileCount = input.ReadInt32();
Spacing = input.ReadInt32();
Margin = input.ReadInt32();
Columns = input.ReadInt32();
Properties = new TiledMapProperties();
var explicitTileCount = input.ReadInt32();
for (var tileIndex = 0; tileIndex < explicitTileCount; tileIndex++)
{
var localTileIdentifier = input.ReadInt32();
var animationFramesCount = input.ReadInt32();
TiledMapTilesetTile tilesetTile;
if (animationFramesCount <= 0)
{
tilesetTile = new TiledMapTilesetTile(localTileIdentifier,input);
}
else
{
var animatedTilesetTile = new TiledMapTilesetAnimatedTile(this, input, localTileIdentifier, animationFramesCount);
animatedTiles.Add(animatedTilesetTile);
_animatedTilesByLocalTileIdentifier.Add(localTileIdentifier, animatedTilesetTile);
tilesetTile = animatedTilesetTile;
}
tiles.Add(tilesetTile);
input.ReadTiledMapProperties(tilesetTile.Properties);
}
input.ReadTiledMapProperties(Properties);
Tiles = new ReadOnlyCollection<TiledMapTilesetTile>(tiles);
AnimatedTiles = new ReadOnlyCollection<TiledMapTilesetAnimatedTile>(animatedTiles);
}
public Rectangle GetTileRegion(int localTileIdentifier)
{
return TiledMapHelper.GetTileSourceRectangle(localTileIdentifier, TileWidth, TileHeight, Columns, Margin, Spacing);
@@ -81,9 +40,10 @@ namespace MonoGame.Extended.Tiled
public TiledMapTilesetAnimatedTile GetAnimatedTilesetTileByLocalTileIdentifier(int localTileIdentifier)
{
TiledMapTilesetAnimatedTile animatedTile;
_animatedTilesByLocalTileIdentifier.TryGetValue(localTileIdentifier, out animatedTile);
return animatedTile;
throw new NotImplementedException();
//TiledMapTilesetAnimatedTile animatedTile;
//_animatedTilesByLocalTileIdentifier.TryGetValue(localTileIdentifier, out animatedTile);
//return animatedTile;
}
public bool ContainsGlobalIdentifier(int globalIdentifier)
@@ -43,7 +43,7 @@ namespace MonoGame.Extended.Tiled
}
public int LocalTileIdentifier { get; set; }
public TiledMapProperties Properties { get; private set; }
public TiledMapProperties Properties { get; }
public TiledMapObject[] Objects { get; set; }
}
}