Example #1
0
        private static void AddBorderCollisionEdges(TileEdgeMap targetEdgeMap, Point2 edgeMapPos, Point2 totalSize)
        {
            int rightBorderPos  = totalSize.X - edgeMapPos.X;
            int bottomBorderPos = totalSize.Y - edgeMapPos.Y;

            // Top border
            if (edgeMapPos.Y == 0)
            {
                for (int x = 1; x < Math.Min(targetEdgeMap.Width, rightBorderPos + 1); x++)
                {
                    targetEdgeMap.AddEdge(new Point2(x - 1, 0), new Point2(x, 0));
                }
            }
            // Bottom border
            if (bottomBorderPos < targetEdgeMap.Height)
            {
                for (int x = 1; x < Math.Min(targetEdgeMap.Width, rightBorderPos + 1); x++)
                {
                    targetEdgeMap.AddEdge(new Point2(x - 1, bottomBorderPos), new Point2(x, bottomBorderPos));
                }
            }

            // Left border
            if (edgeMapPos.X == 0)
            {
                for (int y = 1; y < Math.Min(targetEdgeMap.Height, bottomBorderPos + 1); y++)
                {
                    targetEdgeMap.AddEdge(new Point2(0, y - 1), new Point2(0, y));
                }
            }
            // Right border
            if (rightBorderPos < targetEdgeMap.Width)
            {
                for (int y = 1; y < Math.Min(targetEdgeMap.Height, bottomBorderPos + 1); y++)
                {
                    targetEdgeMap.AddEdge(new Point2(rightBorderPos, y - 1), new Point2(rightBorderPos, y));
                }
            }
        }
Example #2
0
        private static void AddFenceCollisionEdges(Grid <TileCollisionShape> collisionData, TileEdgeMap targetEdgeMap)
        {
            // Populate the edge map with all the collision fences
            for (int y = 0; y < SectorSize; y++)
            {
                for (int x = 0; x < SectorSize; x++)
                {
                    TileCollisionShape collision = collisionData[x, y];

                    // Skip both free and completely solid tiles
                    if (collision == TileCollisionShape.Free)
                    {
                        continue;
                    }
                    if ((collision & TileCollisionShape.Solid) == TileCollisionShape.Solid)
                    {
                        continue;
                    }

                    // Add the various fence collision types
                    if ((collision & TileCollisionShape.Top) != TileCollisionShape.Free)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y), new Point2(x + 1, y));
                    }
                    if ((collision & TileCollisionShape.Bottom) != TileCollisionShape.Free)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y + 1), new Point2(x + 1, y + 1));
                    }
                    if ((collision & TileCollisionShape.Left) != TileCollisionShape.Free)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y), new Point2(x, y + 1));
                    }
                    if ((collision & TileCollisionShape.Right) != TileCollisionShape.Free)
                    {
                        targetEdgeMap.AddEdge(new Point2(x + 1, y), new Point2(x + 1, y + 1));
                    }
                    if ((collision & TileCollisionShape.DiagonalDown) != TileCollisionShape.Free)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y), new Point2(x + 1, y + 1));
                    }
                    if ((collision & TileCollisionShape.DiagonalUp) != TileCollisionShape.Free)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y + 1), new Point2(x + 1, y));
                    }
                }
            }
        }
