예제 #1
0
 public AlgorithmState(ObservableCollection <PFNode> squares, List <PFNode> available, PFNode currentlyChecking, AlgorithmState last)
 {
     Squares           = squares;
     CurrentlyChecking = currentlyChecking;
     Available         = available;
     Last = last;
 }
예제 #2
0
    // This is heftily f****d up. Seriously needs fixing.
    public PFNode getNodeNearestCover()
    {
        //float nearestDistance = float.MaxValue;
        //PFNode nearestNode;

        if (currentNode.type == PFNodeType.Crouch || currentNode.type == PFNodeType.Stand)
        {
            return(currentNode);
        }

        foreach (PFNodeEntry node in currentNode.Nodes)
        {
            if (node.node.type == PFNodeType.Stand || node.node.type == PFNodeType.Crouch)
            {
                // If node is cover
                Vector3 startPos = transform.position;
                Vector3.MoveTowards(startPos, node.node.transform.position, 1);
                if (!Physics.Linecast(startPos, node.node.transform.position))
                {
                    choice = node.node;
                    return(node.node);
                }
            }
        }

        return(currentNode);        // Untill we can have recursive search systems.
    }
예제 #3
0
    private int GetManhattenDistance(PFNode nodeA, PFNode nodeB)
    {
        int ix = Mathf.Abs(nodeA.GridX - nodeB.GridX);
        int iy = Mathf.Abs(nodeA.GridY - nodeB.GridY);

        return(ix + iy);
    }
예제 #4
0
 public void SetupGroup()
 {
     PFNode[] PFNodes = GetComponentsInChildren <PFNode>();
     //print (PFNodes.Length);
     for (int i = 0; i < PFNodes.Length; i++)
     {
         PFNodes[i].Nodes = new PFNodeEntry[PFNodes.Length - 1];
         for (int o = 0; o < PFNodes[i].Nodes.Length; o++)
         {
             PFNodes[i].Nodes[o] = new PFNodeEntry();
         }
         //print("Working at "+PFNodes[i].name+".");
         for (int o = 0; o < PFNodes.Length; o++)
         {
             //print("Attempting to connect "+i+" and "+o+".");
             PFNode n0 = PFNodes[o];
             if (o > i)
             {
                 PFNodes[i].Nodes[o - 1].node     = PFNodes[o];
                 PFNodes[i].Nodes[o - 1].distance = Vector3.Distance(PFNodes[i].transform.position, PFNodes[o].transform.position);
             }
             else if (o < i)
             {
                 PFNodes[i].Nodes[o].node     = PFNodes[o];
                 PFNodes[i].Nodes[o].distance = Vector3.Distance(PFNodes[i].transform.position, PFNodes[o].transform.position);
             }
         }
     }
 }
예제 #5
0
            public PFNode UpdateStatus(int newStatus)             //Since List Returns Copy of Node
            //We use this to replace existing node.
            {
                PFNode newNode = this;

                newNode.Status = newStatus;
                return(newNode);
            }
예제 #6
0
파일: PFNode.cs 프로젝트: wow4all/Scripts
 public float riskAssessment(GameObject[] enemies, PFNode otherNode)
 {
     foreach (GameObject enemy in enemies) {
         riskFactor += Vector3.Distance(enemy.transform.position, node.transform.position);
         riskFactor += Vector3.Distance(enemy.transform.position, otherNode.transform.position);
     }
     riskFactor += Vector3.Distance(node.transform.position, otherNode.transform.position);
     return riskFactor;
 }
예제 #7
0
    private void FindPath(Vector3 startPosition, Vector3 targetPosition)
    {
        PFNode startNode  = _grid.GetNodeFromWorldPosition(startPosition);
        PFNode targetNode = _grid.GetNodeFromWorldPosition(targetPosition);

        // The list for all the checked nodes, and get deleted each time
        List <PFNode> openList = new List <PFNode>();

        // The hashset of the relevant nodes for the path
        HashSet <PFNode> closedList = new HashSet <PFNode>();

        openList.Add(startNode);

        while (openList.Count > 0)
        {
            PFNode currentNode = openList[0];

            for (int i = 1; i < openList.Count; i++)
            {
                if (openList[i].FCost < currentNode.FCost || openList[i].FCost == currentNode.FCost &&
                    openList[i].hCost < currentNode.hCost)
                {
                    currentNode = openList[i];
                }
            }
            openList.Remove(currentNode);
            closedList.Add(currentNode);

            if (currentNode == targetNode)
            {
                GetFinalPath(startNode, targetNode);
            }

            foreach (PFNode neighborNode in _grid.GetNeighboringNodes(currentNode))
            {
                if (neighborNode.IsObstacle || closedList.Contains(neighborNode))
                {
                    continue;
                }

                int moveCost = currentNode.gCost + GetManhattenDistance(currentNode, neighborNode);

                if (moveCost < neighborNode.gCost || !openList.Contains(neighborNode))
                {
                    neighborNode.gCost  = moveCost;
                    neighborNode.hCost  = GetManhattenDistance(neighborNode, targetNode);
                    neighborNode.Parent = currentNode;

                    if (!openList.Contains(neighborNode))
                    {
                        openList.Add(neighborNode);
                    }
                }
            }
        }
    }
