示例#1
0
        public InclineMeshData BuildMeshData(MapMetaData mapMetaData)
        {
            DateTime startTime = System.DateTime.Now;

            Debug.Log("started making incline mesh at " + startTime);

            int numInclineNodesX = Mathf.CeilToInt(mapMetaData.mapTerrainDataCells.GetLength(0) / (float)downsampleFactor);
            int numInclineNodesZ = Mathf.CeilToInt(mapMetaData.mapTerrainDataCells.GetLength(1) / (float)downsampleFactor);

            InclineMeshData meshData = new InclineMeshData(numInclineNodesX, numInclineNodesZ);

            meshData.downsampleFactor = downsampleFactor;
            meshData.mapMetaData      = mapMetaData;

            for (int x = 0; x < numInclineNodesX; ++x)
            {
                for (int z = 0; z < numInclineNodesZ; ++z)
                {
                    InclineIndexPoint inclinePoint = new InclineIndexPoint(x, z);
                    processNode(meshData, mapMetaData, inclinePoint);
                }
            }
            DateTime endTime = System.DateTime.Now;
            TimeSpan elapsed = endTime - startTime;

            Debug.Log("finished making incline mesh at " + endTime);
            Debug.Log("Elapsed Time: " + elapsed);

            return(meshData);
        }
示例#2
0
        /// <summary>
        /// Finds a path from any of start to goal, such that the path has no links that are steeper up than maxIncline
        /// nor steeper down than maxDecline.
        /// </summary>
        /// <returns>The path.</returns>
        /// <param name="startPoint">PointWithDistance of point to start from</param>
        /// <param name="goalPoint">map indices of point to go to</param>
        List <PointWithDistance> FindPath(PointWithDistance startPoint, InclineIndexPoint goalPoint, float maxIncline, float maxDecline)
        {
            List <PointWithDistance> startList = new List <PointWithDistance>();

            startList.Add(startPoint);
            return(FindPath(startList, goalPoint, maxIncline, maxDecline));
        }
示例#3
0
        float getDistanceBetweenTwoInclinePoints(InclineMeshData meshData, MapMetaData mapMetaData)
        {
            InclineIndexPoint inclinePoint1 = new InclineIndexPoint(1, 1);
            InclineIndexPoint inclinePoint2 = new InclineIndexPoint(1, 2);

            Point mapPoint1 = meshData.InclineIndicesToMapIndices(inclinePoint1);
            Point mapPoint2 = meshData.InclineIndicesToMapIndices(inclinePoint2);

            Vector3 worldVec1 = mapMetaData.getWorldPos(mapPoint1);
            Vector3 worldVec2 = mapMetaData.getWorldPos(mapPoint2);

            return((worldVec2 - worldVec1).magnitude);
        }
