protected override void InternalFromXml(System.Xml.Linq.XElement xml, TmxMap tmxMap) { // Get the tile uint gid = TmxHelper.GetAttributeAsUInt(xml, "gid"); this.Tile = tmxMap.Tiles[gid]; // Our size is given by the tile this.Size = this.Tile.TileSize; }
public Point GetMapPositionAt(int x, int y, TmxTile tile) { Point point = GetMapPositionAt(x, y); // The tile may have different dimensions than the cells of the map so correct for that // In this case, the y-position needs to be adjusted point.Y = (point.Y + this.TileHeight) - tile.TileSize.Height; return point; }
private PointF[] CalculateFaceTextureCoordinates(TmxTile tmxTile, bool flipDiagonal, bool flipHorizontal, bool flipVertical) { Point imageLocation = tmxTile.LocationOnSource; Size tileSize = tmxTile.TileSize; Size imageSize = tmxTile.TmxImage.Size; PointF[] points = new PointF[4]; points[0] = imageLocation; points[1] = PointF.Add(imageLocation, new Size(tileSize.Width, 0)); points[2] = PointF.Add(imageLocation, tileSize); points[3] = PointF.Add(imageLocation, new Size(0, tileSize.Height)); PointF center = new PointF(tileSize.Width * 0.5f, tileSize.Height * 0.5f); center.X += imageLocation.X; center.Y += imageLocation.Y; TmxMath.TransformPoints_DiagFirst(points, center, flipDiagonal, flipHorizontal, flipVertical); //TmxMath.TransformPoints(points, center, flipDiagonal, flipHorizontal, flipVertical); PointF[] coordinates = new PointF[4]; coordinates[3] = PointToTextureCoordinate(points[0], imageSize); coordinates[2] = PointToTextureCoordinate(points[1], imageSize); coordinates[1] = PointToTextureCoordinate(points[2], imageSize); coordinates[0] = PointToTextureCoordinate(points[3], imageSize); // Apply a small bias to the "inner" edges of the texels // This keeps us from seeing seams //const float bias = 1.0f / 8192.0f; //const float bias = 1.0f / 4096.0f; //const float bias = 1.0f / 2048.0f; if (Tiled2Unity.Settings.TexelBias > 0) { float bias = 1.0f / Tiled2Unity.Settings.TexelBias; PointF[] multiply = new PointF[4]; multiply[0] = new PointF(1, 1); multiply[1] = new PointF(-1, 1); multiply[2] = new PointF(-1, -1); multiply[3] = new PointF(1, -1); // This nudge has to be transformed too TmxMath.TransformPoints_DiagFirst(multiply, Point.Empty, flipDiagonal, flipHorizontal, flipVertical); coordinates[0] = TmxMath.AddPoints(coordinates[0], TmxMath.ScalePoints(multiply[0], bias)); coordinates[1] = TmxMath.AddPoints(coordinates[1], TmxMath.ScalePoints(multiply[1], bias)); coordinates[2] = TmxMath.AddPoints(coordinates[2], TmxMath.ScalePoints(multiply[2], bias)); coordinates[3] = TmxMath.AddPoints(coordinates[3], TmxMath.ScalePoints(multiply[3], bias)); } return coordinates; }
private void ParseTilesetFromImageLayer(XElement elemImageLayer) { string tilesetName = TmxHelper.GetAttributeAsString(elemImageLayer, "name"); XElement xmlImage = elemImageLayer.Element("image"); if (xmlImage == null) { Logger.WriteWarning("Image Layer '{0}' has no image assigned.", tilesetName); return; } TmxImage tmxImage = TmxImage.FromXml(xmlImage); // The "firstId" is is always one more than all the tiles that we've already parsed (which may be zero) uint firstId = 1; if (this.Tiles.Count > 0) { firstId = this.Tiles.Max(t => t.Key) + 1; } uint localId = 1; uint globalId = firstId + localId; TmxTile tile = new TmxTile(globalId, localId, tilesetName, tmxImage); tile.SetTileSize(tmxImage.Size.Width, tmxImage.Size.Height); tile.SetLocationOnSource(0, 0); this.Tiles[tile.GlobalId] = tile; }
// This method is called eventually for external tilesets too // Only the gid attribute has been consumed at this point for the tileset private void ParseInternalTileset(XElement elemTileset, uint firstId) { string tilesetName = TmxHelper.GetAttributeAsString(elemTileset, "name"); Logger.WriteLine("Parse internal tileset '{0}' (gid = {1}) ...", tilesetName, firstId); int tileWidth = TmxHelper.GetAttributeAsInt(elemTileset, "tilewidth"); int tileHeight = TmxHelper.GetAttributeAsInt(elemTileset, "tileheight"); int spacing = TmxHelper.GetAttributeAsInt(elemTileset, "spacing", 0); int margin = TmxHelper.GetAttributeAsInt(elemTileset, "margin", 0); PointF tileOffset = PointF.Empty; XElement xmlTileOffset = elemTileset.Element("tileoffset"); if (xmlTileOffset != null) { tileOffset.X = TmxHelper.GetAttributeAsInt(xmlTileOffset, "x"); tileOffset.Y = TmxHelper.GetAttributeAsInt(xmlTileOffset, "y"); } IList<TmxTile> tilesToAdd = new List<TmxTile>(); // Tilesets may have an image for all tiles within it, or it may have an image per tile if (elemTileset.Element("image") != null) { TmxImage tmxImage = TmxImage.FromXml(elemTileset.Element("image")); // Create all the tiles // This is a bit complicated because of spacing and margin // (Margin is ignored from Width and Height) for (int end_y = margin + tileHeight; end_y <= tmxImage.Size.Height; end_y += spacing + tileHeight) { for (int end_x = margin + tileWidth; end_x <= tmxImage.Size.Width; end_x += spacing + tileWidth) { uint localId = (uint) tilesToAdd.Count(); uint globalId = firstId + localId; TmxTile tile = new TmxTile(globalId, localId, tilesetName, tmxImage); tile.Offset = tileOffset; tile.SetTileSize(tileWidth, tileHeight); tile.SetLocationOnSource(end_x - tileWidth, end_y - tileHeight); tilesToAdd.Add(tile); } } } else { // Each tile will have it's own image foreach (var t in elemTileset.Elements("tile")) { TmxImage tmxImage = TmxImage.FromXml(t.Element("image")); uint localId = (uint)tilesToAdd.Count(); // Local Id can be overridden by the tile element // This is because tiles can be removed from the tileset, so we won'd always have a zero-based index localId = TmxHelper.GetAttributeAsUInt(t, "id", localId); uint globalId = firstId + localId; TmxTile tile = new TmxTile(globalId, localId, tilesetName, tmxImage); tile.Offset = tileOffset; tile.SetTileSize(tmxImage.Size.Width, tmxImage.Size.Height); tile.SetLocationOnSource(0, 0); tilesToAdd.Add(tile); } } StringBuilder builder = new StringBuilder(); foreach (TmxTile tile in tilesToAdd) { builder.AppendFormat("{0}", tile.ToString()); if (tile != tilesToAdd.Last()) builder.Append("\n"); this.Tiles[tile.GlobalId] = tile; } Logger.WriteLine("Added {0} tiles", tilesToAdd.Count); // Add any extra data to tiles foreach (var elemTile in elemTileset.Elements("tile")) { int localTileId = TmxHelper.GetAttributeAsInt(elemTile, "id"); var tiles = from t in this.Tiles where t.Value.GlobalId == localTileId + firstId select t.Value; // Note that some old tile data may be sticking around if (tiles.Count() == 0) { Logger.WriteWarning("Tile '{0}' in tileset '{1}' does not exist but there is tile data for it.\n{2}", localTileId, tilesetName, elemTile.ToString()); } else { tiles.First().ParseTileXml(elemTile, this, firstId); } } }
private void ParseTilesetFromImageLayer(XElement elemImageLayer) { string tilesetName = TmxHelper.GetAttributeAsString(elemImageLayer, "name"); XElement xmlImage = elemImageLayer.Element("image"); if (xmlImage == null) { Program.WriteWarning("Image Layer '{0}' has no image assigned.", tilesetName); return; } TmxImage tmxImage = TmxImage.FromXml(xmlImage); uint firstId = this.Tiles.Max(t => t.Key) + 1; uint localId = 1; uint globalId = firstId + localId; TmxTile tile = new TmxTile(globalId, localId, tilesetName, tmxImage); tile.SetTileSize(tmxImage.Size.Width, tmxImage.Size.Height); tile.SetLocationOnSource(0, 0); this.Tiles[tile.GlobalId] = tile; }
private bool CanAddFrame(TmxTile tile, int startMs, int durationMs) { if (IsMeshFull()) return false; if (this.TmxImage != tile.TmxImage) return false; if (this.StartTimeMs != startMs) return false; if (this.DurationMs != durationMs) return false; return true; }
// Creates a TmxMesh from a tile (for tile objects) public static List<TmxMesh> FromTmxTile(TmxTile tmxTile, TmxMap tmxMap) { List<TmxMesh> meshes = new List<TmxMesh>(); int timeMs = 0; foreach (var frame in tmxTile.Animation.Frames) { uint frameTileId = frame.GlobalTileId; TmxTile frameTile = tmxMap.Tiles[frameTileId]; TmxMesh mesh = new TmxMesh(); mesh.TileIds = new uint[1]; mesh.TileIds[0] = frameTileId; mesh.UniqueMeshName = String.Format("mesh_tile_{0}", TmxMath.GetTileIdWithoutFlags(frameTileId).ToString("D4")); mesh.TmxImage = frameTile.TmxImage; mesh.ObjectName = "tile_obj"; // Keep track of the timing for this mesh (non-animating meshes will have a start time and duration of 0) mesh.StartTimeMs = timeMs; mesh.DurationMs = frame.DurationMs; mesh.FullAnimationDurationMs = tmxTile.Animation.TotalTimeMs; if (mesh.DurationMs != 0) { // Decorate the name a bit with some animation details for the frame mesh.ObjectName += string.Format("[{0}-{1}]", timeMs, timeMs + mesh.DurationMs); } // Advance time timeMs += frame.DurationMs; // Add the animation frame to our list of meshes meshes.Add(mesh); } return meshes; }
public static IEnumerable<TileFrame> EnumerateFramesFromTile(TmxTile tile, TmxMap map) { if (tile.Animation == null) { // Treat the tile as a single-frame animation yield return new TileFrame { Tile = tile, Position_z = 0 }; } else { // Visit all the frames of the animated tile float sign = 1.0f; foreach (var f in tile.Animation.Frames) { // The frame Id is baked into the z value of the tile // (Negative values frames are not shown, so we start off with only the first tile being positive/visible) float z = (float)f.UniqueFrameId * sign; yield return new TileFrame { Tile = map.Tiles[f.GlobalTileId], Position_z = z }; // Next frames start off invisible / negative sign = -1.0f; } } }
private PointF[] CalculateFaceTextureCoordinates(TmxTile tmxTile, bool flipDiagonal, bool flipHorizontal, bool flipVertical) { Point imageLocation = tmxTile.LocationOnSource; Size tileSize = tmxTile.TileSize; Size imageSize = tmxTile.TmxImage.Size; PointF[] points = new PointF[4]; points[0] = imageLocation; points[1] = PointF.Add(imageLocation, new Size(tileSize.Width, 0)); points[2] = PointF.Add(imageLocation, tileSize); points[3] = PointF.Add(imageLocation, new Size(0, tileSize.Height)); PointF center = new PointF(tileSize.Width * 0.5f, tileSize.Height * 0.5f); center.X += imageLocation.X; center.Y += imageLocation.Y; TmxMath.TransformPoints_DiagFirst(points, center, flipDiagonal, flipHorizontal, flipVertical); //TmxMath.TransformPoints(points, center, flipDiagonal, flipHorizontal, flipVertical); PointF[] coordinates = new PointF[4]; coordinates[3] = PointToTextureCoordinate(points[0], imageSize); coordinates[2] = PointToTextureCoordinate(points[1], imageSize); coordinates[1] = PointToTextureCoordinate(points[2], imageSize); coordinates[0] = PointToTextureCoordinate(points[3], imageSize); // Apply a small bias to the "inner" edges of the texels // This keeps us from seeing seams // (If seams continue along "outer" edges we can try applying the bias there as well) // Note: On Oct 25, a user was having issues with outer edges, so I brought those in as well afterall (for version 0.9.5.4) //const float bias = 1.0f / 8192.0f; //const float bias = 1.0f / 4096.0f; //const float bias = 1.0f / 2048.0f; float bias = 1.0f / Program.TexelBias; coordinates[0].X += bias; coordinates[0].Y += bias; coordinates[1].X -= bias; coordinates[1].Y += bias; coordinates[2].X -= bias; coordinates[2].Y -= bias; coordinates[3].X += bias; coordinates[3].Y -= bias; return coordinates; }
// This method is called eventually for external tilesets too // Only the gid attribute has been consumed at this point for the tileset private void ParseInternalTileset(XElement elemTileset, uint firstId) { string tilesetName = TmxHelper.GetAttributeAsString(elemTileset, "name"); Program.WriteLine("Parse internal tileset '{0}' (gid = {1}) ...", tilesetName, firstId); Program.WriteVerbose(elemTileset.ToString()); int tileWidth = TmxHelper.GetAttributeAsInt(elemTileset, "tilewidth"); int tileHeight = TmxHelper.GetAttributeAsInt(elemTileset, "tileheight"); int spacing = TmxHelper.GetAttributeAsInt(elemTileset, "spacing", 0); int margin = TmxHelper.GetAttributeAsInt(elemTileset, "margin", 0); IList<TmxTile> tilesToAdd = new List<TmxTile>(); // Tilesets may have an image for all tiles within it, or it may have an image per tile if (elemTileset.Element("image") != null) { TmxImage tmxImage = TmxImage.FromXml(elemTileset.Element("image")); RegisterImagePath(tmxImage.Path); // Create all the tiles // This is a bit complicated because of spacing and margin // (Margin is ignored from Width and Height) for (int end_y = margin + tileHeight; end_y <= tmxImage.Size.Height; end_y += spacing + tileHeight) { for (int end_x = margin + tileWidth; end_x <= tmxImage.Size.Width; end_x += spacing + tileWidth) { uint localId = (uint) tilesToAdd.Count(); uint globalId = firstId + localId; TmxTile tile = new TmxTile(globalId, localId, tilesetName, tmxImage); tile.SetTileSize(tileWidth, tileHeight); tile.SetLocationOnSource(end_x - tileWidth, end_y - tileHeight); tilesToAdd.Add(tile); } } } else { // Each tile will have it's own image foreach (var t in elemTileset.Elements("tile")) { TmxImage tmxImage = TmxImage.FromXml(t.Element("image")); RegisterImagePath(tmxImage.Path); uint localId = (uint)tilesToAdd.Count(); uint globalId = firstId + localId; TmxTile tile = new TmxTile(globalId, localId, tilesetName, tmxImage); tile.SetTileSize(tmxImage.Size.Width, tmxImage.Size.Height); tile.SetLocationOnSource(0, 0); tilesToAdd.Add(tile); } } StringBuilder builder = new StringBuilder(); foreach (TmxTile tile in tilesToAdd) { builder.AppendFormat("{0}", tile.ToString()); if (tile != tilesToAdd.Last()) builder.Append("\n"); this.Tiles[tile.GlobalId] = tile; } Program.WriteLine("Added {0} tiles", tilesToAdd.Count); Program.WriteVerbose(builder.ToString()); // Add any extra data to tiles foreach (var elemTile in elemTileset.Elements("tile")) { int localTileId = TmxHelper.GetAttributeAsInt(elemTile, "id"); var tiles = from t in this.Tiles where t.Value.GlobalId == localTileId + firstId select t.Value; tiles.First().ParseXml(elemTile, this, firstId); } }
// Splits a layer into TmxMesh instances public static List <TmxMesh> ListFromTmxLayer(TmxLayer layer) { List <TmxMesh> meshes = new List <TmxMesh>(); for (int i = 0; i < layer.TileIds.Count(); ++i) { // Copy the tile unto the mesh that uses the same image // (In other words, we are grouping tiles by images into a mesh) uint tileId = layer.TileIds[i]; TmxTile tile = layer.TmxMap.GetTileFromTileId(tileId); if (tile == null) { continue; } int timeMs = 0; foreach (var frame in tile.Animation.Frames) { uint frameTileId = frame.GlobalTileId; // Have to put any rotations/flipping from the source tile into this one frameTileId |= (tileId & TmxMath.FLIPPED_HORIZONTALLY_FLAG); frameTileId |= (tileId & TmxMath.FLIPPED_VERTICALLY_FLAG); frameTileId |= (tileId & TmxMath.FLIPPED_DIAGONALLY_FLAG); // Find a mesh to stick this tile into (if it exists) TmxMesh mesh = meshes.Find(m => m.CanAddFrame(tile, timeMs, frame.DurationMs, tile.Animation.TotalTimeMs)); if (mesh == null) { var frameTile = layer.TmxMap.GetTileFromTileId(frameTileId); // Create a new mesh and add it to our list mesh = new TmxMesh(); mesh.TileIds = new uint[layer.TileIds.Count()]; mesh.UniqueMeshName = String.Format("mesh_{0}", layer.TmxMap.GetUniqueId().ToString("D4")); mesh.TmxImage = frameTile.TmxImage; // Keep track of the timing for this mesh (non-animating meshes will have a start time and duration of 0) mesh.StartTimeMs = timeMs; mesh.DurationMs = frame.DurationMs; mesh.FullAnimationDurationMs = tile.Animation.TotalTimeMs; mesh.ObjectName = Path.GetFileNameWithoutExtension(frameTile.TmxImage.AbsolutePath); if (mesh.DurationMs != 0) { // Decorate the name a bit with some animation details for the frame mesh.ObjectName += string.Format("[{0}-{1}][{2}]", timeMs, timeMs + mesh.DurationMs, mesh.FullAnimationDurationMs); } meshes.Add(mesh); } // This mesh contains this tile mesh.AddTile(i, frameTileId); // Advance time timeMs += frame.DurationMs; } } return(meshes); }
// This method is called eventually for external tilesets too // Only the gid attribute has been consumed at this point for the tileset private void ParseInternalTileset(XElement elemTileset, uint firstId) { string tilesetName = TmxHelper.GetAttributeAsString(elemTileset, "name"); Program.WriteLine("Parse internal tileset '{0}' (gid = {1}) ...", tilesetName, firstId); Program.WriteVerbose(elemTileset.ToString()); int tileWidth = TmxHelper.GetAttributeAsInt(elemTileset, "tilewidth"); int tileHeight = TmxHelper.GetAttributeAsInt(elemTileset, "tileheight"); int spacing = TmxHelper.GetAttributeAsInt(elemTileset, "spacing", 0); int margin = TmxHelper.GetAttributeAsInt(elemTileset, "margin", 0); PointF tileOffset = PointF.Empty; XElement xmlTileOffset = elemTileset.Element("tileoffset"); if (xmlTileOffset != null) { tileOffset.X = TmxHelper.GetAttributeAsInt(xmlTileOffset, "x"); tileOffset.Y = TmxHelper.GetAttributeAsInt(xmlTileOffset, "y"); } IList <TmxTile> tilesToAdd = new List <TmxTile>(); // Tilesets may have an image for all tiles within it, or it may have an image per tile if (elemTileset.Element("image") != null) { TmxImage tmxImage = TmxImage.FromXml(elemTileset.Element("image")); // Create all the tiles // This is a bit complicated because of spacing and margin // (Margin is ignored from Width and Height) for (int end_y = margin + tileHeight; end_y <= tmxImage.Size.Height; end_y += spacing + tileHeight) { for (int end_x = margin + tileWidth; end_x <= tmxImage.Size.Width; end_x += spacing + tileWidth) { uint localId = (uint)tilesToAdd.Count(); uint globalId = firstId + localId; TmxTile tile = new TmxTile(globalId, localId, tilesetName, tmxImage); tile.Offset = tileOffset; tile.SetTileSize(tileWidth, tileHeight); tile.SetLocationOnSource(end_x - tileWidth, end_y - tileHeight); tilesToAdd.Add(tile); } } } else { // Each tile will have it's own image foreach (var t in elemTileset.Elements("tile")) { TmxImage tmxImage = TmxImage.FromXml(t.Element("image")); uint localId = (uint)tilesToAdd.Count(); uint globalId = firstId + localId; TmxTile tile = new TmxTile(globalId, localId, tilesetName, tmxImage); tile.Offset = tileOffset; tile.SetTileSize(tmxImage.Size.Width, tmxImage.Size.Height); tile.SetLocationOnSource(0, 0); tilesToAdd.Add(tile); } } StringBuilder builder = new StringBuilder(); foreach (TmxTile tile in tilesToAdd) { builder.AppendFormat("{0}", tile.ToString()); if (tile != tilesToAdd.Last()) { builder.Append("\n"); } this.Tiles[tile.GlobalId] = tile; } Program.WriteLine("Added {0} tiles", tilesToAdd.Count); Program.WriteVerbose(builder.ToString()); // Add any extra data to tiles foreach (var elemTile in elemTileset.Elements("tile")) { int localTileId = TmxHelper.GetAttributeAsInt(elemTile, "id"); var tiles = from t in this.Tiles where t.Value.GlobalId == localTileId + firstId select t.Value; tiles.First().ParseTileXml(elemTile, this, firstId); } }