예제 #8
0
 public float riskAssessment(GameObject[] enemies, PFNode otherNode)
 {
     foreach (GameObject enemy in enemies)
     {
         riskFactor += Vector3.Distance(enemy.transform.position, node.transform.position);
         riskFactor += Vector3.Distance(enemy.transform.position, otherNode.transform.position);
     }
     riskFactor += Vector3.Distance(node.transform.position, otherNode.transform.position);
     return(riskFactor);
 }
예제 #9
0
    /// <summary>
    /// Gets the node closest from any enemy combatants, inclusive of current nodea.
    ///
    /// FUTURE: Add calculations for safety based on effective range of the weapon they are holding.
    ///     e.g., One is much safer ten meters away from a sniper than one half-kilometer away.
    /// </summary>
    /// <returns>
    /// The most dangerous node.
    /// </returns>
    public PFNode getNodeClosestToEnemies(GameObject[] enemies, Faction allegiance = Faction.Evil)
    {
        float leastDangerous = 0f;
        int   index          = -1;
        int   i = 0;

        foreach (GameObject e in enemies)
        {
            // Change the != to whatever the faction relationship system is.
            if (e.GetComponent <Enemy>().faction != allegiance)
            {
                leastDangerous +=
                    (currentNode.transform.position - e.transform.position).sqrMagnitude;
            }
        }
        if (debugMode)
        {
            print("Risk for " + currentNode.name + " is " + leastDangerous);
        }

        foreach (PFNodeEntry node in currentNode.Nodes)
        {
            float riskFactor = 0;
            if (debugMode)
            {
                foreach (GameObject g in enemies)
                {
                    print(g.name);
                }
            }
            foreach (GameObject e in enemies)
            {
                if (e.GetComponent <Enemy>().faction != allegiance)
                {
                    riskFactor +=
                        (node.node.transform.position - e.transform.position).sqrMagnitude;
                }
                //if (debugMode) print ("Calculated for " + e.name + " near " + node.node.gameObject.name);
            }
            if (debugMode)
            {
                print("Risk for " + node.node.name + " is " + riskFactor);
            }
            if (riskFactor < leastDangerous)
            {
                index          = i;
                leastDangerous = riskFactor;
            }
            i++;
        }
        choice = (index == -1) ? currentNode : currentNode.Nodes[index].node;
        return((index == -1) ? currentNode : currentNode.Nodes[index].node);
    }
예제 #10
0
    public PFNode Dequeue()
    {
        if (List.Count == 0)
        {
            return(null);
        }

        PFNode top = List[0];

        List.RemoveAt(0);
        return(top);
    }
예제 #11
0
    public PFNode Take(Vector2Int pos)
    {
        for (int i = 0; i < List.Count; i++)
        {
            if (List[i].pos == pos)
            {
                PFNode ret = List[i];
                List.RemoveAt(i);
                return(ret);
            }
        }

        return(null);
    }
예제 #12
0
    private void GetFinalPath(PFNode startNode, PFNode endNode)
    {
        List <PFNode> finalPath   = new List <PFNode>();
        PFNode        currentNode = endNode;

        while (currentNode != startNode)
        {
            finalPath.Add(currentNode);
            currentNode = currentNode.Parent;
        }

        Debug.Log("found path!");
        finalPath.Reverse();
        _grid.FinalPath = finalPath;
    }
예제 #13
0
 public void OnSceneGUI()
 {
     PFNode[] PFNs = ((PFNodeAmorphousGroup)target).transform.gameObject.GetComponentsInChildren <PFNode>();
     for (int i = 0; i < PFNs.Length; i++)
     {
         PFNode p = PFNs[i];
         p.transform.position = Handles.PositionHandle(p.transform.position, p.transform.rotation);
         //foreach (PFNodeEntry e in p.Nodes) {
         //	Handles.DrawLine(e.node.transform.position, p.transform.position);
         //}
         Handles.Label(p.transform.position, "Node " + i.ToString());
     }
     if (GUI.changed)
     {
         EditorUtility.SetDirty(target);
     }
 }
예제 #14
0
    /// <summary>
    /// Gets the nearest node to the current node.
    /// </summary>
    /// <returns>
    /// The node nearest the current node.
    /// </returns>
    public PFNode getNodeNearest()
    {
        float distance = float.MaxValue;                        // Should be safe.
        int   index    = -1;
        int   i        = 0;

        foreach (PFNodeEntry E in currentNode.Nodes)
        {
            if (E.distance < distance)
            {
                distance = E.distance;
                index    = i;
            }
            i++;
        }
        choice = (index == -1) ? currentNode : currentNode.Nodes[index].node;
        return((index == -1) ? currentNode : currentNode.Nodes[index].node);
    }
예제 #15
0
    private int InsertSearch(int start, int end, int fcost)
    {
        if (start == end)
        {
            return(start);
        }

        int mid  = (start + end) / 2;
        int comp = PFNode.Compare(fcost, List[mid]);

        if (comp <= 0)
        {
            return(InsertSearch(start, mid, fcost));
        }
        else
        {
            return(InsertSearch(mid + 1, end, fcost));
        }
    }