示例#4
0
        public Vector3 GetDestination(List <PointWithDistance> startPointList, Vector3 goal, float movementBudget, float maxSlope, AbstractActor unit, bool shouldSprint, List <AbstractActor> lanceUnits, PathNodeGrid pathGrid, out Vector3 lookAtPoint)
        {
            if (shouldSprint && unit.CanSprint)
            {
                unit.Pathing.SetSprinting();
            }
            else
            {
                unit.Pathing.SetWalking();
            }

            InclineIndexPoint goalPoint = WorldPointToInclineIndices(goal);

            List <PointWithDistance> pathLatticePoints = FindPath(startPointList, goalPoint, maxSlope, maxSlope);

            if ((pathLatticePoints == null) || (pathLatticePoints.Count == 0))
            {
                // can't find a path(!)

                // set the lookAtPoint (out) variable to a point further out in the direction of start->goal
                lookAtPoint = goal * 2.0f - unit.CurrentPosition;
                return(goal);
            }


            List <PathNode> pathNodes = new List <PathNode>();
            PathNode        walkNode  = pathLatticePoints[0].pathNode;

            while (walkNode != null)
            {
                pathNodes.Insert(0, walkNode);
                walkNode = walkNode.Parent;
            }

            List <Vector3> longRangePathWorldPoints = pathLatticePoints.ConvertAll(x => InclineIndicesToWorldPoint(x.point));
            List <Vector3> pathWorldPoints          = pathNodes.ConvertAll(x => x.Position);

            pathWorldPoints.AddRange(longRangePathWorldPoints);

            Vector3 destination;

            if (longRangePathWorldPoints.Count == 1)
            {
                destination = longRangePathWorldPoints[0];
                if ((goal - destination).magnitude < 1.0f)
                {
                    lookAtPoint = destination * 2.0f - unit.CurrentPosition;
                }
                else
                {
                    lookAtPoint = goal;
                }

                return(destination);
            }

            // Debug Draw Path
            float scale = 1.0f;

            for (int pathIndex = 0; pathIndex < pathWorldPoints.Count - 1; ++pathIndex)
            {
                int     nextIndex = pathIndex + 1;
                Vector3 p0        = pathWorldPoints[pathIndex];
                Vector3 p1        = pathWorldPoints[nextIndex];

                scale = (p1 - p0).magnitude;

                for (int dx = -1; dx <= 1; ++dx)
                {
                    for (int dz = -1; dz <= 1; ++dz)
                    {
                        Vector3 offset = new Vector3(dx * scale * 0.1f, 0, dz * scale * 0.1f);
                        Debug.DrawLine(p0 + offset, p1 + offset, Color.red, 30.0f);
                    }
                }
            }

            drawCircle(unit.CurrentPosition, scale * 0.4f, Color.cyan, 30.0f);
            drawCircle(goal, scale * 0.4f, Color.magenta, 30.0f);
            drawCircle(pathWorldPoints[0], scale * 0.3f, Color.red, 30.0f);
            drawCircle(pathWorldPoints[0], scale * 0.35f, Color.white, 30.0f);
            drawCircle(pathWorldPoints[0], scale * 0.4f, Color.blue, 30.0f);

            // TODO/dlecompte push this up to filter our selection of path nodes, above.
            float spread = unit.BehaviorTree.GetBehaviorVariableValue(
                unit.Combat.TurnDirector.IsInterleaved ?
                BehaviorVariableName.Float_InterleavedLanceSpreadDistance :
                BehaviorVariableName.Float_NonInterleavedLanceSpreadDistance).FloatVal;

            drawCircle(unit.CurrentPosition, spread, Color.green, 30.0f);

            Debug.Assert(pathWorldPoints.Count >= 2);             // already tested this, above.
            float accumDistance = 0.0f;

            // if we can get to the goal, look at a point further away in the direction of start -> goal
            lookAtPoint = 2 * goal - unit.CurrentPosition;
            Vector3 clipPoint = goal;

            // Now we walk along the pathWorldPoints, snapping them to grid points.
            // We want to take the point furthest along the path that doesn't alias to an earlier point.
            // Also, we want to make sure that it's the furthest point within our movement budget and within our lance spread.
            // MUST BE : within movement budget, not an alias to an earlier point
            // IF any points exist inside lance spread, pick last point inside lance spread, else last point.

            List <Vector3> dedupedSnappedPointsList = new List <Vector3>();
            List <Vector3> snappedPointsInOrder     = new List <Vector3>();
            List <Vector3> nextPointsInOrder        = new List <Vector3>();
            List <bool>    pointsInSpreadRangeList  = new List <bool>();
            List <bool>    isNewGroundList          = new List <bool>();

            float ROUNDING_RADIUS = 1.0f;

            bool wasEverInside = false;

            for (int pointIndex = 0; (pointIndex < pathWorldPoints.Count) && (accumDistance <= movementBudget); ++pointIndex)
            {
                Vector3 thisPoint = pathWorldPoints[pointIndex];
                Vector3 nextPoint = goal;
                if (pointIndex + 1 < pathWorldPoints.Count)
                {
                    nextPoint = pathWorldPoints[pointIndex + 1];
                }

                Vector3 thisSnappedPoint = unit.Combat.HexGrid.GetClosestPointOnGrid(thisPoint);
                snappedPointsInOrder.Add(thisSnappedPoint);
                nextPointsInOrder.Add(nextPoint);

                bool pointIsInsideSpread = AIUtil.IsPositionWithinLanceSpread(unit, lanceUnits, thisSnappedPoint);
                wasEverInside |= pointIsInsideSpread;
                pointsInSpreadRangeList.Add(pointIsInsideSpread);

                bool alreadyVisited = isPointInList(thisSnappedPoint, dedupedSnappedPointsList, ROUNDING_RADIUS);

                isNewGroundList.Add(!alreadyVisited);

                if (!alreadyVisited)
                {
                    dedupedSnappedPointsList.Add(thisSnappedPoint);
                }

                if (pointIndex + 1 < pathWorldPoints.Count)
                {
                    accumDistance += (nextPoint - thisPoint).magnitude;
                }
            }

            if (wasEverInside)
            {
                // find the last point of our list that is "new ground" and inside
                for (int i = snappedPointsInOrder.Count - 1; i >= 0; --i)
                {
                    if (isNewGroundList[i] && pointsInSpreadRangeList[i])
                    {
                        clipPoint   = snappedPointsInOrder[i];
                        lookAtPoint = nextPointsInOrder[i];
                        break;
                    }
                }
            }

            if ((!wasEverInside) || ((clipPoint - unit.CurrentPosition).magnitude < 1.0f))
            {
                // find the last point of our list that is "new ground"
                for (int i = snappedPointsInOrder.Count - 1; i >= 0; --i)
                {
                    if (isNewGroundList[i])
                    {
                        clipPoint   = snappedPointsInOrder[i];
                        lookAtPoint = nextPointsInOrder[i];
                        break;
                    }
                }
            }

            for (int i = snappedPointsInOrder.Count - 1; i >= 0; --i)
            {
                drawCircle(snappedPointsInOrder[i], scale * 0.2f, new Color(0.5f, 0.5f, 0.0f), 30.0f);
                if (pointsInSpreadRangeList[i])
                {
                    drawCircle(snappedPointsInOrder[i], scale * 0.25f, new Color(0.0f, 1.0f, 0.0f), 30.0f);
                }
            }

            //float lookAngle = PathingUtil.GetAngle(lookAtPoint - clipPoint);
            //Vector3 resultPos = clipPoint;
            drawCircle(clipPoint, scale * 0.4f, new Color(1.0f, 0.5f, 0.0f), 30.0f);
            return(clipPoint);
        }
