/// <summary>
            /// returns the 2 corners adjacent to the input edge
            /// </summary>
            /// ![green = input edge , blue = result](GetCorners_AdjacentToEdge.png)
            public static List <Vector3Int> OfEdge(Vector3Int edge)
            {
                List <Vector3Int> corners     = new List <Vector3Int>();
                EdgeAlignment     orientation = HexUtility.GetEdgeAlignment(edge);

                int x = edge.x * 3;
                int y = edge.y * 3;
                int z = edge.z * 3;

                if (orientation == EdgeAlignment.ParallelToCubeX)
                {
                    Vector3Int topLeft     = new Vector3Int((x - 2) / 2, (y + 1) / 2, (z + 1) / 2);
                    Vector3Int bottomRight = new Vector3Int((x + 2) / 2, (y - 1) / 2, (z - 1) / 2);
                    corners.Add(topLeft);
                    corners.Add(bottomRight);
                }

                if (orientation == EdgeAlignment.ParallelToCubeY)
                {
                    Vector3Int top    = new Vector3Int((x - 1) / 2, (y + 2) / 2, (z - 1) / 2);
                    Vector3Int bottom = new Vector3Int((x + 1) / 2, (y - 2) / 2, (z + 1) / 2);
                    corners.Add(top);
                    corners.Add(bottom);
                }

                if (orientation == EdgeAlignment.ParallelToCubeZ)
                {
                    Vector3Int topRight   = new Vector3Int((x + 1) / 2, (y + 1) / 2, (z - 2) / 2);
                    Vector3Int bottomLeft = new Vector3Int((x - 1) / 2, (y - 1) / 2, (z + 2) / 2);
                    corners.Add(topRight);
                    corners.Add(bottomLeft);
                }
                return(corners);
            }
Example #2
0
            /// <summary>
            /// returns tiles forming a line between origin and target tile, optionally including the origin tile itself
            /// </summary>
            /// TODO: explain nudge
            /// ![yellow = origin , blue = target, yellow/blue = line, when includeOrigin = true the origin belongs is part of the line](GetTiles_Line.png)
            public static List <Vector3Int> Line(Vector3Int origin, Vector3Int target, bool includeOrigin, float horizontalNudgeFromOriginCenter = NudgePositive)
            {
                if (origin == target)
                {
                    throw new System.ArgumentException("origin corner and target corner are the same - can't create a Path");
                }


                List <Vector3Int> lineCells = new List <Vector3Int>();

                if (includeOrigin)
                {
                    lineCells.Add(origin);
                }

                int dist = GetDistance.BetweenTiles(origin, target);

                for (int i = 1; i <= dist; i++)
                {
                    Vector3    lerped = HexUtility.LerpCubeCoordinates(origin, target, horizontalNudgeFromOriginCenter, (1f / dist) * i);
                    Vector3Int cell   = HexUtility.RoundCubeCoordinate(lerped);
                    lineCells.Add(cell);
                }
                return(lineCells);
            }
        /// <summary>
        /// wraps edge coordinates and then removes all which are out of map bounds
        /// </summary>
        protected List <Vector3Int> GetValidEdgeCoordinates(List <Vector3Int> rawPositions)
        {
            List <Vector3Int> positions = rawPositions;

            if (coordinateWrapper != null)
            {
                positions = coordinateWrapper.WrapEdgeCoordinates(positions);
            }
            positions = HexUtility.RemoveInvalidCoordinates(positions, EdgeIndexByPosition);
            return(positions);
        }
            /// <summary>
            /// returns the edge-distance of the 2 inpute edges
            /// </summary>
            public static int BetweenEdges(Vector3Int edgeA, Vector3Int edgeB)
            {
                if (edgeA == edgeB)
                {
                    return(0);
                }

                int DeltaX   = Mathf.Abs(edgeA.x - edgeB.x);
                int DeltaY   = Mathf.Abs(edgeA.y - edgeB.y);
                int DeltaZ   = Mathf.Abs(edgeA.z - edgeB.z);
                int distance = Mathf.Max(DeltaX, DeltaY, DeltaZ);

                if ((HexUtility.GetEdgeAlignment(edgeA) == EdgeAlignment.ParallelToCubeX && edgeA.x == edgeB.x) ||
                    (HexUtility.GetEdgeAlignment(edgeA) == EdgeAlignment.ParallelToCubeY && edgeA.y == edgeB.y) ||
                    (HexUtility.GetEdgeAlignment(edgeA) == EdgeAlignment.ParallelToCubeZ && edgeA.z == edgeB.z))
                {
                    distance += 1;
                }
                return(distance);
            }
            /// <summary>
            /// returns the 4 edges which are adjacent to an edge
            /// </summary>
            /// ![green = input edge , blue = result](GetEdges_AdjacentToEdge.png)
            public static List <Vector3Int> AdjacentToEdge(Vector3Int edge)
            {
                List <Vector3Int> edgeCoords   = new List <Vector3Int>();
                EdgeAlignment     orientiation = HexUtility.GetEdgeAlignment(edge);

                if (orientiation == EdgeAlignment.ParallelToCubeY)
                {
                    Vector3Int topRightEdge    = edge + new Vector3Int(0, +1, -1);
                    Vector3Int bottomRightEdge = edge + new Vector3Int(+1, -1, 0);
                    Vector3Int bottomLeftEdge  = edge + new Vector3Int(0, -1, +1);
                    Vector3Int topLeftEdge     = edge + new Vector3Int(-1, +1, 0);
                    edgeCoords.Add(topRightEdge);
                    edgeCoords.Add(bottomRightEdge);
                    edgeCoords.Add(bottomLeftEdge);
                    edgeCoords.Add(topLeftEdge);
                }
                else if (orientiation == EdgeAlignment.ParallelToCubeX)
                {
                    Vector3Int rightEdge  = edge + new Vector3Int(+1, 0, -1);
                    Vector3Int bottomEdge = edge + new Vector3Int(+1, -1, 0);
                    Vector3Int leftEdge   = edge + new Vector3Int(-1, 0, +1);
                    Vector3Int topEdge    = edge + new Vector3Int(-1, +1, 0);
                    edgeCoords.Add(rightEdge);
                    edgeCoords.Add(bottomEdge);
                    edgeCoords.Add(leftEdge);
                    edgeCoords.Add(topEdge);
                }
                else if (orientiation == EdgeAlignment.ParallelToCubeZ)
                {
                    Vector3Int rightEdge  = edge + new Vector3Int(+1, 0, -1);
                    Vector3Int bottomEdge = edge + new Vector3Int(0, -1, +1);
                    Vector3Int leftEdge   = edge + new Vector3Int(-1, 0, +1);
                    Vector3Int topEdge    = edge + new Vector3Int(0, +1, -1);
                    edgeCoords.Add(rightEdge);
                    edgeCoords.Add(bottomEdge);
                    edgeCoords.Add(leftEdge);
                    edgeCoords.Add(topEdge);
                }
                return(edgeCoords);
            }