예제 #16
0
    /// <summary>
    /// Gets the node where one is most likely to be able to blow someone's brains out.
    /// Basically, the node with the most teammates, and the most enemeies nearby.
    /// </summary>
    /// <returns>
    /// The most dangerous node.
    /// </returns>
    public PFNode getNodeMostDangerous(GameObject[] enemies, Faction allegiance = Faction.Evil)
    {
        float leastDangerous = 0f;
        int index = -1;
        int i = 0;

        foreach (GameObject e in enemies) {
                                  // Change the != to whatever the faction relationship system is.
            if (e.GetComponent<Enemy>().faction != allegiance) leastDangerous +=
                (currentNode.transform.position - e.transform.position).sqrMagnitude;
        }
        if (debugMode) print ("Risk for " + currentNode.name + " is "+leastDangerous);

        foreach (PFNodeEntry node in currentNode.Nodes) {
            float riskFactor = 0;
            if (debugMode) foreach (GameObject g in enemies)print (g.name);
            foreach (GameObject e in enemies) {

                // This is the fancy bit where you calculate where to run and hide.

                if (e.GetComponent<Enemy>() is ShootingEnemy) {
                    //float thisCombatantsRisk;
                    if (e != gameObject.GetComponent<Enemy>()) {

                        if (e.GetComponent<Enemy>().faction != allegiance) riskFactor +=
                            (node.node.transform.position-e.transform.position).sqrMagnitude;

                    }

                } else if (e.GetComponent<Enemy>() is PlayerCombatant) {

                    if (e.GetComponent<Enemy>().faction != allegiance) riskFactor +=
                        (node.node.transform.position- e.transform.position).sqrMagnitude;

                } else {

                    if (e.GetComponent<Enemy>().faction != allegiance) riskFactor +=
                        (node.node.transform.position- e.transform.position).sqrMagnitude;

                }
                //if (debugMode) print ("Calculated for " + e.name + " near " + node.node.gameObject.name);

            }
            if (debugMode) print ("Risk for " + node.node.name + " is "+riskFactor);
            if (riskFactor < leastDangerous) {
                index = i;
                leastDangerous = riskFactor;
            }
            i++;
        }

        choice=(index == -1) ? currentNode : currentNode.Nodes[index].node;
        return (index == -1) ? currentNode : currentNode.Nodes[index].node;
    }
예제 #17
0
    /// <summary>
    /// Gets the node closest from any enemy combatants, inclusive of current nodea.
    /// 
    /// FUTURE: Add calculations for safety based on effective range of the weapon they are holding.
    /// 	e.g., One is much safer ten meters away from a sniper than one half-kilometer away.
    /// </summary>
    /// <returns>
    /// The most dangerous node.
    /// </returns>
    public PFNode getNodeClosestToEnemies(GameObject[] enemies, Faction allegiance = Faction.Evil)
    {
        float leastDangerous = 0f;
        int index = -1;
        int i = 0;

        foreach (GameObject e in enemies) {
                        // Change the != to whatever the faction relationship system is.
            if (e.GetComponent<Enemy>().faction != allegiance) leastDangerous +=
                (currentNode.transform.position- e.transform.position).sqrMagnitude;
        }
        if (debugMode) print ("Risk for " + currentNode.name + " is "+leastDangerous);

        foreach (PFNodeEntry node in currentNode.Nodes) {
            float riskFactor = 0;
            if (debugMode) foreach (GameObject g in enemies)print (g.name);
            foreach (GameObject e in enemies) {
                if (e.GetComponent<Enemy>().faction != allegiance) riskFactor +=
                    (node.node.transform.position - e.transform.position).sqrMagnitude;
                //if (debugMode) print ("Calculated for " + e.name + " near " + node.node.gameObject.name);
            }
            if (debugMode) print ("Risk for " + node.node.name + " is "+riskFactor);
            if (riskFactor < leastDangerous) {
                index = i;
                leastDangerous = riskFactor;
            }
            i++;
        }
        choice=(index == -1) ? currentNode : currentNode.Nodes[index].node;
        return (index == -1) ? currentNode : currentNode.Nodes[index].node;
    }
예제 #18
0
    // This is heftily f****d up. Seriously needs fixing.
    public PFNode getNodeNearestCover()
    {
        //float nearestDistance = float.MaxValue;
        //PFNode nearestNode;

        if (currentNode.type == PFNodeType.Crouch || currentNode.type == PFNodeType.Stand) return currentNode;

        foreach (PFNodeEntry node in currentNode.Nodes) {
            if (node.node.type == PFNodeType.Stand || node.node.type == PFNodeType.Crouch) {
                // If node is cover
                Vector3 startPos = transform.position;
                Vector3.MoveTowards(startPos, node.node.transform.position, 1);
                if (!Physics.Linecast(startPos, node.node.transform.position)) {
                    choice=node.node;
                    return node.node;
                }
            }
        }

        return currentNode; // Untill we can have recursive search systems.
    }
예제 #19
0
 /// <summary>
 /// Gets the nearest node to the current node.
 /// </summary>
 /// <returns>
 /// The node nearest the current node.
 /// </returns>
 public PFNode getNodeNearest()
 {
     float distance = float.MaxValue;		// Should be safe.
     int index = -1;
     int i = 0;
     foreach (PFNodeEntry E in currentNode.Nodes) {
         if (E.distance < distance) {
             distance = E.distance;
             index = i;
         }
         i++;
     }
     choice=(index == -1) ? currentNode : currentNode.Nodes[index].node;
     return (index == -1) ? currentNode : currentNode.Nodes[index].node;
 }