示例#5
0
        /// <summary>
        /// Finds a path from any of the points in startPointList to goal, such that the path has no links that are steeper up than maxIncline
        /// nor steeper down than maxDecline.
        /// </summary>
        /// <returns>The path.</returns>
        /// <param name="startPointList">PointWithDistance structs for starting area</param>
        /// <param name="goalPoint">map indices of point to go to</param>
        List <PointWithDistance> FindPath(List <PointWithDistance> startPointList, InclineIndexPoint goalPoint, float maxIncline, float maxDecline)
        {
            List <PointWithDistance> path = new List <PointWithDistance>();

            HeapQueue <PointWithDistance> openHeap = new HeapQueue <PointWithDistance>();

            Dictionary <InclineIndexPoint, float> bestDistanceDict = new Dictionary <InclineIndexPoint, float>();

            Dictionary <InclineIndexPoint, PointWithDistance> bestPrevPoint = new Dictionary <InclineIndexPoint, PointWithDistance>();

            Point goalMapPoint = InclineIndicesToMapIndices(goalPoint);

            Vector3 worldGoalPoint = mapMetaData.getWorldPos(goalMapPoint);

            for (int startIndex = 0; startIndex < startPointList.Count; ++startIndex)
            {
                PointWithDistance pwd = startPointList[startIndex];
                openHeap.Push(pwd);
                bestDistanceDict[pwd.point] = pwd.distance;
                bestPrevPoint[pwd.point]    = null;
            }

            float             bestPathLength = -1;
            PointWithDistance bestGoalPoint  = new PointWithDistance(new InclineIndexPoint(-1024, -1024),
                                                                     float.MaxValue,
                                                                     float.MaxValue);

            while (!openHeap.IsEmpty())
            {
                PointWithDistance ptWithDist = openHeap.PopMinimum();

                if ((bestPathLength > 0) && ((ptWithDist.estimatedTotalDistance > bestPathLength) || TAKE_FIRST_PATH))
                {
                    break;
                }

                int[] xOffsets = { 1, 0, -1, 0 };
                int[] zOffsets = { 0, 1, 0, -1 };

                InclineMeshNode node = nodes[ptWithDist.point.X, ptWithDist.point.Z];

                Vector3 worldNodePoint = InclineIndicesToWorldPoint(ptWithDist.point);

                for (int direction = 0; direction < 4; ++direction)
                {
                    int dx = xOffsets[direction];
                    int dz = zOffsets[direction];

                    int nx = ptWithDist.point.X + dx;
                    int nz = ptWithDist.point.Z + dz;

                    InclineIndexPoint neighborPoint    = new InclineIndexPoint(nx, nz);
                    Point             mapNeighborPoint = InclineIndicesToMapIndices(neighborPoint);

                    if ((!mapMetaData.IsWithinBounds(mapNeighborPoint)) || (node.NeighborLinks[direction] == null))
                    {
                        continue;
                    }

                    Vector3 worldNeighborPoint = InclineIndicesToWorldPoint(neighborPoint);

                    for (int linkIndex = 0; linkIndex < node.NeighborLinks[direction].Count; ++linkIndex)
                    {
                        Debug.DrawLine(worldNodePoint, worldNeighborPoint, Color.yellow, 15.0f);

                        InclineLinkData link = node.NeighborLinks[direction][linkIndex];

                        if ((link.declineAsFloat() > maxDecline) || (link.inclineAsFloat() > maxIncline))
                        {
                            continue;
                        }

                        float linkDistance = (worldNeighborPoint - worldNodePoint).magnitude;

                        float totalDistance = ptWithDist.distance + linkDistance;

                        if ((bestPathLength >= 0) &&
                            (totalDistance >= bestPathLength))
                        {
                            continue;
                        }

                        if ((!bestDistanceDict.ContainsKey(neighborPoint)) ||
                            (totalDistance < bestDistanceDict[neighborPoint]))
                        {
                            bestDistanceDict[neighborPoint] = totalDistance;
                            bestPrevPoint[neighborPoint]    = ptWithDist;

                            float distanceToGoal = (worldNeighborPoint - worldGoalPoint).magnitude;

                            if (neighborPoint.Equals(goalPoint))
                            {
                                if ((bestPathLength < 0) ||
                                    (totalDistance < bestPathLength))
                                {
                                    bestPathLength = totalDistance;
                                    bestGoalPoint  = new PointWithDistance(neighborPoint, totalDistance, 0.0f);
                                }
                            }
                            else
                            {
                                openHeap.Push(new PointWithDistance(neighborPoint, totalDistance, totalDistance + distanceToGoal));
                            }
                        }
                        break;
                    }
                }
            }

            if (bestPathLength >= 0)
            {
                PointWithDistance p = bestGoalPoint;
                path.Add(p);
                while (bestPrevPoint.ContainsKey(p.point))
                {
                    PointWithDistance prevPoint = bestPrevPoint[p.point];
                    if ((prevPoint == null) || (path.Contains(prevPoint)))
                    {
                        break;
                    }
                    path.Insert(0, prevPoint);
                    p = prevPoint;
                }
            }

            return(path);
        }
