Бесконечный l oop в Unity при запуске кода поиска пути - PullRequest
0 голосов
/ 06 августа 2020

В моей пошаговой игре я пытаюсь заставить вражеские юниты найти путь к области, в которой они могут атаковать базу игроков. Когда я заканчиваю очередь на вызов DoActions(), Unity съедает мой процессор и перестает отвечать, поэтому я предполагаю, что написал бесконечное l oop. Однако я не могу найти причину проблемы в сценариях, которые я использовал для этого.

public class Pathfinding : MonoBehaviour
{

    public static List<Vector2> FindPath(Vector2 start, Vector2 goal, Unit unit)
    {
        PriorityQueue<double, Vector2> frontier = new PriorityQueue<double, Vector2>();
        Vector2 current;
        frontier.Enqueue(0, start);
        Dictionary<Vector2, Vector2> from = new Dictionary<Vector2, Vector2>();
        Dictionary<Vector2, double> cost_so_far = new Dictionary<Vector2, double>();
        cost_so_far[start] = 0;
        while (!frontier.IsEmpty)
        {
            current = frontier.Dequeue().Value;
            if (current == goal)
                break;
            foreach(Vector2 next in GetNeighborsCoor(current))
            {
                if (next.x < Tile.tilemap.GetLength(0) && next.y < Tile.tilemap.GetLength(1) && Building.FindBuildingAtCoor(next) == null)
                {
                    double cost = cost_so_far[current] + GetMoveCost(next, unit);
                    if (!from.ContainsKey(next))
                    {
                        cost_so_far[next] = cost;
                        frontier.Enqueue(cost, next);
                        from[next] = current;
                    }
                }
            }
        }
        current = goal;
        List<Vector2> path = new List<Vector2>();
        while(current != start)
        {
            path.Add(current);
            current = from[current];
        }
        path.Add(start);
        path.Reverse();
        return path;
    }
    public static List<Vector2> FindPathToArea(Vector2 start, List<Vector2> area, Unit unit)
    {
        PriorityQueue<double, Vector2> frontier = new PriorityQueue<double, Vector2>();
        Vector2 current;
        Vector2 goal = Vector2.negativeInfinity;
        frontier.Enqueue(0, start);
        Dictionary<Vector2, Vector2> from = new Dictionary<Vector2, Vector2>();
        Dictionary<Vector2, double> cost_so_far = new Dictionary<Vector2, double>();
        cost_so_far[start] = 0;
        while (!frontier.IsEmpty)
        {
            current = frontier.Dequeue().Value;
            if (area.Contains(current))
            {
                goal = current;
                break;
            }
            foreach(Vector2 next in GetNeighborsCoor(current))
            {
                if (next.x < Tile.tilemap.GetLength(0) && next.y < Tile.tilemap.GetLength(1) && Building.FindBuildingAtCoor(next) == null)
                {
                    double cost = cost_so_far[current] + GetMoveCost(next, unit);
                    if (!from.ContainsKey(next))
                    {
                        cost_so_far[next] = cost;
                        frontier.Enqueue(cost, next);
                        from[next] = current;
                    }
                }
            }
        }
        current = goal;
        List<Vector2> path = new List<Vector2>();
        while(current != start)
        {
            path.Add(current);
            current = from[current];
        }
        path.Add(start);
        path.Reverse();
        return path;
    }
    public static List<Vector2> GetNeighborsCoor(Vector2 coor)
    {
        List<Vector2> neighborsCoor = new List<Vector2>();
        neighborsCoor.Add(new Vector2(coor.x + 1, coor.y));
        neighborsCoor.Add(new Vector2(coor.x - 1, coor.y));
        neighborsCoor.Add(new Vector2(coor.x, coor.y + 1));
        neighborsCoor.Add(new Vector2(coor.x, coor.y - 1));
        return neighborsCoor;
    }
    public static double GetMoveCost(Vector2 coor, Unit unit)
    {
        double cost = 0;
        Building building = Building.FindBuildingAtCoor(coor);
        if(building == null)
        {
            cost = unit.apt / unit.speed;
        }
        else
        {
            cost = building.HP / unit.atk;
        }
        return cost;
    }
    public static Vector3 TransformCoor(Vector2 coor)
    {
        Vector3 position = Tile.tilemap[(int)coor.x, (int)coor.y].gameObject.transform.position;
        position.x = -1;
        return position;
    }
    public static List<Vector2> FindAreaToAttackFrom(Vector2 target, double range)
    {
        List<Vector2> area = new List<Vector2>();
        for (int x = 0; x < Tile.tilemap.GetLength(0); x++)
        {
            for (int y = 0; y < Tile.tilemap.GetLength(1); y++)
            {
                Vector2 current = new Vector2(x, y);
                if (Vector2.Distance(target, current) <= range)
                {
                    if(Building.FindBuildingAtCoor(current) == null && Unit.FindUnitAtCoor(current))
                    {
                        if(EnemyAI.CheckLineOfSight(current, target, 1, out List<Building> obstacles))
                        {
                            area.Add(current);
                        }
                    }
                }
            }
        }
        return area;
    }
}
public class EnemyAI : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Turn.OnTurnEnded += DoActions;
    }

    public void DoActions()
    {
        Building playerBase = Building.GetBaseOfOwner(0);
        foreach (Unit unit in Unit.myUnits)
        {
            if(unit.owner != 0 && unit.action != 0)
            {
                if(unit.range >= Vector2.Distance(playerBase.coor, unit.coor))
                {
                    bool clearLOS = CheckLineOfSight(unit.coor, playerBase.coor, 1, out List<Building> obstacles);
                    if (clearLOS)
                    {
                        playerBase.HP -= unit.atk * unit.action;
                    }
                    else
                    {
                        obstacles[0].HP -= unit.atk * unit.action;
                    }
                    unit.action = 0;
                }
                else
                {
                    while(unit.action != 0)
                    {
                        WalkPath(Pathfinding.FindPathToArea(unit.coor, Pathfinding.FindAreaToAttackFrom(playerBase.coor, unit.range), unit), unit);

                    }
                }
            }
        }
    }
    public void WalkPath(List<Vector2> path, Unit unit)
    {
        for (int step = 0; step <= unit.speed;)
        {
            if (Building.FindBuildingAtCoor(path[step]) == null)
            {
                if (step == unit.speed)
                {
                    Unit.MoveUnit(unit, path[step]);
                    unit.action -= 1;
                }
                else
                {
                    step++;
                }
            }
            else 
            {
                Building building = Building.FindBuildingAtCoor(path[step]);
                if (CheckLineOfSight(unit.coor, path[step], 1, out List<Building> obstacles))
                {
                    building.HP -= unit.atk * unit.action;
                    unit.action = 0;
                    break;
                }
                else
                {
                    Unit.MoveUnit(unit, path[step - 1]);
                    unit.action -= 1;
                    break;
                }
            }
        }
    }
    public static bool CheckLineOfSight(Vector2 from, Vector2 target, int actor, out List<Building> obstacles)
    {
        bool clear = true;
        obstacles = new List<Building>();
        RaycastHit[] hits = Physics.RaycastAll(Pathfinding.TransformCoor(from), Pathfinding.TransformCoor(target) - Pathfinding.TransformCoor(from));
        if (hits != null)
        {
            foreach (RaycastHit hit in hits)
            {
                if (hit.transform.GetComponent<Building>() != null)
                {
                    if ((hit.transform != Building.FindBuildingAtCoor(from).gameObject) && hit.transform != Building.FindBuildingAtCoor(target).gameObject)
                    {
                        Building building = hit.transform.GetComponent<Building>();
                        if (building.owner != actor)
                        {
                            obstacles.Add(building);
                            clear = false;
                        }
                    }
                }
            }
        }
        
        return clear;
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...