예제 #20
0
    /// <summary>
    /// Gets the node where one is most likely to be able to blow someone's brains out.
    /// Basically, the node with the most teammates, and the most enemeies nearby.
    /// </summary>
    /// <returns>
    /// The most dangerous node.
    /// </returns>
    public PFNode getNodeMostDangerous(GameObject[] enemies, Faction allegiance = Faction.Evil)
    {
        float leastDangerous = 0f;
        int   index          = -1;
        int   i = 0;

        foreach (GameObject e in enemies)
        {
            // Change the != to whatever the faction relationship system is.
            if (e.GetComponent <Enemy>().faction != allegiance)
            {
                leastDangerous +=
                    (currentNode.transform.position - e.transform.position).sqrMagnitude;
            }
        }
        if (debugMode)
        {
            print("Risk for " + currentNode.name + " is " + leastDangerous);
        }

        foreach (PFNodeEntry node in currentNode.Nodes)
        {
            float riskFactor = 0;
            if (debugMode)
            {
                foreach (GameObject g in enemies)
                {
                    print(g.name);
                }
            }
            foreach (GameObject e in enemies)
            {
                // This is the fancy bit where you calculate where to run and hide.


                if (e.GetComponent <Enemy>() is ShootingEnemy)
                {
                    //float thisCombatantsRisk;
                    if (e != gameObject.GetComponent <Enemy>())
                    {
                        if (e.GetComponent <Enemy>().faction != allegiance)
                        {
                            riskFactor +=
                                (node.node.transform.position - e.transform.position).sqrMagnitude;
                        }
                    }
                }
                else if (e.GetComponent <Enemy>() is PlayerCombatant)
                {
                    if (e.GetComponent <Enemy>().faction != allegiance)
                    {
                        riskFactor +=
                            (node.node.transform.position - e.transform.position).sqrMagnitude;
                    }
                }
                else
                {
                    if (e.GetComponent <Enemy>().faction != allegiance)
                    {
                        riskFactor +=
                            (node.node.transform.position - e.transform.position).sqrMagnitude;
                    }
                }
                //if (debugMode) print ("Calculated for " + e.name + " near " + node.node.gameObject.name);
            }
            if (debugMode)
            {
                print("Risk for " + node.node.name + " is " + riskFactor);
            }
            if (riskFactor < leastDangerous)
            {
                index          = i;
                leastDangerous = riskFactor;
            }
            i++;
        }

        choice = (index == -1) ? currentNode : currentNode.Nodes[index].node;
        return((index == -1) ? currentNode : currentNode.Nodes[index].node);
    }
예제 #21
0
파일: PFNode.cs 프로젝트: wow4all/Scripts
 public bool accessibilityAssessment(PFNode otherNode)
 {
     return accessible = !Physics.Linecast(node.transform.position, otherNode.transform.position);
 }
예제 #22
0
        // TODO: update UI components affected (put it in Calculate function for each of the squares)
        private async Task <List <PFNode> > CalculateSquareSorroundings(PFNode square, bool calcCosts = true)
        {
            var           x     = square.X;
            var           y     = square.Y;
            List <Task>   tasks = new List <Task>();
            List <PFNode> toR   = new List <PFNode>();
            // this list is any square sorrounding the square that we need to check
            List <(int, int)> toCheck = new List <(int, int)>()
            {
                //(x + 1, y + 1),
                (x, y + 1),
                //(x - 1, y + 1),
                (x + 1, y),
                (x, y),
                (x - 1, y),
                //(x + 1, y - 1),
                (x, y - 1),
                //(x - 1, y - 1),
            };

            // because we are removing elements in toCheck I'd like to avoid using the same list
            foreach (var t in toCheck.ToList())
            {
                if (t.Item1 < 0 || t.Item1 > 52 || t.Item2 < 0 || t.Item2 > 52)
                {
                    toCheck.Remove(t);
                }
                else if (!SquareIsWalkable(SquaresList[t.Item1 * 53 + t.Item2]))
                {
                    toCheck.Remove(t);
                }
            }

            if (calcCosts)
            {
                if (SelectedAlgorithmType == AlgorithmType.AStar)
                {
                    foreach (var t in toCheck)
                    {
                        PFNode curr = SquaresList[t.Item1 * 53 + t.Item2];
                        tasks.Add(Task.Run(curr.AStarCalculateCosts));
                        toR.Add(curr);
                    }
                }
                else if (SelectedAlgorithmType == AlgorithmType.Djikstras)
                {
                    foreach (var t in toCheck)
                    {
                        PFNode curr = SquaresList[t.Item1 * 53 + t.Item2];
                        tasks.Add(Task.Run(curr.DjikstrasCalculateCosts));
                        toR.Add(curr);
                    }
                }
                else
                {
                    // THIS IS TEMPORARY
                    foreach (var t in toCheck)
                    {
                        PFNode curr = SquaresList[t.Item1 * 53 + t.Item2];
                        tasks.Add(Task.Run(curr.AStarCalculateCosts));
                        toR.Add(curr);
                    }
                }
            }
            else
            {
                foreach (var k in toCheck)
                {
                    toR.Add(SquaresList[k.Item1 * 53 + k.Item2]);
                }
                return(toR);
            }


            await Task.WhenAll(tasks);

            return(toR);
        }