Example #6
0
        public HexMap(Dictionary <Vector3Int, int> tileIndexByPosition, CoordinateWrapper coordinateWrapper = null)
        {
            this.CoordinateWrapper   = coordinateWrapper;
            this.TileIndexByPosition = tileIndexByPosition;
            TilePositions            = new Vector3Int[TileCount];
            foreach (var kvp in TileIndexByPosition)
            {
                TilePositions[kvp.Value] = kvp.Key;
            }
            this.GetTilePosition  = new TilePositionProvider(coordinateWrapper, tileIndexByPosition);
            this.GetTilePositions = new TilePositionsProvider(coordinateWrapper, tileIndexByPosition);

            MapSizeData = HexUtility.CalculateMapCenterAndExtents(TileIndexByPosition.Keys);


            CreateEdgeIndex();
            this.GetEdgePosition  = new EdgePositionProvider(CoordinateWrapper, EdgeIndexByPosition);
            this.GetEdgePositions = new EdgePositionsProvider(CoordinateWrapper, EdgeIndexByPosition);

            CreateCornerIndex();
            this.GetCornerPosition  = new CornerPositionProvider(CoordinateWrapper, CornerIndexByPosition);
            this.GetCornerPositions = new CornersPositionsProvider(CoordinateWrapper, CornerIndexByPosition);
        }
            /// <summary>
            /// returns the 3 corners adjacent to the input corner
            /// </summary>
            /// ![green = input corner , blue = result](GetCorners_AdjacentToCorner.png)
            public static List <Vector3Int> AdjacentToCorner(Vector3Int corner)
            {
                Vector3Int a, b, c;
                CornerType cornerType = HexUtility.GetCornerType(corner);

                //its the same approach like getting adjacent tiles but inverted (and without dividing by 3)
                if (cornerType == CornerType.BottomOfYParallelEdge)
                {
                    a = new Vector3Int((corner.x - 1), (corner.y + 2), (corner.z - 1));
                    b = new Vector3Int((corner.x + 2), (corner.y - 1), (corner.z - 1));
                    c = new Vector3Int((corner.x - 1), (corner.y - 1), (corner.z + 2));
                }

                else
                {
                    a = new Vector3Int((corner.x + 1), (corner.y + 1), (corner.z - 2));
                    b = new Vector3Int((corner.x + 1), (corner.y - 2), (corner.z + 1));
                    c = new Vector3Int((corner.x - 2), (corner.y + 1), (corner.z + 1));
                }
                return(new List <Vector3Int> {
                    a, b, c
                });
            }
        /// <summary>
        /// returns an list of each contiguous border path of the input Tile Coordinates. Each individual path is ordered in clockwise direction with an arbitrary starting point. The different Paths are returned in an arbitrary order
        /// </summary>
        /// ![green = input tiles , blue = result](Map_GetEdges_BorderPaths.png)
        public List <List <Vector3Int> > BorderPaths(IEnumerable <Vector3Int> tiles, out List <List <EdgeDirection> > pathDirections)
        {
            if (coordinateWrapper == null)
            {
                return(HexGrid.GetEdges.BorderPaths(tiles, out pathDirections));
            }

            pathDirections = new List <List <EdgeDirection> >();
            List <List <Vector3Int> > borderPaths    = new List <List <Vector3Int> >();
            List <Vector3Int>         edgesUnordered = TileBorders(tiles);
            HashSet <Vector3Int>      unusedEdges    = new HashSet <Vector3Int>(edgesUnordered); //we remove every edge which we used from this collection to find out which are still left after we finished a path

            //we do it as long as we didn't use all edges because that means we didn't get all paths yet.
            while (unusedEdges.Count > 0)
            {
                List <Vector3Int>    borderPath      = new List <Vector3Int>();
                List <EdgeDirection> borderDirection = new List <EdgeDirection>();
                Vector3Int           topRightEdge    = new Vector3Int();

                //can we just use any edge instead? -> nah we want to ensure it being clockwise...

                int maxYsoFar       = int.MinValue;
                int maxXOfmaxYsoFar = int.MinValue;
                //now we pick one of the top most edges which is parallel to the X-axis of our cube
                foreach (Vector3Int edge in unusedEdges)
                {
                    EdgeAlignment orientation = HexUtility.GetEdgeAlignment(edge);
                    if (orientation != EdgeAlignment.ParallelToCubeX)
                    {
                        continue;
                    }
                    if (edge.y > maxYsoFar)
                    {
                        topRightEdge    = edge;
                        maxXOfmaxYsoFar = edge.x;
                        maxYsoFar       = edge.y;
                    }
                    else if (edge.y == maxYsoFar && edge.x > maxXOfmaxYsoFar)
                    {
                        topRightEdge    = edge;
                        maxXOfmaxYsoFar = edge.x;
                        maxYsoFar       = edge.y;
                    }
                }

                Vector3Int    currentEdge      = topRightEdge;
                EdgeDirection currentDirection = EdgeDirection.BottomRight;
                bool          targetReached    = false;
                int           safety           = 0;

                while (!targetReached)
                {
                    safety++;
                    if (safety > 250)
                    {
                        Debug.Log("safety reached!!! Error in while loop, preventing going infinite");
                        break;
                    }
                    borderPath.Add(currentEdge);
                    borderDirection.Add(currentDirection);
                    unusedEdges.Remove(currentEdge);

                    Vector3Int offsetClockwise                    = HexGrid.ClockWiseNeighbourOfEdgeByEdgeDirection[(int)currentDirection];
                    Vector3Int offsetCounterClockwise             = HexGrid.CounterClockWiseNeighbourOfEdgeByEdgeDirection[(int)currentDirection];
                    Vector3Int potentialClockwiseNeighbour        = coordinateWrapper.WrapEdgeCoordinate(currentEdge + offsetClockwise);
                    Vector3Int potentialCounterClockwiseNeighbour = coordinateWrapper.WrapEdgeCoordinate(currentEdge + offsetCounterClockwise);

                    if (unusedEdges.Contains(potentialCounterClockwiseNeighbour))
                    {
                        currentEdge      = potentialCounterClockwiseNeighbour;
                        currentDirection = (EdgeDirection)((int)(currentDirection + 5) % 6);
                    }
                    else if (unusedEdges.Contains(potentialClockwiseNeighbour))
                    {
                        currentEdge      = potentialClockwiseNeighbour;
                        currentDirection = (EdgeDirection)((int)(currentDirection + 1) % 6);
                    }
                    else //we didn't found any unused edge so we must be at end (change to flag I guess and replace do while with normal while
                    {
                        targetReached = true;
                    }
                }

                borderPaths.Add(borderPath);
                pathDirections.Add(borderDirection);
            }

            for (int i = 1; i < borderPaths.Count; i++)
            {
                borderPaths[i].Reverse();
                pathDirections[i].Reverse();
                for (int j = 0; j < pathDirections[i].Count; j++)
                {
                    pathDirections[i][j] = (EdgeDirection)(((int)pathDirections[i][j] + 3) % 6);
                }
            }
            return(borderPaths);
        }
