// TODO: Implement rotation! -> ok, you can rotate inside tiled... /// <summary> /// Generates Clipper's Path. As Clipper uses Integer for calculations, all point values are pre-multiplied by a factor of ClipperScale to minimize precision lost. /// </summary> /// <param name="tileX">Tile X position in the scene</param> /// <param name="tileY">Tile Y position in the scene</param> /// <param name="spriteEffects">The Tile's SpriteEffects in the TileLayer to generate its correct path if it is rotated.</param> /// <returns>List of IntPoints to be used with ClipperLib functions</returns> public List<IntPoint> GetPath(int tileX, int tileY, SpriteEffects spriteEffects, int mapTileWidth, int mapTileHeight) { List<IntPoint> path = new List<IntPoint>(); // First we copy this object's point to a list, generating Box points' if needed and approximating an ellipse List<Vector2> points = new List<Vector2>(); // For tiles higher than the tileset, we must add this differente to the points. // This only happens with ImageCollections TileSets, for normal TileSets, heightDifference == 0. float heightDifference = (TileHeight - mapTileHeight) / (float)mapTileHeight; switch (ObjectType) { case ObjectType.Box: points.Add(new Vector2(Bounds.xMin, Bounds.yMin - heightDifference)); points.Add(new Vector2(Bounds.xMax, Bounds.yMin - heightDifference)); points.Add(new Vector2(Bounds.xMax, Bounds.yMax - heightDifference)); points.Add(new Vector2(Bounds.xMin, Bounds.yMax - heightDifference)); break; case ObjectType.Ellipse: #region Approximate Ellipse // Segments per quadrant int incFactor = Mathf.FloorToInt(XUniTMXConfiguration.Instance.EllipsoideColliderApproximationFactor / 4.0f); float minIncrement = 2 * Mathf.PI / (incFactor * XUniTMXConfiguration.Instance.EllipsoideColliderApproximationFactor / 2.0f); int currentInc = 0; // grow represents if we are going right on x-axis (true) or left (false) bool grow = true; // Ellipsoide center //Vector2 center = new Vector2(Bounds.x + Bounds.width / 2.0f, heightRatio - Bounds.y - Bounds.height / 2.0f - heightDifference); Vector2 center = new Vector2(Bounds.x + Bounds.width / 2.0f, Bounds.y + Bounds.height / 2.0f - heightDifference); float r = 0; float angle = 0; for (int i = 0; i < XUniTMXConfiguration.Instance.EllipsoideColliderApproximationFactor; i++) { // Calculate radius at each point angle += currentInc * minIncrement; r = Bounds.width * Bounds.height / Mathf.Sqrt(Mathf.Pow(Bounds.height * Mathf.Cos(angle), 2) + Mathf.Pow(Bounds.width * Mathf.Sin(angle), 2)) / 2.0f; // Define the point localization using the calculated radius, angle and center points.Add(r * new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) + center); // if we are "growing", increment the angle, else, start decrementing it to close the polygon if (grow) currentInc++; else currentInc--; if (currentInc > incFactor - 1 || currentInc < 1) grow = !grow; } #endregion break; case ObjectType.Polygon: case ObjectType.Polyline: for (int i = 0; i < Points.Count; i++) { points.Add(new Vector2(Points[i].x + Bounds.x, Points[i].y + Bounds.y - heightDifference)); } break; } // Then, rotate / flip if needed Vector2 flipAnchor = Vector2.one; Vector2 rotateAnchor = new Vector2(0.5f, 0.5f); if (Rotation != 0) { for (int i = 0; i < points.Count; i++) { points[i] = points[i].RotatePoint(Bounds.x, Bounds.y, Rotation * Mathf.Deg2Rad); } } if (spriteEffects != null) { if (spriteEffects.flippedAntiDiagonally || spriteEffects.flippedHorizontally || spriteEffects.flippedVertically) { if (spriteEffects.flippedHorizontally == true && spriteEffects.flippedVertically == false && spriteEffects.flippedAntiDiagonally == false) { for (int i = 0; i < points.Count; i++) { points[i] = points[i].FlipPointHorizontally(flipAnchor); } } if (spriteEffects.flippedHorizontally == false && spriteEffects.flippedVertically == true && spriteEffects.flippedAntiDiagonally == false) { for (int i = 0; i < points.Count; i++) { points[i] = points[i].FlipPointVertically(flipAnchor); } } if (spriteEffects.flippedHorizontally == true && spriteEffects.flippedVertically == true && spriteEffects.flippedAntiDiagonally == false) { for (int i = 0; i < points.Count; i++) { points[i] = points[i].FlipPointDiagonally(flipAnchor); } } if (spriteEffects.flippedHorizontally == false && spriteEffects.flippedVertically == false && spriteEffects.flippedAntiDiagonally == true) { for (int i = 0; i < points.Count; i++) { points[i] = points[i].RotatePoint(rotateAnchor, 90 * Mathf.Deg2Rad); //points[i] = points[i].FlipPointDiagonally(flipAnchor); points[i] = points[i].FlipPointVertically(flipAnchor); } } if (spriteEffects.flippedHorizontally == true && spriteEffects.flippedVertically == false && spriteEffects.flippedAntiDiagonally == true) { for (int i = 0; i < points.Count; i++) { points[i] = points[i].RotatePoint(rotateAnchor, 90 * Mathf.Deg2Rad); points[i] = points[i].FlipPointDiagonally(flipAnchor); } } if (spriteEffects.flippedHorizontally == false && spriteEffects.flippedVertically == true && spriteEffects.flippedAntiDiagonally == true) { for (int i = 0; i < points.Count; i++) { points[i] = points[i].RotatePoint(rotateAnchor, -90 * Mathf.Deg2Rad); points[i] = points[i].FlipPointDiagonally(flipAnchor); } } if (spriteEffects.flippedHorizontally == true && spriteEffects.flippedVertically == true && spriteEffects.flippedAntiDiagonally == true) { for (int i = 0; i < points.Count; i++) { points[i] = points[i].RotatePoint(rotateAnchor, -90 * Mathf.Deg2Rad); points[i] = points[i].FlipPointVertically(flipAnchor); } } } } // Finally, position the points using tileX and tileY position, apply ClipperScale and add to the path for (int i = 0; i < points.Count; i++) { path.Add( new IntPoint( (points[i].x + tileX) * ClipperScale, (points[i].y + tileY) * ClipperScale ) ); } return path; }
private void Initialize(Map map, uint[] data, List<Material> materials) { Tiles = new TileGrid(Width, Height); BaseMap = map; BaseMaterials = materials; LayerTileSets = new List<TileSet>(); // data is left-to-right, top-to-bottom for (int x = 0; x < Width; x++) { for (int y = 0; y < Height; y++) { uint id = data[y * Width + x]; // compute the SpriteEffects to apply to this tile SpriteEffects spriteEffects = new SpriteEffects(); // MARIO: new method to verify flipped tiles spriteEffects.flippedHorizontally = (id & FlippedHorizontallyFlag) == FlippedHorizontallyFlag; spriteEffects.flippedVertically = (id & FlippedVerticallyFlag) == FlippedVerticallyFlag; spriteEffects.flippedAntiDiagonally = (id & FlippedAntiDiagonallyFlag) == FlippedAntiDiagonallyFlag; // MARIO: new strip out the flip flags to get the real ID // Fixed for AntiDiagonallyFlgs id &= ~(FlippedHorizontallyFlag | FlippedVerticallyFlag | FlippedAntiDiagonallyFlag); // get the tile Tile t = null; BaseMap.Tiles.TryGetValue((int)id, out t); // if the tile is non-null... if (t != null) { // if we want unique instances, clone it if (MakeUniqueTiles) { t = t.Clone(); t.SpriteEffects = spriteEffects; } // otherwise we may need to clone if the tile doesn't have the correct effects // in this world a flipped tile is different than a non-flipped one; just because // they have the same source rect doesn't mean they're equal. else if (t.SpriteEffects != spriteEffects) { t = t.Clone(); t.SpriteEffects = spriteEffects; } // Add this Tile's TileSet to LayerTileSets list, if it is not there yet if (!LayerTileSets.Contains(t.TileSet)) LayerTileSets.Add(t.TileSet); } // put that tile in our grid Tiles[x, y] = t; } } GenerateLayer(); }