예제 #23
0
 public PFNode(INavable cube, PFNode prevNode, int cost)
 {
     this.cube     = cube;
     this.prevNode = prevNode;
     this.cost     = cost;
 }
예제 #24
0
    /// <summary>
    /// maxDistance로 갈수 있는 큐브들을 BFS로 찾아 OnServe콜백함수의 PFPath인자로 돌려줍니다.
    /// </summary>
    /// <param name="maxDistance">BFS로 찾을 최대 거리</param>
    /// <param name="OnServe">함수가 끝나면 호출할 함수를 전달하세요. 함수의 인자로 Path가 전달됩니다.</param>
    /// <param name="cubeIgnore">Path에 포함시키지 않을 Predicate</param>
    /// <returns></returns>
    private IEnumerator BFSPathfinding(
        INavable start, List <INavable> navables, int maxDistance,
        Action <List <PFPath> > OnServe, Func <INavable, bool> cubeIgnore)
    {
        OnSearchBegin();

        // 나중에 cost가 정해진 노드들만 path로 만들기 위함
        List <PFNode> table = new List <PFNode>();

        // BFS: Initialization
        Queue <PFNode> queue     = new Queue <PFNode>();
        PFNode         startNode = new PFNode(start, null, 0);

        queue.Enqueue(startNode);
        table.Add(startNode);

        // BFS: Traversal
        int maxLoop  = 40;
        int currLoop = 0;

        while (queue.Count > 0)
        {
            PFNode currNode = queue.Dequeue();
            if (currNode.cost >= maxDistance)
            {
                continue;
            }

            List <INavable> neighborCubes = currNode.cube.Neighbors;

            foreach (var neighborCube in neighborCubes)
            {
                if (cubeIgnore(neighborCube))
                {
                    continue;
                }
                if (table.Any(node => node.cube == neighborCube))
                {
                    continue;                                               // 이미 다른 Path에 있음
                }
                PFNode newNode = new PFNode(neighborCube, currNode, currNode.cost + 1);
                queue.Enqueue(newNode);
                table.Add(newNode);
            }
            currLoop++;

            if (currLoop >= maxLoop)
            {
                currLoop = 0;
                yield return(null);
            }
        }

        // Path Construction
        List <PFPath> paths = new List <PFPath>();

        currLoop = 0;
        foreach (var destination in table)
        {
            PFPath path = new PFPath(start, destination);
            path.Add(destination);

            PFNode currNode = destination;
            while (currNode.prevNode != null)
            {
                path.Add(currNode.prevNode);
                currNode = currNode.prevNode;
            }
            path.Reverse();

            paths.Add(path);

            currLoop++;
            if (currLoop >= maxLoop)
            {
                currLoop = 0;
                yield return(null);
            }
        }

        // return by Calling Callback Function
        OnServe(paths);
        OnSearchEnd();
    }
예제 #25
0
 public static int Compare(int a, PFNode b)
 {
     return(a - b.GetFcost());
 }
예제 #26
0
 public static int Compare(PFNode a, PFNode b)
 {
     return(a.GetFcost() - b.GetFcost());
 }