示例#6
0
 public PointWithDistance(InclineIndexPoint point, float distance, float estimatedTotalDistance)
 {
     this.point    = point;
     this.distance = distance;
     this.estimatedTotalDistance = estimatedTotalDistance;
 }
示例#7
0
        public Vector3 InclineIndicesToWorldPoint(InclineIndexPoint inclineIndices)
        {
            Point mapIndices = InclineIndicesToMapIndices(inclineIndices);

            return(mapMetaData.getWorldPos(mapIndices));
        }
示例#8
0
 public Point InclineIndicesToMapIndices(InclineIndexPoint inclineIndices)
 {
     return(new Point(inclineIndices.X * downsampleFactor, inclineIndices.Z * downsampleFactor));
 }
示例#9
0
        void processNode(InclineMeshData meshData, MapMetaData mapMetaData, InclineIndexPoint inclinePoint)
        {
            Point startPointMapIndices = meshData.InclineIndicesToMapIndices(inclinePoint);

            if (!mapMetaData.IsWithinBounds(startPointMapIndices))
            {
                return;
            }

            Dictionary <Point, List <InclineLinkData> > bestPaths = new Dictionary <Point, List <InclineLinkData> >();
            List <InclineLinkData> starterList = new List <InclineLinkData>();

            starterList.Add(new InclineLinkData());

            bestPaths[startPointMapIndices] = starterList;

            List <Point> openPoints = new List <Point>();

            openPoints.Add(startPointMapIndices);

            float maximumPathDistance = overshootMultiplier * getDistanceBetweenTwoInclinePoints(meshData, mapMetaData);

            while (openPoints.Count > 0)
            {
                Point p = openPoints[0];
                openPoints.RemoveAt(0);

                //Debug.LogFormat("dequeueing {0} {1}", p.X, p.Z);

                for (int d = 0; d < 4; ++d)
                {
                    int dx = 0;
                    int dz = 0;

                    switch (d)
                    {
                    case 0: dx = 1; dz = 0; break;

                    case 1: dx = 0; dz = 1; break;

                    case 2: dx = -1; dz = 0; break;

                    case 3: dx = 0; dz = -1; break;

                    default: Debug.LogError("invalid direction: " + d); continue;
                    }

                    Point newPoint = new Point(p.X + dx, p.Z + dz);

                    if ((!mapMetaData.IsWithinBounds(newPoint)) ||
                        (!mapMetaData.IsWithinBounds(p)))
                    {
                        continue;
                    }

                    float incline, decline, distance;
                    getIncrementalInclines(mapMetaData, p, newPoint, out incline, out decline, out distance);

                    bool pointIsDirty = false;

                    for (int pathIndex = 0; pathIndex < bestPaths[p].Count; pathIndex++)
                    {
                        InclineLinkData pathSoFar = bestPaths[p][pathIndex];

                        float oldFloatIncline  = pathSoFar.inclineAsFloat();
                        float oldFloatDecline  = pathSoFar.declineAsFloat();
                        float oldFloatDistance = pathSoFar.distanceAsFloat();

                        float newFloatIncline  = Mathf.Max(incline, oldFloatIncline);
                        float newFloatDecline  = Mathf.Max(decline, oldFloatDecline);
                        float newFloatDistance = oldFloatDistance + distance;

                        // if the distance is too far, also stop recursing.
                        if (newFloatDistance > maximumPathDistance)
                        {
                            continue;
                        }

                        InclineLinkData newPathLinkData = new InclineLinkData(newFloatIncline, newFloatDecline, newFloatDistance);

                        bool foundAnyBetter         = false;
                        int  iAmBetterThanThisIndex = -1;

                        if (bestPaths.ContainsKey(newPoint))
                        {
                            for (int existingPathIndex = 0; existingPathIndex < bestPaths[newPoint].Count; ++existingPathIndex)
                            {
                                InclineLinkData existingPath = bestPaths[newPoint][existingPathIndex];
                                // If an existing path is as good or better than us, then stop recursing.

                                if (existingPath.Equals(newPathLinkData) ||
                                    existingPath.Dominates(newPathLinkData))
                                {
                                    foundAnyBetter = true;
                                    break;
                                }

                                if (newPathLinkData.Dominates(existingPath))
                                {
                                    iAmBetterThanThisIndex = existingPathIndex;
                                    break;
                                }
                            }
                        }
                        else
                        {
                            bestPaths[newPoint] = new List <InclineLinkData>();
                        }

                        if (iAmBetterThanThisIndex >= 0)
                        {
                            // found a better path than an existing one, remove the old one and recompute.
                            bestPaths[newPoint][iAmBetterThanThisIndex] = newPathLinkData;
                            pointIsDirty = true;
                        }
                        else if (!foundAnyBetter)
                        {
                            // Otherwise, add this path to the list of paths, and recurse.

                            bestPaths[newPoint].Add(newPathLinkData);
                            pointIsDirty = true;
                        }
                    }
                    if (pointIsDirty)
                    {
                        openPoints.Add(newPoint);
                    }
                }
            }

            meshData.nodes[inclinePoint.X, inclinePoint.Z] = new InclineMeshNode();

            // now, grab the links from our neighbors
            for (int d = 0; d < 4; ++d)
            {
                int dx = 0;
                int dz = 0;

                switch (d)
                {
                case 0: dx = 1; dz = 0; break;

                case 1: dx = 0; dz = 1; break;

                case 2: dx = -1; dz = 0; break;

                case 3: dx = 0; dz = -1; break;

                default: Debug.LogError("invalid direction: " + d); continue;
                }

                InclineIndexPoint neighborInclinePoint = new InclineIndexPoint(inclinePoint.X + dx, inclinePoint.Z + dz);
                Point             neighborMapIndices   = meshData.InclineIndicesToMapIndices(neighborInclinePoint);

                if (!mapMetaData.IsWithinBounds(neighborMapIndices))
                {
                    continue;
                }

                if (bestPaths.ContainsKey(neighborMapIndices))
                {
                    /*
                     * foreach (InclineLinkData ild in bestPaths[neighborWorldPoint])
                     * {
                     *      //Debug.LogFormat("from {0} {1} in dir {2}: {3}/{4}/{5}", inclinePoint.X, inclinePoint.Z, d, ild.incline, ild.decline, ild.distance);
                     * }
                     */
                    meshData.nodes[inclinePoint.X, inclinePoint.Z].NeighborLinks[d] = bestPaths[neighborMapIndices];

                    // draw debug
                    //Debug.DrawLine(meshData.InclineIndicesToWorldPoint(inclinePoint), meshData.mapMetaData.getWorldPos(neighborMapIndices), Color.white, 25.0f);
                }
            }
        }