private PointF[] CalculateFaceVertices(Point mapLocation, Size tileSize, int mapTileHeight, PointF offset) { // Location on map is complicated by tiles that are 'higher' than the tile size given for the overall map mapLocation.Offset(0, -tileSize.Height + mapTileHeight); PointF pt0 = mapLocation; PointF pt1 = PointF.Add(mapLocation, new Size(tileSize.Width, 0)); PointF pt2 = PointF.Add(mapLocation, tileSize); PointF pt3 = PointF.Add(mapLocation, new Size(0, tileSize.Height)); // Apply the tile offset pt0 = TmxMath.AddPoints(pt0, offset); pt1 = TmxMath.AddPoints(pt1, offset); pt2 = TmxMath.AddPoints(pt2, offset); pt3 = TmxMath.AddPoints(pt3, offset); // We need to use ccw winding for Wavefront objects PointF[] vertices = new PointF[4]; vertices[3] = PointFToObjVertex(pt0); vertices[2] = PointFToObjVertex(pt1); vertices[1] = PointFToObjVertex(pt2); vertices[0] = PointFToObjVertex(pt3); return(vertices); }
protected override void InternalFromXml(System.Xml.Linq.XElement xml, TmxMap tmxMap) { // Get the tile uint gid = TmxHelper.GetAttributeAsUInt(xml, "gid"); this.FlippedHorizontal = TmxMath.IsTileFlippedHorizontally(gid); this.FlippedVertical = TmxMath.IsTileFlippedVertically(gid); uint rawTileId = TmxMath.GetTileIdWithoutFlags(gid); this.Tile = tmxMap.Tiles[rawTileId]; // The tile needs to have a mesh on it. // Note: The tile may already be referenced by another TmxObjectTile instance, and as such will have its mesh data already made if (this.Tile.Meshes.Count() == 0) { this.Tile.Meshes = TmxMesh.FromTmxTile(this.Tile, tmxMap); } // Check properties for layer placement if (this.Properties.PropertyMap.ContainsKey("unity:sortingLayerName")) { this.SortingLayerName = this.Properties.GetPropertyValueAsString("unity:sortingLayerName"); } if (this.Properties.PropertyMap.ContainsKey("unity:sortingOrder")) { this.SortingOrder = this.Properties.GetPropertyValueAsInt("unity:sortingOrder"); } }
private void ParseImageLayerXml(XElement xml) { if (xml.Element("image") == null) { Logger.WriteWarning("Image Layer '{0}' is being ignored since it has no image.", base.Name); base.Ignore = IgnoreSettings.True; } else { Width = 1; Height = 1; string imagePath = TmxHelper.GetAttributeAsFullPath(xml.Element("image"), "source"); TmxTile value = base.ParentMap.Tiles.First((KeyValuePair <uint, TmxTile> t) => t.Value.TmxImage.AbsolutePath.ToLower() == imagePath.ToLower()).Value; Data = new TmxData(this); TmxChunk tmxChunk = new TmxChunk(Data); tmxChunk.X = 0; tmxChunk.Y = 0; tmxChunk.Width = 1; tmxChunk.Height = 1; tmxChunk.TileIds.Add(value.GlobalId); Data.Chunks.Add(tmxChunk); PointF offset = base.Offset; offset.Y -= (float)base.ParentMap.TileHeight; offset.Y += (float)value.TmxImage.Size.Height; PointF pointF = TmxMath.TileCornerInScreenCoordinates(base.ParentMap, 0, 0); offset.X -= pointF.X; offset.Y -= pointF.Y; offset.X += TmxHelper.GetAttributeAsFloat(xml, "x", 0f); offset.Y += TmxHelper.GetAttributeAsFloat(xml, "y", 0f); base.Offset = offset; } }
private void ReadTileIds(XElement xml) { TileIds.Clear(); if (ParentData.Encoding == DataEncoding.Xml) { ReadTileIds_Xml(xml); } else if (ParentData.Encoding == DataEncoding.Csv) { ReadTiledIds_Csv(xml.Value); } else if (ParentData.Encoding == DataEncoding.Base64) { ReadTileIds_Base64(xml.Value); } else { TmxException.ThrowFormat("Unsupported encoding for chunk data in layer '{0}'", ParentData.ParentLayer); } for (int i = 0; i < TileIds.Count; i++) { uint tileId = TileIds[i]; tileId = TmxMath.GetTileIdWithoutFlags(tileId); if (!ParentData.ParentLayer.ParentMap.Tiles.ContainsKey(tileId)) { TileIds[i] = 0u; } } }
private PointF[] CalculateFaceVertices_TileObject(Size tileSize, PointF offset) { // Tile Object vertices are not concerned about where they are placed in the world PointF origin = PointF.Empty; PointF pt0 = origin; PointF pt1 = PointF.Add(origin, new Size(tileSize.Width, 0)); PointF pt2 = PointF.Add(origin, tileSize); PointF pt3 = PointF.Add(origin, new Size(0, tileSize.Height)); // Apply the tile offset pt0 = TmxMath.AddPoints(pt0, offset); pt1 = TmxMath.AddPoints(pt1, offset); pt2 = TmxMath.AddPoints(pt2, offset); pt3 = TmxMath.AddPoints(pt3, offset); // We need to use ccw winding for Wavefront objects PointF[] vertices = new PointF[4]; vertices[3] = PointFToObjVertex(pt0); vertices[2] = PointFToObjVertex(pt1); vertices[1] = PointFToObjVertex(pt2); vertices[0] = PointFToObjVertex(pt3); return(vertices); }
private void BuildCollisionLayers_ByObjectType() { for (int i = 0; i < Data.Chunks.Count; i++) { TmxChunk tmxChunk = Data.Chunks[i]; for (int j = 0; j < tmxChunk.TileIds.Count; j++) { uint num = tmxChunk.TileIds[j]; if (num != 0) { uint tileIdWithoutFlags = TmxMath.GetTileIdWithoutFlags(num); foreach (TmxObject @object in base.ParentMap.Tiles[tileIdWithoutFlags].ObjectGroup.Objects) { if (@object is TmxHasPoints) { TmxLayer tmxLayer = CollisionLayers.Find((TmxLayer l) => string.Compare(l.Name, @object.Type, true) == 0); if (tmxLayer == null) { tmxLayer = new TmxLayer(null, base.ParentMap); CollisionLayers.Add(tmxLayer); tmxLayer.Name = @object.Type; tmxLayer.Offset = base.Offset; tmxLayer.Width = Width; tmxLayer.Height = Height; tmxLayer.Ignore = base.Ignore; tmxLayer.Properties = base.Properties; tmxLayer.Data = Data.MakeEmptyCopy(tmxLayer); } tmxLayer.Data.Chunks[i].TileIds[j] = num; } } } } } }
protected override void InternalFromXml(System.Xml.Linq.XElement xml, TmxMap tmxMap) { Debug.Assert(xml.Name == "object"); Debug.Assert(xml.Element("polyline") != null); var points = from pt in xml.Element("polyline").Attribute("points").Value.Split(' ') let x = float.Parse(pt.Split(',')[0]) let y = float.Parse(pt.Split(',')[1]) select new PointF(x, y); // If there are only 2 points in the polyline then we force a midpoint between them // This is because the clipper library is rejecting polylines unless there is 3 or more points if (points.Count() == 2) { var A = points.First(); var B = points.Last(); var M = TmxMath.MidPoint(A, B); this.Points = new List <PointF>() { A, M, B }; } else { this.Points = points.ToList(); } }
public static TmxObject FromXml(XElement xml, TmxObjectGroup tmxObjectGroup, TmxMap tmxMap) { Logger.WriteVerbose("Parsing object ..."); uint attributeAsUInt = TmxHelper.GetAttributeAsUInt(xml, "tid", 0u); if (attributeAsUInt != 0 && tmxMap.Templates.TryGetValue(attributeAsUInt, out TgxTemplate value)) { xml = value.Templatize(xml); tmxMap = value.TemplateGroupMap; } TmxObject tmxObject = null; if (xml.Element("ellipse") != null) { tmxObject = new TmxObjectEllipse(); } else if (xml.Element("polygon") != null) { tmxObject = new TmxObjectPolygon(); } else if (xml.Element("polyline") != null) { tmxObject = new TmxObjectPolyline(); } else if (xml.Attribute("gid") != null) { uint attributeAsUInt2 = TmxHelper.GetAttributeAsUInt(xml, "gid"); attributeAsUInt2 = TmxMath.GetTileIdWithoutFlags(attributeAsUInt2); if (tmxMap.Tiles.ContainsKey(attributeAsUInt2)) { tmxObject = new TmxObjectTile(); } else { Logger.WriteWarning("Tile Id {0} not found in tilesets. Using a rectangle instead.\n{1}", attributeAsUInt2, xml.ToString()); tmxObject = new TmxObjectRectangle(); } } else { tmxObject = new TmxObjectRectangle(); } tmxObject.Id = TmxHelper.GetAttributeAsInt(xml, "id", 0); tmxObject.Name = TmxHelper.GetAttributeAsString(xml, "name", ""); tmxObject.Type = TmxHelper.GetAttributeAsString(xml, "type", ""); tmxObject.Visible = (TmxHelper.GetAttributeAsInt(xml, "visible", 1) == 1); tmxObject.ParentObjectGroup = tmxObjectGroup; float attributeAsFloat = TmxHelper.GetAttributeAsFloat(xml, "x"); float attributeAsFloat2 = TmxHelper.GetAttributeAsFloat(xml, "y"); float attributeAsFloat3 = TmxHelper.GetAttributeAsFloat(xml, "width", 0f); float attributeAsFloat4 = TmxHelper.GetAttributeAsFloat(xml, "height", 0f); float attributeAsFloat5 = TmxHelper.GetAttributeAsFloat(xml, "rotation", 0f); tmxObject.Position = new PointF(attributeAsFloat, attributeAsFloat2); tmxObject.Size = new SizeF(attributeAsFloat3, attributeAsFloat4); tmxObject.Rotation = attributeAsFloat5; tmxObject.Properties = TmxProperties.FromXml(xml); tmxObject.InternalFromXml(xml, tmxMap); return(tmxObject); }
private void DrawPolygon(Graphics g, Pen pen, Brush brush, TmxObjectPolygon tmxPolygon) { var points = TmxMath.GetPointsInMapSpace(this.tmxMap, tmxPolygon).ToArray(); g.FillPolygon(brush, points); g.DrawPolygon(pen, points); }
static public Point TileCornerInGridCoordinates(TmxMap tmxMap, int x, int y) { // Support different map display types (orthographic, isometric, etc..) // Note: simulates "tileToScreenCoords" function from Tiled source if (tmxMap.Orientation == TmxMap.MapOrientation.Isometric) { Point point = Point.Empty; int origin_x = tmxMap.Height * tmxMap.TileWidth / 2; point.X = (x - y) * tmxMap.TileWidth / 2 + origin_x; point.Y = (x + y) * tmxMap.TileHeight / 2; return(point); } else if (tmxMap.Orientation == TmxMap.MapOrientation.Staggered || tmxMap.Orientation == TmxMap.MapOrientation.Hexagonal) { Point point = Point.Empty; int tileWidth = tmxMap.TileWidth & ~1; int tileHeight = tmxMap.TileHeight & ~1; int sideLengthX = tmxMap.StaggerAxis == TmxMap.MapStaggerAxis.X ? tmxMap.HexSideLength : 0; int sideLengthY = tmxMap.StaggerAxis == TmxMap.MapStaggerAxis.Y ? tmxMap.HexSideLength : 0; int sideOffsetX = (tileWidth - sideLengthX) / 2; int sideOffsetY = (tileHeight - sideLengthY) / 2; int columnWidth = sideOffsetX + sideLengthX; int rowHeight = sideOffsetY + sideLengthY; if (tmxMap.StaggerAxis == TmxMap.MapStaggerAxis.X) { point.Y = y * (tileHeight + sideLengthY); if (TmxMath.DoStaggerX(tmxMap, x)) { point.Y += rowHeight; } point.X = x * columnWidth; } else { point.X = x * (tileWidth + sideLengthX); if (TmxMath.DoStaggerY(tmxMap, y)) { point.X += columnWidth; } point.Y = y * rowHeight; } point.Offset(tileWidth / 2, 0); return(point); } // Default orthographic orientation return(new Point(x * tmxMap.TileWidth, y * tmxMap.TileHeight)); }
public TmxTile GetTileFromTileId(uint tileId) { if (tileId == 0) { return(null); } tileId = TmxMath.GetTileIdWithoutFlags(tileId); return(Tiles[tileId]); }
public PointF GetCombinedOffset() { PointF pointF = Offset; for (TmxLayerNode parentNode = ParentNode; parentNode != null; parentNode = parentNode.ParentNode) { pointF = TmxMath.AddPoints(pointF, parentNode.Offset); } return(pointF); }
private StringWriter BuildWavefrontStringForLayerMesh(TmxLayer layer, TmxMesh mesh, IEnumerable <int> horizontalRange, IEnumerable <int> verticalRange) { Logger.WriteVerbose("Building mesh obj file for '{0}'", mesh.UniqueMeshName); GenericListDatabase <Vertex3> vertexDatabase = new GenericListDatabase <Vertex3>(); HashIndexOf <PointF> uvDatabase = new HashIndexOf <PointF>(); StringBuilder faces = new StringBuilder(); foreach (int y in verticalRange) { foreach (int x in horizontalRange) { int tileIndex = layer.GetTileIndex(x, y); uint tileId = mesh.GetTileIdAt(tileIndex); // Skip blank tiles if (tileId == 0) { continue; } TmxTile tile = this.tmxMap.Tiles[TmxMath.GetTileIdWithoutFlags(tileId)]; // What are the vertex and texture coorindates of this face on the mesh? var position = this.tmxMap.GetMapPositionAt(x, y, tile); var vertices = CalculateFaceVertices(position, tile.TileSize); // If we're using depth shaders then we'll need to set a depth value of this face float depth_z = 0.0f; if (Tiled2Unity.Settings.DepthBufferEnabled) { depth_z = CalculateFaceDepth(position.Y + tmxMap.TileHeight, tmxMap.MapSizeInPixels.Height); } FaceVertices faceVertices = new FaceVertices { Vertices = vertices, Depth_z = depth_z }; // Is the tile being flipped or rotated (needed for texture cooridinates) bool flipDiagonal = TmxMath.IsTileFlippedDiagonally(tileId); bool flipHorizontal = TmxMath.IsTileFlippedHorizontally(tileId); bool flipVertical = TmxMath.IsTileFlippedVertically(tileId); var uvs = CalculateFaceTextureCoordinates(tile, flipDiagonal, flipHorizontal, flipVertical); // Adds vertices and uvs to the database as we build the face strings string v0 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V0) + 1, uvDatabase.Add(uvs[0]) + 1); string v1 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V1) + 1, uvDatabase.Add(uvs[1]) + 1); string v2 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V2) + 1, uvDatabase.Add(uvs[2]) + 1); string v3 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V3) + 1, uvDatabase.Add(uvs[3]) + 1); faces.AppendFormat("f {0} {1} {2} {3}\n", v0, v1, v2, v3); } } // We have all the data we need to build the wavefront file format return(CreateWavefrontWriter(mesh, vertexDatabase, uvDatabase, faces)); }
private XElement CreatePolygonColliderElement(TmxObjectPolygon tmxPolygon) { var points = from pt in TmxMath.GetPointsInMapSpace(this.tmxMap, tmxPolygon) select PointFToUnityVector(pt); XElement polygonCollider = new XElement("PolygonCollider2D", new XElement("Path", String.Join(" ", points.Select(pt => String.Format("{0},{1}", pt.X, pt.Y))))); return(polygonCollider); }
private XElement CreateEdgeColliderElement(TmxObjectPolyline tmxPolyline) { // The points need to be transformed into unity space var points = from pt in TmxMath.GetPointsInMapSpace(this.tmxMap, tmxPolyline) select PointFToUnityVector(pt); XElement edgeCollider = new XElement("EdgeCollider2D", new XElement("Points", String.Join(" ", points.Select(pt => String.Format("{0},{1}", pt.X, pt.Y))))); return(edgeCollider); }
public static List <PointF> GetPointsInMapSpace(TmxMap tmxMap, TmxHasPoints objectWithPoints) { PointF local = TmxMath.ObjectPointFToMapSpace(tmxMap, 0, 0); local.X = -local.X; local.Y = -local.Y; List <PointF> xfPoints = objectWithPoints.Points.Select(pt => TmxMath.ObjectPointFToMapSpace(tmxMap, pt)).ToList(); xfPoints = xfPoints.Select(pt => TmxMath.AddPoints(pt, local)).ToList(); return(xfPoints); }
public PointF GetCombinedOffset() { PointF offset = this.Offset; TmxLayerNode parent = this.ParentNode; while (parent != null) { offset = TmxMath.AddPoints(offset, parent.Offset); parent = parent.ParentNode; } return(offset); }
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 (Program.TexelBias > 0) { float bias = 1.0f / Program.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); }
public void BakeRotation() { PointF[] array = new PointF[1] { PointF.Empty }; TmxMath.RotatePoints(array, this); float x = Position.X - array[0].X; float y = Position.Y - array[0].Y; Position = new PointF(x, y); Position = TmxMath.Sanitize(Position); Rotation = 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)); // Transform the points with our flip flags 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); // "Tuck in" the points a tiny bit to help avoid seams // This can be turned off by setting Texel Bias to zero // Note that selecting a texel bias that is too small or a texture that is too big may affect pixel-perfect rendering (pixel snapping in shader will help) float bias = 0.0f; PointF[] tucks = new PointF[4]; if (Tiled2Unity.Settings.TexelBias > 0) { bias = 1.0f / Tiled2Unity.Settings.TexelBias; tucks[0].X += 1.0f; tucks[0].Y += 1.0f; tucks[1].X -= 1.0f; tucks[1].Y += 1.0f; tucks[2].X -= 1.0f; tucks[2].Y -= 1.0f; tucks[3].X += 1.0f; tucks[3].Y -= 1.0f; } TmxMath.TransformPoints_DiagFirst(tucks, PointF.Empty, flipDiagonal, flipHorizontal, flipVertical); PointF[] coordinates = new PointF[4]; coordinates[3] = TmxMath.AddPoints(PointToTextureCoordinate(points[0], imageSize), TmxMath.ScalePoint(tucks[0].X, -tucks[0].Y, bias)); coordinates[2] = TmxMath.AddPoints(PointToTextureCoordinate(points[1], imageSize), TmxMath.ScalePoint(tucks[1].X, -tucks[1].Y, bias)); coordinates[1] = TmxMath.AddPoints(PointToTextureCoordinate(points[2], imageSize), TmxMath.ScalePoint(tucks[2].X, -tucks[2].Y, bias)); coordinates[0] = TmxMath.AddPoints(PointToTextureCoordinate(points[3], imageSize), TmxMath.ScalePoint(tucks[3].X, -tucks[3].Y, bias)); return(coordinates); }
public static TmxObjectGroup FromXml(XElement xml, TmxLayerNode parent, TmxMap tmxMap) { TmxObjectGroup tmxObjectGroup = new TmxObjectGroup(parent, tmxMap); tmxObjectGroup.FromXmlInternal(xml); tmxObjectGroup.Color = TmxHelper.GetAttributeAsColor(xml, "color", new Color32(128, 128, 128, 255)); Logger.WriteVerbose("Parsing objects in object group '{0}'", tmxObjectGroup.Name); IEnumerable <TmxObject> source = from obj in xml.Elements("object") select TmxObject.FromXml(obj, tmxObjectGroup, tmxMap); tmxObjectGroup.Objects = (from o in source orderby TmxMath.ObjectPointFToMapSpace(tmxMap, o.Position).Y select o).ToList(); return(tmxObjectGroup); }
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); }
private void BuildCollisionLayers_ByObjectType() { // Find all tiles with collisions on them and put them into a "Collision Layer" of the same type for (int t = 0; t < this.TileIds.Length; ++t) { uint rawTileId = this.TileIds[t]; if (rawTileId == 0) { continue; } uint tileId = TmxMath.GetTileIdWithoutFlags(rawTileId); TmxTile tmxTile = this.TmxMap.Tiles[tileId]; foreach (TmxObject colliderObject in tmxTile.ObjectGroup.Objects) { if ((colliderObject is TmxHasPoints) == false) { continue; } // We have a collider object on the tile // Add the tile to the Collision Layer of the matching type // Or, create a new Collision Layer of this type to add this tile to TmxLayer collisionLayer = this.CollisionLayers.Find(l => String.Compare(l.Name, colliderObject.Type, true) == 0); if (collisionLayer == null) { // Create a new Collision Layer collisionLayer = new TmxLayer(null, this.TmxMap); this.CollisionLayers.Add(collisionLayer); // The new Collision Layer has the name of the collider object and empty tiles (they will be filled with tiles that have matching collider objects) collisionLayer.Name = colliderObject.Type; collisionLayer.TileIds = new uint[this.TileIds.Length]; // Copy over some stuff from parent layer that we need for creating collisions collisionLayer.Offset = this.Offset; collisionLayer.Width = this.Width; collisionLayer.Height = this.Height; collisionLayer.Ignore = this.Ignore; collisionLayer.Properties = this.Properties; } // Add the tile to this collision layer collisionLayer.TileIds[t] = rawTileId; } } }
public void BakeRotation() { // Rotate (0, 0) PointF[] pointfs = new PointF[1] { PointF.Empty }; TmxMath.RotatePoints(pointfs, this); // Bake that rotation into our position, sanitizing the result float x = this.Position.X - pointfs[0].X; float y = this.Position.Y - pointfs[0].Y; this.Position = new PointF(x, y); this.Position = TmxMath.Sanitize(this.Position); // Null out our rotation this.Rotation = 0; }
protected override void InternalFromXml(System.Xml.Linq.XElement xml, TmxMap tmxMap) { // Get the tile uint gid = TmxHelper.GetAttributeAsUInt(xml, "gid"); this.FlippedHorizontal = TmxMath.IsTileFlippedHorizontally(gid); this.FlippedVertical = TmxMath.IsTileFlippedVertically(gid); uint rawTileId = TmxMath.GetTileIdWithoutFlags(gid); this.Tile = tmxMap.Tiles[rawTileId]; // The tile needs to have a mesh on it. // Note: The tile may already be referenced by another TmxObjectTile instance, and as such will have its mesh data already made if (this.Tile.Meshes.Count() == 0) { this.Tile.Meshes = TmxMesh.FromTmxTile(this.Tile, tmxMap); } }
private void AddTileObjectElements(TmxObjectTile tmxTile, XElement xmlTileObject) { // We combine the properties of the tile that is referenced and add it to our own properties AssignTiledProperties(tmxTile.Tile, xmlTileObject); // Add any colliders that might be on the tile foreach (TmxObject tmxObject in tmxTile.Tile.ObjectGroup.Objects) { // All the objects/colliders in our object group need to be separate game objects because they can have unique tags/layers XElement xmlObject = new XElement("GameObject", new XAttribute("name", tmxObject.GetNonEmptyName())); // Transform object locaction into map space (needed for isometric and hex modes) PointF xfPosition = TmxMath.ObjectPointFToMapSpace(this.tmxMap, tmxObject.Position); Vector3D pos = PointFToUnityVector(xfPosition); xmlObject.SetAttributeValue("x", pos.X); xmlObject.SetAttributeValue("y", pos.Y); xmlObject.SetAttributeValue("rotation", tmxObject.Rotation); XElement objElement = null; if (tmxObject.GetType() == typeof(TmxObjectRectangle)) { // Note: Tile objects have orthographic rectangles even in isometric orientations so no need to transform rectangle points objElement = CreateBoxColliderElement(tmxObject as TmxObjectRectangle); } else if (tmxObject.GetType() == typeof(TmxObjectEllipse)) { objElement = CreateCircleColliderElement(tmxObject as TmxObjectEllipse, tmxTile.Tile.ObjectGroup.Name); } else if (tmxObject.GetType() == typeof(TmxObjectPolygon)) { objElement = CreatePolygonColliderElement(tmxObject as TmxObjectPolygon); } else if (tmxObject.GetType() == typeof(TmxObjectPolyline)) { objElement = CreateEdgeColliderElement(tmxObject as TmxObjectPolyline); } if (objElement != null) { xmlTileObject.Add(objElement); } } }
protected override void InternalFromXml(XElement xml, TmxMap tmxMap) { uint attributeAsUInt = TmxHelper.GetAttributeAsUInt(xml, "gid"); FlippedHorizontal = TmxMath.IsTileFlippedHorizontally(attributeAsUInt); FlippedVertical = TmxMath.IsTileFlippedVertically(attributeAsUInt); uint tileIdWithoutFlags = TmxMath.GetTileIdWithoutFlags(attributeAsUInt); Tile = tmxMap.Tiles[tileIdWithoutFlags]; if (Tile.Meshes.Count() == 0) { Tile.Meshes = TmxMesh.FromTmxTile(Tile, tmxMap); } ExplicitSortingLayerName = base.Properties.GetPropertyValueAsString("unity:sortingLayerName", ""); if (base.Properties.PropertyMap.ContainsKey("unity:sortingOrder")) { ExplicitSortingOrder = base.Properties.GetPropertyValueAsInt("unity:sortingOrder"); } }
private void FixTileColliderObjects(TmxMap tmxMap) { // Objects inside of tiles are colliders that will be merged with the colliders on neighboring tiles. // In order to promote this merging we have to perform the following clean up operations ... // - All rectangles objects are made into polygon objects // - All polygon objects will have their rotations burned into the polygon points (and Rotation set to zero) // - All cooridinates will be "sanitized" to make up for floating point errors due to rotation and poor placement of colliders // (The sanitation will round all numbers to the nearest 1/256th) // Replace rectangles with polygons for (int i = 0; i < this.ObjectGroup.Objects.Count; i++) { TmxObject tmxObject = this.ObjectGroup.Objects[i]; if (tmxObject is TmxObjectRectangle) { TmxObjectPolygon tmxObjectPolygon = TmxObjectPolygon.FromRectangle(tmxMap, tmxObject as TmxObjectRectangle); this.ObjectGroup.Objects[i] = tmxObjectPolygon; } } // Burn rotation into all polygon points, sanitizing the point locations as we go foreach (TmxObject tmxObject in this.ObjectGroup.Objects) { TmxHasPoints tmxHasPoints = tmxObject as TmxHasPoints; if (tmxHasPoints != null) { var pointfs = tmxHasPoints.Points.ToArray(); // Rotate our points by the rotation and position in the object TmxMath.RotatePoints(pointfs, tmxObject); // Sanitize our points to make up for floating point precision errors pointfs = pointfs.Select(TmxMath.Sanitize).ToArray(); // Set the points back into the object tmxHasPoints.Points = pointfs.ToList(); // Zero out our rotation tmxObject.BakeRotation(); } } }
public static TmxObjectGroup FromXml(XElement xml, TmxLayerNode parent, TmxMap tmxMap) { Debug.Assert(xml.Name == "objectgroup"); TmxObjectGroup tmxObjectGroup = new TmxObjectGroup(parent, tmxMap); tmxObjectGroup.FromXmlInternal(xml); // Color is specific to object group tmxObjectGroup.Color = TmxHelper.GetAttributeAsColor(xml, "color", Color.FromArgb(128, 128, 128)); // Get all the objects Logger.WriteLine("Parsing objects in object group '{0}'", tmxObjectGroup.Name); var objects = from obj in xml.Elements("object") select TmxObject.FromXml(obj, tmxObjectGroup, tmxMap); // The objects are ordered "visually" by Y position tmxObjectGroup.Objects = objects.OrderBy(o => TmxMath.ObjectPointFToMapSpace(tmxMap, o.Position).Y).ToList(); return(tmxObjectGroup); }
// 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); }