예제 #27
0
        public List <Vector2> FindPath(Vector2 start, Vector2 end)
        {
            #region Setup
            //Stop if end goal is impossible
            if (GridManager.Instance.ContainsGridObject(true, (int)end.x, (int)end.y))
            {
                Debug.LogWarning("AStar Failed. End Location is blocked");
                return(null);
            }

            //Clearing Before Start
            while (traversedCoordinates.Count > 0)
            {
                nodes[traversedCoordinates.Pop()].Clear();
            }

            Debug.Log("FindPath Called. Start: (" + start.x + "," + start.y + ")  & " + "End: (" + end.x + "," + end.y + ")");

            //Reset Values
            nodeOpenValue  += 2;            //This allows for nodes to be reset without looping through grid
            nodeCloseValue += 2;
            openLocations.Clear();

            //If Created Before GridManager is loaded
            if (nodes.Length == 0)
            {
                SetUpGridAndQueue();
            }


            //Convert From Vector to Location
            Location myLocation  = new Location((int)start.y * GridManager.Instance.GridWidth + (int)start.x, 0);
            Location endLocation = new Location((int)end.y * GridManager.Instance.GridWidth + (int)end.x, 0);



            //First Node To Branch From
            PFNode firstNode = new PFNode();
            firstNode.G      = 0;
            firstNode.F      = 1;
            firstNode.PX     = (ushort)start.x;
            firstNode.PY     = (ushort)start.y;
            firstNode.PZ     = 0;
            firstNode.Status = nodeOpenValue;

            //Setting Jump Length
            if (GridManager.Instance.ContainsGridObject(true, (int)start.x, (int)start.y - 1))
            {
                firstNode.JumpLength = 0;
            }
            else
            {
                firstNode.JumpLength = (short)(characterJumpHeight * 2);
            }

            Debug.Log("GridWidth = " + GridManager.Instance.GridWidth + ". mylocation.xy = " + myLocation.xy
                      + ". Nodes Array Length = " + nodes.Length);

            //Adding Start Location to Stack
            nodes[myLocation.xy].Add(firstNode);
            traversedCoordinates.Push(myLocation.xy);
            openLocations.Push(myLocation);

            #endregion

            bool found          = false;
            long iterationCount = 0;
            int[,] direction = new int[8, 2] {
                { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 }, { 1, -1 }, { 1, 1 }, { -1, 1 }, { -1, -1 }
            };
            //Loop Through Priority Queue
            while (openLocations.Count > 0)             //Add Other Stop Condition Maybe?
            {
                Location current = openLocations.Pop();

                if (nodes[current.xy][current.z].Status == nodeCloseValue)                 //Ignore Visited
                {
                    continue;
                }

                int currentX = current.xy % GridManager.Instance.GridWidth;
                int currentY = current.xy / GridManager.Instance.GridWidth;                 //Int division truncates off x portion

                //Found Target Path!
                if (current.xy == endLocation.xy)
                {
                    nodes[current.xy][current.z] = nodes[current.xy][current.z].UpdateStatus(nodeCloseValue);
                    found = true;
                    break;
                }

                //Search Limit
                if (iterationCount > iterationSearchLimit)
                {
                    Debug.LogWarning("AStar Pathfinding Failed Due to Search Limit");
                    return(null);
                }

                //Find Successors
                for (int i = 0; i < 8; ++i)
                {
                    int successorX  = (ushort)(currentX + direction[i, 0]);
                    int successorY  = (ushort)(currentY + direction[i, 1]);
                    int successorXY = successorY * GridManager.Instance.GridWidth + successorX;

                    //Ignore non-navigable block
                    if (HasBlock(successorX, successorY))
                    {
                        continue;
                    }
                    //Ignore moving diagonal edge case- blocks perpendicular sides
                    if (direction[i, 0] != 0 && direction[i, 1] != 0)
                    {
                        if (HasBlock(currentX + direction[i, 0], currentY) &&
                            HasBlock(currentX, currentY + direction[i, 1]))
                        {
                            continue;
                        }
                    }


                    bool onGround  = HasBlock(successorX, successorY - 1);
                    bool atCeiling = HasBlock(successorX, successorY + 1);

                    bool currentOnGround = HasBlock(currentX, currentY - 1);

                    int jumpLength    = nodes[current.xy][current.z].JumpLength;                  //Grabs Old
                    int newJumpLength = -1;


                    //JumpLength is how long in the air, at max jump height, JumpLength is maxJumpHeight * 2
                    //This gives granularity to the stage of jump length
                    //Even JumpLength values means the character could go Up, Down, Right, Left
                    //Odd  JumpLength values means the character could go Up, Down

                    //////////////////////////////////////////
                    //--Find New Jump Length for Successor--//
                    //////////////////////////////////////////
                    //Reset to Zero
                    if (onGround)
                    {
                        newJumpLength = 0;
                    }

                    //Ceiling
                    else if (atCeiling)
                    {
                        if (successorX == currentX)                         //Fall Down
                        {
                            newJumpLength = (short)Mathf.Max(characterJumpHeight * 2, jumpLength + 2);
                        }
                        else                         //Slide Horizontal
                        {
                            newJumpLength = (short)Mathf.Max(characterJumpHeight * 2 + 1, jumpLength + 1);
                        }
                    }

                    //Going Up
                    else if (successorY > currentY)
                    {
                        if (jumpLength < 2)                         //Boost! Guarantees next move will go  --- not -- Up
                        {
                            newJumpLength = 2;
                        }
                        else
                        {
                            newJumpLength = NextEvenNumber(jumpLength);
                        }
                    }

                    //Going Down
                    else if (successorY < currentY)
                    {
                        newJumpLength = (short)Mathf.Max(characterJumpHeight * 2, NextEvenNumber(jumpLength));
                    }

                    //In-Air Side to Side
                    else if (successorX != currentX)
                    {
                        newJumpLength = jumpLength + 1;
                    }


                    //////////////////////////////////////////////////
                    //--Ignore Poor Successors Based On JumpLength--//
                    //////////////////////////////////////////////////
                    //If Odd, Ignore Right and Left Successors
                    if (jumpLength % 2 != 0 && successorX != currentX)
                    {
                        continue;
                    }

                    //If Falling, Make Sure Not Going Up
                    if (jumpLength >= characterJumpHeight * 2 && successorY > currentY)
                    {
                        continue;
                    }

                    //If Falling fast, Make Sure Not Going Sideways
                    if (newJumpLength >= characterJumpHeight * 2 + blocksFallenUntilCancelSideways &&
                        successorX != currentX)
                    {
                        continue;
                    }

                    if (onGround && !currentOnGround && successorX != currentX)
                    {
                        continue;
                    }

                    //If revisiting, only continue if it can add something new to the table

                    /*Debug.Log("SuccessorXY is " + successorXY + ". X = " + successorX + ". Y = " + successorY
                     + ". CurrentX = " + currentX + ". CurrentY = " + currentY
                     + ". Direction is "+direction[i,0]+","+direction[i,1]
                     + ". NewJumpLength is"+newJumpLength); */
                    if (nodes[successorXY].Count > 0)
                    {
                        int  lowestJump = short.MaxValue;
                        bool visitedCouldMoveSideways = false;
                        for (int j = 0; j < nodes[successorXY].Count; ++j)
                        {
                            if (nodes[successorXY][j].JumpLength < lowestJump)
                            {
                                lowestJump = nodes[successorXY][j].JumpLength;
                            }

                            if (nodes[successorXY][j].JumpLength % 2 == 0 &&
                                nodes[successorXY][j].JumpLength < characterJumpHeight * 2 + blocksFallenUntilCancelSideways)
                            {
                                visitedCouldMoveSideways = true;
                            }
                        }

                        //Ignore if already visited node has shorter jump length and provides more insight
                        if (lowestJump <= newJumpLength &&
                            (newJumpLength % 2 != 0 ||
                             newJumpLength >= characterJumpHeight * 2 + blocksFallenUntilCancelSideways ||
                             visitedCouldMoveSideways))
                        {
                            continue;
                        }
                    }

                    ////////////////////////////////////
                    //--Create and Add Node To Queue--//
                    ////////////////////////////////////
                    //Calculate costs
                    int successorCost = nodes[current.xy][current.z].G + (int)(newJumpLength * jumpDeterrentMultiplier);

                    int distToGoal = (int)(Math.Sqrt(Math.Pow((successorX - end.x), 2) + Math.Pow((successorY - end.y), 2)));

                    //Create Node
                    PFNode newNode = new PFNode();
                    newNode.JumpLength = newJumpLength;
                    newNode.PX         = currentX;
                    newNode.PY         = currentY;
                    newNode.PZ         = current.z;
                    newNode.G          = successorCost;
                    newNode.F          = successorCost + distToGoal;
                    newNode.Status     = nodeOpenValue;

                    if (nodes[successorXY].Count == 0)
                    {
                        traversedCoordinates.Push(successorXY);
                    }

                    nodes[successorXY].Add(newNode);
                    openLocations.Push(new Location(successorXY, nodes[successorXY].Count - 1));
                }

                //After adding all possible successors, mark current node as closed
                nodes[current.xy][current.z] = nodes[current.xy][current.z].UpdateStatus(nodeCloseValue);
                iterationCount++;
            }

            if (found)
            {
                List <Vector2> path = new List <Vector2>();
                int            posX = (int)end.x;
                int            posY = (int)end.y;

                PFNode fPrevNodeTmp = new PFNode();
                PFNode fNodeTmp     = nodes[endLocation.xy][0];

                Vector2 fNode     = end;
                Vector2 fPrevNode = end;

                int parentXY = fNodeTmp.PY * GridManager.Instance.GridWidth + fNodeTmp.PX;

                //Recursively Build Path
                while (fNode.x != fNodeTmp.PX || fNode.y != fNodeTmp.PY)
                {
                    PFNode fNextNodeTmp = nodes[parentXY][fNodeTmp.PZ];

                    //Filters out redundant nodes
                    if ((path.Count == 0) ||
                        (fNodeTmp.JumpLength == 3) ||
                        (fNextNodeTmp.JumpLength != 0 && fNodeTmp.JumpLength == 0) ||                                                                                                                               //mark jumps starts
                        (fNodeTmp.JumpLength == 0 && fPrevNodeTmp.JumpLength != 0) ||                                                                                                                               //mark landings
                        (fNode.y > path[path.Count - 1].y && fNode.y > fNodeTmp.PY) ||
                        (fNode.y < path[path.Count - 1].y && fNode.y < fNodeTmp.PY) ||
                        ((HasBlock(fNode.x - 1, fNode.y) || HasBlock(fNode.x + 1, fNode.y)) &&
                         fNode.y != path[path.Count - 1].y && fNode.x != path[path.Count - 1].x))
                    {
                        path.Add(fNode);
                    }


                    fPrevNode    = fNode;
                    posX         = fNodeTmp.PX;
                    posY         = fNodeTmp.PY;
                    fPrevNodeTmp = fNodeTmp;
                    fNodeTmp     = fNextNodeTmp;
                    parentXY     = fNodeTmp.PY * GridManager.Instance.GridWidth + fNodeTmp.PX;
                    fNode        = new Vector2(posX, posY);
                }

                path.Add(fNode);

                return(path);
            }

            Debug.LogWarning("AStar Pathfinding failed. Could not find path to goal. (" + end.x + "," + end.y + ")");
            return(new List <Vector2>());
        }