Example #9
0
 /// <summary>
 /// Initializes a new Edge instance
 /// </summary>>
 public Edge(Vector3Int position, int index, Vector2 normalizedPosition) : base(position, index, normalizedPosition)
 {
     EdgeAlignment = HexUtility.GetEdgeAlignment(position);
 }
            /// <summary>
            /// returns all the border paths of one contiguous Area. Outer path is clockwise, others are counterclockwise
            /// </summary>
            /// ![green = input tiles , blue = result](GetEdges_BorderPaths.png)
            public static List <List <Vector3Int> > BorderPaths(IEnumerable <Vector3Int> tiles, out List <List <EdgeDirection> > pathDirections)
            {
                pathDirections = new List <List <EdgeDirection> >();
                List <List <Vector3Int> > borderPaths    = new List <List <Vector3Int> >();
                List <Vector3Int>         edgesUnordered = TileBorders(tiles);
                HashSet <Vector3Int>      unusedEdges    = new HashSet <Vector3Int>(edgesUnordered); //we remove every edge which we used from this collection to find out which are still left after we finished a path

                //we do it as long as we didn't use all edges because that means we didn't get all paths yet.
                while (unusedEdges.Count > 0)
                {
                    List <Vector3Int>    borderPath      = new List <Vector3Int>();
                    List <EdgeDirection> borderDirection = new List <EdgeDirection>();
                    Vector3Int           topRightEdge    = new Vector3Int();

                    //can we just use any edge instead? -> nah we want to ensure it being clockwise...

                    int maxYsoFar       = int.MinValue;
                    int maxXOfmaxYsoFar = int.MinValue;
                    //now we pick one of the top most edges which is parallel to the X-axis of our cube
                    foreach (Vector3Int edge in unusedEdges)
                    {
                        EdgeAlignment orientation = HexUtility.GetEdgeAlignment(edge);
                        if (orientation != EdgeAlignment.ParallelToCubeX)
                        {
                            continue;
                        }
                        if (edge.y > maxYsoFar)
                        {
                            topRightEdge    = edge;
                            maxXOfmaxYsoFar = edge.x;
                            maxYsoFar       = edge.y;
                        }
                        else if (edge.y == maxYsoFar && edge.x > maxXOfmaxYsoFar)
                        {
                            topRightEdge    = edge;
                            maxXOfmaxYsoFar = edge.x;
                            maxYsoFar       = edge.y;
                        }
                    }

                    Vector3Int    currentEdge      = topRightEdge;
                    EdgeDirection currentDirection = EdgeDirection.BottomRight;
                    bool          targetReached    = false;

                    while (!targetReached)
                    {
                        borderPath.Add(currentEdge);
                        borderDirection.Add(currentDirection);
                        unusedEdges.Remove(currentEdge);

                        Vector3Int offsetClockwise        = ClockWiseNeighbourOfEdgeByEdgeDirection[(int)currentDirection];
                        Vector3Int offsetCounterClockwise = CounterClockWiseNeighbourOfEdgeByEdgeDirection[(int)currentDirection];

                        if (unusedEdges.Contains(currentEdge + offsetCounterClockwise))
                        {
                            currentEdge      = currentEdge + offsetCounterClockwise;
                            currentDirection = (EdgeDirection)((int)(currentDirection + 5) % 6);
                        }
                        else if (unusedEdges.Contains(currentEdge + offsetClockwise))
                        {
                            currentEdge      = currentEdge + offsetClockwise;
                            currentDirection = (EdgeDirection)((int)(currentDirection + 1) % 6);
                        }
                        else //we didn't find any unused edge so we must be at end
                        {
                            targetReached = true;
                        }
                    }

                    borderPaths.Add(borderPath);
                    pathDirections.Add(borderDirection);
                }

                for (int i = 1; i < borderPaths.Count; i++)
                {
                    borderPaths[i].Reverse();
                    pathDirections[i].Reverse();
                    for (int j = 0; j < pathDirections[i].Count; j++)
                    {
                        pathDirections[i][j] = (EdgeDirection)(((int)pathDirections[i][j] + 3) % 6);
                    }
                }
                return(borderPaths);
            }