Example #3
0
        private static void AddBlockCollisionEdges(Grid <TileCollisionShape> collisionData, TileEdgeMap targetEdgeMap, Point2 edgeMapPos, Point2 totalSize)
        {
            int leftBorderPos   = 0 - edgeMapPos.X;
            int rightBorderPos  = totalSize.X - edgeMapPos.X;
            int topBorderPos    = 0 - edgeMapPos.Y;
            int bottomBorderPos = totalSize.Y - edgeMapPos.Y;

            // Add block geometry to the specified edge map
            for (int y = 0; y < SectorSize; y++)
            {
                for (int x = 0; x < SectorSize; x++)
                {
                    // Skip non-solid blocks
                    bool center = (collisionData[x, y] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    if (!center)
                    {
                        continue;
                    }

                    // A filled block will always overwrite its inner diagonal edges
                    targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x + 1, y + 1));
                    targetEdgeMap.RemoveEdge(new Point2(x, y + 1), new Point2(x + 1, y));

                    // Determine block collision neighbourhood
                    bool left   = (x == 0)              ? (x == leftBorderPos) : (collisionData[x - 1, y] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool right  = (x == SectorSize - 1) ? (x == rightBorderPos) : (collisionData[x + 1, y] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool top    = (y == 0)              ? (y == topBorderPos) : (collisionData[x, y - 1] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool bottom = (y == SectorSize - 1) ? (y == bottomBorderPos) : (collisionData[x, y + 1] & TileCollisionShape.Solid) == TileCollisionShape.Solid;

                    // Adjust outer edge states
                    if (center != left)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y), new Point2(x, y + 1));
                    }
                    else
                    {
                        targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x, y + 1));
                    }
                    if (center != right)
                    {
                        targetEdgeMap.AddEdge(new Point2(x + 1, y), new Point2(x + 1, y + 1));
                    }
                    else
                    {
                        targetEdgeMap.RemoveEdge(new Point2(x + 1, y), new Point2(x + 1, y + 1));
                    }
                    if (center != top)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y), new Point2(x + 1, y));
                    }
                    else
                    {
                        targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x + 1, y));
                    }
                    if (center != bottom)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y + 1), new Point2(x + 1, y + 1));
                    }
                    else
                    {
                        targetEdgeMap.RemoveEdge(new Point2(x, y + 1), new Point2(x + 1, y + 1));
                    }
                }
            }

            // Detect diagonal fences next to solid blocks and remove the
            // edges that might have become redundant. This can't be done
            // in the above loop without complicating control flow, so it's
            // done here.
            for (int y = 0; y < SectorSize; y++)
            {
                for (int x = 0; x < SectorSize; x++)
                {
                    TileCollisionShape centerShape = collisionData[x, y];
                    bool diagonalDown = (centerShape & TileCollisionShape.DiagonalDown) == TileCollisionShape.DiagonalDown;
                    bool diagonalUp   = (centerShape & TileCollisionShape.DiagonalUp) == TileCollisionShape.DiagonalUp;

                    // Skip tiles that aren't diagonal fences
                    if (!diagonalDown && !diagonalUp)
                    {
                        continue;
                    }

                    // Determine block collision neighbourhood
                    bool left   = (x == 0)              ? (x == leftBorderPos) : (collisionData[x - 1, y] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool right  = (x == SectorSize - 1) ? (x == rightBorderPos) : (collisionData[x + 1, y] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool top    = (y == 0)              ? (y == topBorderPos) : (collisionData[x, y - 1] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool bottom = (y == SectorSize - 1) ? (y == bottomBorderPos) : (collisionData[x, y + 1] & TileCollisionShape.Solid) == TileCollisionShape.Solid;

                    // Remove perpendicular edges that are redundant because of the diagonal fence
                    // connecting two adjacent solid blocks.
                    if (diagonalDown)
                    {
                        if (top && right)
                        {
                            targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x + 1, y));
                            targetEdgeMap.RemoveEdge(new Point2(x + 1, y), new Point2(x + 1, y + 1));
                        }
                        if (bottom && left)
                        {
                            targetEdgeMap.RemoveEdge(new Point2(x, y + 1), new Point2(x + 1, y + 1));
                            targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x, y + 1));
                        }
                    }
                    else
                    {
                        if (top && left)
                        {
                            targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x + 1, y));
                            targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x, y + 1));
                        }
                        if (bottom && right)
                        {
                            targetEdgeMap.RemoveEdge(new Point2(x, y + 1), new Point2(x + 1, y + 1));
                            targetEdgeMap.RemoveEdge(new Point2(x + 1, y), new Point2(x + 1, y + 1));
                        }
                    }
                }
            }
        }
        private static void GetTileAreaOutlines(IReadOnlyGrid<bool> tileArea, Vector2 tileSize, ref List<Vector2[]> outlines)
        {
            // Initialize the container we'll put our outlines into
            if (outlines == null)
                outlines = new List<Vector2[]>();
            else
                outlines.Clear();

            // Generate a data structure containing all visible edges
            TileEdgeMap edgeMap = new TileEdgeMap(tileArea.Width + 1, tileArea.Height + 1);
            for (int y = 0; y < edgeMap.Height; y++)
            {
                for (int x = 0; x < edgeMap.Width; x++)
                {
                    // Determine highlight state of the four tiles around this node
                    bool topLeft     = x > 0              && y > 0               && tileArea[x - 1, y - 1];
                    bool topRight    = x < tileArea.Width && y > 0               && tileArea[x    , y - 1];
                    bool bottomLeft  = x > 0              && y < tileArea.Height && tileArea[x - 1, y    ];
                    bool bottomRight = x < tileArea.Width && y < tileArea.Height && tileArea[x    , y    ];

                    // Determine which edges are visible
                    if (topLeft     != topRight   ) edgeMap.AddEdge(new Point2(x, y), new Point2(x    , y - 1));
                    if (topRight    != bottomRight) edgeMap.AddEdge(new Point2(x, y), new Point2(x + 1, y    ));
                    if (bottomRight != bottomLeft ) edgeMap.AddEdge(new Point2(x, y), new Point2(x    , y + 1));
                    if (bottomLeft  != topLeft    ) edgeMap.AddEdge(new Point2(x, y), new Point2(x - 1, y    ));
                }
            }

            // Traverse edges to form outlines until no more edges are left
            RawList<Vector2> outlineBuilder = new RawList<Vector2>();
            while (true)
            {
                // Find the beginning of an outline
                Point2 current = edgeMap.FindNonEmpty();
                if (current.X == -1 || current.Y == -1) break;

                // Traverse it until no more edges are left
                while (true)
                {
                    Point2 next = edgeMap.GetClockwiseNextFrom(current);
                    if (next.X == -1 || next.Y == -1) break;

                    outlineBuilder.Add(next * tileSize);
                    edgeMap.RemoveEdge(current, next);
                    current = next;
                }

                // Close the loop by adding the first element again
                if (outlineBuilder.Count > 0)
                    outlineBuilder.Add(outlineBuilder[0]);

                // If we have enough vertices, keep the outline for drawing
                Vector2[] outline = new Vector2[outlineBuilder.Count];
                outlineBuilder.CopyTo(outline, 0);
                outlines.Add(outline);

                // Reset the outline builder to an empty state
                outlineBuilder.Clear();
            }
        }