예제 #28
0
 public bool accessibilityAssessment(PFNode otherNode)
 {
     return(accessible = !Physics.Linecast(node.transform.position, otherNode.transform.position));
 }
예제 #29
0
        public async Task AStarAlgorithmSteppedAsync(AlgorithmState last = null)
        {
            // first time check
            if (last is null)
            {
                last = new AlgorithmState(new ObservableCollection <PFNode>(SquaresList), new List <PFNode>()
                {
                    PFNode.StartPoint
                }, PFNode.StartPoint, null);
                Debug.WriteLine($"Last:{Environment.NewLine}{last}");
                PFNode.StartPoint.Visited      = true;
                PFNode.StartPoint.PreviousNode = null;
                States.Add(CurrentState);
            }
            else
            {
                last = CurrentState;
            }
            // end condition
            if (last.CurrentlyChecking == PFNode.EndPoint)
            {
                Debug.WriteLine($"Solution found");
                solved = true;
                var curr = PFNode.EndPoint;

                for (; ;)
                {
                    if (curr.PreviousNode is null)
                    {
                        break;
                    }
                    if (curr != PFNode.StartPoint && curr != PFNode.EndPoint)
                    {
                        curr.VisualType = VisualSquareType.FinishPath;
                    }
                    curr = curr.PreviousNode;
                }
                return;
            }
            Debug.WriteLine($"Last checked square is not the endpoint, continue");

            // calculate current square
            PFNode currentlyChecking = last.Available[0];

            Debug.WriteLine($"Currently checking the square {currentlyChecking}");

            currentlyChecking.Visited = true;

            // get valid sorroundings
            List <PFNode> sorroundings = await CalculateSquareSorroundings(currentlyChecking);

            Debug.WriteLine($"Got sorroundings of {currentlyChecking}:");
            sorroundings = RemoveVisited(sorroundings);
            sorroundings.ForEach(x =>
            {
                if (x != PFNode.EndPoint && x != PFNode.StartPoint)
                {
                    x.VisualType = VisualSquareType.Sorrounding;
                }
            });
            sorroundings.ForEach(x =>
            {
                if (x.PreviousNode is null)
                {
                    x.PreviousNode = currentlyChecking;
                }
            });

            Debug.WriteLine($"Removed visited squares");
            last.Available.Remove(currentlyChecking);
            last.Available = last.Available.Distinct(new AStarSquareComparer()).ToList();

            var newAvailable = new List <PFNode>(last.Available);

            newAvailable.AddRange(sorroundings);
            RemoveVisited(newAvailable);
            newAvailable.Sort(new AStarSquareComparer());
            Debug.WriteLine($"Added last's sorroundings and removed all visited.");
            CurrentState = new AlgorithmState(SquaresList, newAvailable, currentlyChecking, last);
            States.Add(CurrentState);

            if (last.CurrentlyChecking != PFNode.StartPoint && last.CurrentlyChecking != PFNode.EndPoint)
            {
                last.CurrentlyChecking.VisualType = VisualSquareType.Visited;
            }
            if (currentlyChecking != PFNode.StartPoint && currentlyChecking != PFNode.EndPoint)
            {
                currentlyChecking.VisualType = VisualSquareType.Visited;
            }

            Debug.WriteLine("");
            Debug.WriteLine($"CurrentAmountOfSquares = {newAvailable.Count}");

            Step++;
            MaxStep++;

            //if (currentlyChecking != PFNode.StartPoint)
            //{
            //    currentlyChecking.PreviousNode = last.CurrentlyChecking;
            //}
            //else
            //{
            //    currentlyChecking.PreviousNode = null;
            //}
        }
예제 #30
0
 private bool SquareIsWalkable(PFNode s) => s.Type != SquareType.Bomb && s.Type != SquareType.Wall;
예제 #31
0
 public static int Compare(PFNode a, int b)
 {
     return(a.GetFcost() - b);
 }
예제 #32
0
    public List <Vector2> FindPath(Vector2Int from, Vector2Int to)
    {
        Debug.Log(string.Format("Finding path from ({0},{1}) to ({2},{3})", from.x, from.y, to.x, to.y));
        PFNode start = CreateInstance <PFNode>();

        start.pos      = from;
        start.gcost    = 0;
        start.hcost    = Dist(start.pos, to);
        start.backpath = null;
        Queue.Enqueue(start);

        int loops = 0;

        while (true)
        {
            if (loops >= 500)
            {
                Debug.LogError("TOO MANY LOOPS! BREAKING.");
                return(null);
            }

            PFNode cur = Queue.Dequeue();

            if (cur == null)
            {
                Debug.LogError("CAN'T FIND PATH");
                return(null);
            }

            Closed.Add(cur);

            if (cur.pos == to)
            {
                Debug.Log("FOUND DESTINATION");
                break;
            }

            int newGcost = cur.gcost + 1;
            for (int i = 0; i < 4; i++)
            {
                Vector2Int neighborPos = DirToValue(i) + cur.pos;
                if (tm.HasTile(new Vector3Int(neighborPos.x, neighborPos.y, 0)) || CloseContains(neighborPos))
                {
                    continue;
                }

                PFNode neighbor = Queue.Take(neighborPos);

                if (neighbor == null)
                {
                    neighbor       = ScriptableObject.CreateInstance <PFNode>();
                    neighbor.pos   = neighborPos;
                    neighbor.hcost = Dist(neighbor.pos, to);
                }
                else if (neighbor.gcost <= newGcost)
                {
                    continue;
                }

                neighbor.gcost    = newGcost;
                neighbor.backpath = cur.pos;
                if (neighbor.GetFcost() <= MaxFCost)
                {
                    Queue.Enqueue(neighbor);
                }
            }
            loops++;
        }

        PFNode            endNode  = Closed[Closed.Count - 1];
        List <Vector2Int> BackPath = new List <Vector2Int>();

        while (endNode != null)
        {
            BackPath.Insert(0, endNode.pos);
            endNode = FindInClosed(endNode.backpath);
        }

        return(FinalizePositions(BackPath));
    }
예제 #33
0
 public NodeNotSetException(PFNode node) : base($"Node {node} not set.")
 {
 }
예제 #34
0
    public void Enqueue(PFNode node)
    {
        int ind = InsertSearch(0, List.Count, node.GetFcost());

        List.Insert(ind, node);
    }