Example #5
0
        private static void AddFenceCollisionEdges(Grid<TileCollisionShape> collisionData, TileEdgeMap targetEdgeMap)
        {
            // Populate the edge map with all the collision fences
            for (int y = 0; y < SectorSize; y++)
            {
                for (int x = 0; x < SectorSize; x++)
                {
                    TileCollisionShape collision = collisionData[x, y];

                    // Skip both free and completely solid tiles
                    if (collision == TileCollisionShape.Free)
                        continue;
                    if ((collision & TileCollisionShape.Solid) == TileCollisionShape.Solid)
                        continue;

                    // Add the various fence collision types
                    if ((collision & TileCollisionShape.Top) != TileCollisionShape.Free)
                        targetEdgeMap.AddEdge(new Point2(x, y), new Point2(x + 1, y));
                    if ((collision & TileCollisionShape.Bottom) != TileCollisionShape.Free)
                        targetEdgeMap.AddEdge(new Point2(x, y + 1), new Point2(x + 1, y + 1));
                    if ((collision & TileCollisionShape.Left) != TileCollisionShape.Free)
                        targetEdgeMap.AddEdge(new Point2(x, y), new Point2(x, y + 1));
                    if ((collision & TileCollisionShape.Right) != TileCollisionShape.Free)
                        targetEdgeMap.AddEdge(new Point2(x + 1, y), new Point2(x + 1, y + 1));
                    if ((collision & TileCollisionShape.DiagonalDown) != TileCollisionShape.Free)
                        targetEdgeMap.AddEdge(new Point2(x, y), new Point2(x + 1, y + 1));
                    if ((collision & TileCollisionShape.DiagonalUp) != TileCollisionShape.Free)
                        targetEdgeMap.AddEdge(new Point2(x, y + 1), new Point2(x + 1, y));
                }
            }
        }
Example #6
0
        private static void AddBorderCollisionEdges(TileEdgeMap targetEdgeMap, Point2 edgeMapPos, Point2 totalSize)
        {
            int rightBorderPos = totalSize.X - edgeMapPos.X;
            int bottomBorderPos = totalSize.Y - edgeMapPos.Y;

            // Top border
            if (edgeMapPos.Y == 0)
            {
                for (int x = 1; x < Math.Min(targetEdgeMap.Width, rightBorderPos + 1); x++)
                    targetEdgeMap.AddEdge(new Point2(x - 1, 0), new Point2(x, 0));
            }
            // Bottom border
            if (bottomBorderPos < targetEdgeMap.Height)
            {
                for (int x = 1; x < Math.Min(targetEdgeMap.Width, rightBorderPos + 1); x++)
                    targetEdgeMap.AddEdge(new Point2(x - 1, bottomBorderPos), new Point2(x, bottomBorderPos));
            }

            // Left border
            if (edgeMapPos.X == 0)
            {
                for (int y = 1; y < Math.Min(targetEdgeMap.Height, bottomBorderPos + 1); y++)
                    targetEdgeMap.AddEdge(new Point2(0, y - 1), new Point2(0, y));
            }
            // Right border
            if (rightBorderPos < targetEdgeMap.Width)
            {
                for (int y = 1; y < Math.Min(targetEdgeMap.Height, bottomBorderPos + 1); y++)
                    targetEdgeMap.AddEdge(new Point2(rightBorderPos, y - 1), new Point2(rightBorderPos, y));
            }
        }
Example #7
0
        private static void AddBlockCollisionEdges(Grid<TileCollisionShape> collisionData, TileEdgeMap targetEdgeMap, Point2 edgeMapPos, Point2 totalSize)
        {
            int leftBorderPos = 0 - edgeMapPos.X;
            int rightBorderPos = totalSize.X - edgeMapPos.X;
            int topBorderPos = 0 - edgeMapPos.Y;
            int bottomBorderPos = totalSize.Y - edgeMapPos.Y;

            // Add block geometry to the specified edge map
            for (int y = 0; y < SectorSize; y++)
            {
                for (int x = 0; x < SectorSize; x++)
                {
                    // Skip non-solid blocks
                    bool center = (collisionData[x, y] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    if (!center) continue;

                    // A filled block will always overwrite its inner diagonal edges
                    targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x + 1, y + 1));
                    targetEdgeMap.RemoveEdge(new Point2(x, y + 1), new Point2(x + 1, y));

                    // Determine block collision neighbourhood
                    bool left   = (x == 0)              ? (x == leftBorderPos  ) : (collisionData[x - 1, y] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool right  = (x == SectorSize - 1) ? (x == rightBorderPos ) : (collisionData[x + 1, y] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool top    = (y == 0)              ? (y == topBorderPos   ) : (collisionData[x, y - 1] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool bottom = (y == SectorSize - 1) ? (y == bottomBorderPos) : (collisionData[x, y + 1] & TileCollisionShape.Solid) == TileCollisionShape.Solid;

                    // Adjust outer edge states
                    if (center != left )  targetEdgeMap.AddEdge   (new Point2(x, y), new Point2(x, y + 1));
                    else                  targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x, y + 1));
                    if (center != right)  targetEdgeMap.AddEdge   (new Point2(x + 1, y), new Point2(x + 1, y + 1));
                    else                  targetEdgeMap.RemoveEdge(new Point2(x + 1, y), new Point2(x + 1, y + 1));
                    if (center != top)    targetEdgeMap.AddEdge   (new Point2(x, y), new Point2(x + 1, y));
                    else                  targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x + 1, y));
                    if (center != bottom) targetEdgeMap.AddEdge   (new Point2(x, y + 1), new Point2(x + 1, y + 1));
                    else                  targetEdgeMap.RemoveEdge(new Point2(x, y + 1), new Point2(x + 1, y + 1));
                }
            }

            // Detect diagonal fences next to solid blocks and remove the
            // edges that might have become redundant. This can't be done
            // in the above loop without complicating control flow, so it's
            // done here.
            for (int y = 0; y < SectorSize; y++)
            {
                for (int x = 0; x < SectorSize; x++)
                {
                    TileCollisionShape centerShape = collisionData[x, y];
                    bool diagonalDown = (centerShape & TileCollisionShape.DiagonalDown) == TileCollisionShape.DiagonalDown;
                    bool diagonalUp = (centerShape & TileCollisionShape.DiagonalUp) == TileCollisionShape.DiagonalUp;

                    // Skip tiles that aren't diagonal fences
                    if (!diagonalDown && !diagonalUp) continue;

                    // Determine block collision neighbourhood
                    bool left   = (x == 0)              ? (x == leftBorderPos  ) : (collisionData[x - 1, y] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool right  = (x == SectorSize - 1) ? (x == rightBorderPos ) : (collisionData[x + 1, y] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool top    = (y == 0)              ? (y == topBorderPos   ) : (collisionData[x, y - 1] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool bottom = (y == SectorSize - 1) ? (y == bottomBorderPos) : (collisionData[x, y + 1] & TileCollisionShape.Solid) == TileCollisionShape.Solid;

                    // Remove perpendicular edges that are redundant because of the diagonal fence
                    // connecting two adjacent solid blocks.
                    if (diagonalDown)
                    {
                        if (top && right)
                        {
                            targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x + 1, y));
                            targetEdgeMap.RemoveEdge(new Point2(x + 1, y), new Point2(x + 1, y + 1));
                        }
                        if (bottom && left)
                        {
                            targetEdgeMap.RemoveEdge(new Point2(x, y + 1), new Point2(x + 1, y + 1));
                            targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x, y + 1));
                        }
                    }
                    else
                    {
                        if (top && left)
                        {
                            targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x + 1, y));
                            targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x, y + 1));
                        }
                        if (bottom && right)
                        {
                            targetEdgeMap.RemoveEdge(new Point2(x, y + 1), new Point2(x + 1, y + 1));
                            targetEdgeMap.RemoveEdge(new Point2(x + 1, y), new Point2(x + 1, y + 1));
                        }
                    }
                }
            }
        }