Beispiel #1
0
 Vector2int Pos2Cell(Pos pos)
 {
     // ArrayPos -> CellPos
     return(new Vector2int(pos.X + MinX, MaxY - pos.Y));
 }
Beispiel #2
0
        public List <Vector2Int> FindPath(Vector2Int startCellPos, Vector2Int destCellPos, bool checkObjects = true, int maxDist = 10)
        {
            List <Pos> path = new List <Pos>();

            // 점수 매기기
            // F = G + H
            // F = 최종 점수 (작을 수록 좋음, 경로에 따라 달라짐)
            // G = 시작점에서 해당 좌표까지 이동하는데 드는 비용 (작을 수록 좋음, 경로에 따라 달라짐)
            // H = 목적지에서 얼마나 가까운지 (작을 수록 좋음, 고정)

            // (y, x) 이미 방문했는지 여부 (방문 = closed 상태)
            HashSet <Pos> closeList = new HashSet <Pos>();

            // (y, x) 가는 길을 한 번이라도 발견했는지
            // 발견X => MaxValue
            // 발견O => F = G + H
            Dictionary <Pos, int> openList = new Dictionary <Pos, int>();
            Dictionary <Pos, Pos> parent   = new Dictionary <Pos, Pos>();

            // 오픈리스트에 있는 정보들 중에서, 가장 좋은 후보를 빠르게 뽑아오기 위한 도구
            PriorityQueue <PQNode> pq = new PriorityQueue <PQNode>();

            // CellPos -> ArrayPos
            Pos pos  = Cell2Pos(startCellPos);
            Pos dest = Cell2Pos(destCellPos);

            // 시작점 발견 (예약 진행)
            openList.Add(pos, 10 * (Math.Abs(dest.Y - pos.Y) + Math.Abs(dest.X - pos.X)));

            pq.Push(new PQNode()
            {
                F = 10 * (Math.Abs(dest.Y - pos.Y) + Math.Abs(dest.X - pos.X)), G = 0, Y = pos.Y, X = pos.X
            });
            parent.Add(pos, pos);

            while (pq.Count > 0)
            {
                // 제일 좋은 후보를 찾는다
                PQNode pqNode = pq.Pop();
                Pos    node   = new Pos(pqNode.Y, pqNode.X);
                // 동일한 좌표를 여러 경로로 찾아서, 더 빠른 경로로 인해서 이미 방문(closed)된 경우 스킵
                if (closeList.Contains(node))
                {
                    continue;
                }

                // 방문한다
                closeList.Add(node);
                // 목적지 도착했으면 바로 종료
                if (node.Y == dest.Y && node.X == dest.X)
                {
                    break;
                }

                // 상하좌우 등 이동할 수 있는 좌표인지 확인해서 예약(open)한다
                for (int i = 0; i < _deltaY.Length; i++)
                {
                    Pos next = new Pos(node.Y + _deltaY[i], node.X + _deltaX[i]);

                    // 너무 멀면 스킵
                    if (Math.Abs(pos.Y - next.Y) + Math.Abs(pos.X - next.X) > maxDist)
                    {
                        continue;
                    }

                    // 유효 범위를 벗어났으면 스킵
                    // 벽으로 막혀서 갈 수 없으면 스킵
                    if (next.Y != dest.Y || next.X != dest.X)
                    {
                        if (CanGo(Pos2Cell(next), checkObjects) == false)                         // CellPos
                        {
                            continue;
                        }
                    }

                    // 이미 방문한 곳이면 스킵
                    if (closeList.Contains(next))
                    {
                        continue;
                    }

                    // 비용 계산
                    int g = 0;                    // node.G + _cost[i];
                    int h = 10 * ((dest.Y - next.Y) * (dest.Y - next.Y) + (dest.X - next.X) * (dest.X - next.X));
                    // 다른 경로에서 더 빠른 길 이미 찾았으면 스킵

                    int value = 0;
                    if (openList.TryGetValue(next, out value) == false)
                    {
                        value = Int32.MaxValue;
                    }

                    if (value < g + h)
                    {
                        continue;
                    }

                    // 예약 진행
                    if (openList.TryAdd(next, g + h) == false)
                    {
                        openList[next] = g + h;
                    }

                    pq.Push(new PQNode()
                    {
                        F = g + h, G = g, Y = next.Y, X = next.X
                    });

                    if (parent.TryAdd(next, node) == false)
                    {
                        parent[next] = node;
                    }
                }
            }

            return(CalcCellPathFromParent(parent, dest));
        }
Beispiel #3
0
        public List <Vector2int> FindPath(Vector2int startCellPos, Vector2int destCellPos, bool checkObjects = true)
        {
            List <Pos> path = new List <Pos>();

            // 점수 매기기
            // F = G + H
            // F = 최종 점수 (작을 수록 좋음, 경로에 따라 달라짐)
            // G = 시작점에서 해당 좌표까지 이동하는데 드는 비용 (작을 수록 좋음, 경로에 따라 달라짐)
            // H = 목적지에서 얼마나 가까운지 (작을 수록 좋음, 고정)

            // (y, x) 이미 방문했는지 여부 (방문 = closed 상태)
            bool[,] closed = new bool[SizeY, SizeX];             // CloseList

            // (y, x) 가는 길을 한 번이라도 발견했는지
            // 발견X => MaxValue
            // 발견O => F = G + H
            int[,] open = new int[SizeY, SizeX];             // OpenList
            for (int y = 0; y < SizeY; y++)
            {
                for (int x = 0; x < SizeX; x++)
                {
                    open[y, x] = Int32.MaxValue;
                }
            }

            Pos[,] parent = new Pos[SizeY, SizeX];

            // 오픈리스트에 있는 정보들 중에서, 가장 좋은 후보를 빠르게 뽑아오기 위한 도구
            PriorityQueue <PQNode> pq = new PriorityQueue <PQNode>();

            // CellPos -> ArrayPos
            Pos pos  = Cell2Pos(startCellPos);
            Pos dest = Cell2Pos(destCellPos);

            // 시작점 발견 (예약 진행)
            open[pos.Y, pos.X] = 10 * (Math.Abs(dest.Y - pos.Y) + Math.Abs(dest.X - pos.X));
            pq.Push(new PQNode()
            {
                F = 10 * (Math.Abs(dest.Y - pos.Y) + Math.Abs(dest.X - pos.X)), G = 0, Y = pos.Y, X = pos.X
            });
            parent[pos.Y, pos.X] = new Pos(pos.Y, pos.X);

            while (pq.Count > 0)
            {
                // 제일 좋은 후보를 찾는다
                PQNode node = pq.Pop();
                // 동일한 좌표를 여러 경로로 찾아서, 더 빠른 경로로 인해서 이미 방문(closed)된 경우 스킵
                if (closed[node.Y, node.X])
                {
                    continue;
                }

                // 방문한다
                closed[node.Y, node.X] = true;
                // 목적지 도착했으면 바로 종료
                if (node.Y == dest.Y && node.X == dest.X)
                {
                    break;
                }

                // 상하좌우 등 이동할 수 있는 좌표인지 확인해서 예약(open)한다
                for (int i = 0; i < _deltaY.Length; i++)
                {
                    Pos next = new Pos(node.Y + _deltaY[i], node.X + _deltaX[i]);

                    // 유효 범위를 벗어났으면 스킵
                    // 벽으로 막혀서 갈 수 없으면 스킵
                    if (next.Y != dest.Y || next.X != dest.X)
                    {
                        if (CanGo(Pos2Cell(next), checkObjects) == false)                         // CellPos
                        {
                            continue;
                        }
                    }

                    // 이미 방문한 곳이면 스킵
                    if (closed[next.Y, next.X])
                    {
                        continue;
                    }

                    // 비용 계산
                    int g = 0;                    // node.G + _cost[i];
                    int h = 10 * ((dest.Y - next.Y) * (dest.Y - next.Y) + (dest.X - next.X) * (dest.X - next.X));
                    // 다른 경로에서 더 빠른 길 이미 찾았으면 스킵
                    if (open[next.Y, next.X] < g + h)
                    {
                        continue;
                    }

                    // 예약 진행
                    open[dest.Y, dest.X] = g + h;
                    pq.Push(new PQNode()
                    {
                        F = g + h, G = g, Y = next.Y, X = next.X
                    });
                    parent[next.Y, next.X] = new Pos(node.Y, node.X);
                }
            }

            return(CalcCellPathFromParent(parent, dest));
        }
Beispiel #4
0
        public List <Vector2Int> FindPath(Vector2Int startCellPos, Vector2Int destCellPos, bool checkObject = false, int maxDist = 10)
        {
            List <Pos> path = new List <Pos>();

            // 점수 매기기
            // F = G + H
            // F = 최종 점수 (작을수록 좋음.)
            // G = 시작점에서 해당 좌표까지 비용
            // H = 목적지에서 얼마나 가까운지


            // 방문 여부
            HashSet <Pos> closeList = new HashSet <Pos>(); // CloseList

            // (y,x) 가는 길을 한 번이라도 발견했나?
            // 발견x => maxVal
            // 발견o => F = G + H
            Dictionary <Pos, int> openList = new Dictionary <Pos, int>();

            Dictionary <Pos, Pos> parent = new Dictionary <Pos, Pos>();

            // 오픈 리스트에 있는 정보 중에서, 가장 좋은 후보를 빠르게 뽑기 위한 도구 (Heap 대신)
            PriorityQueue <PQNode> pq = new PriorityQueue <PQNode>();

            Pos pos  = Cell2Pos(startCellPos);
            Pos dest = Cell2Pos(destCellPos);


            // 시작점 발견 (예약 진행)
            openList.Add(pos, 10 * (Math.Abs(dest.Y - pos.Y) + Math.Abs(dest.X - pos.X)));

            pq.Push(new PQNode()
            {
                F = (Math.Abs(dest.Y - pos.Y) + Math.Abs(dest.X - pos.X)), G = 0, Y = pos.Y, X = pos.X
            });
            parent.Add(pos, pos);

            while (pq.Count > 0)
            {
                // 제일 좋은 후보를 찾는다.
                PQNode pqNode = pq.Pop();
                Pos    node   = new Pos(pqNode.Y, pqNode.X);

                // 동일한 좌표를 여러 경로로 찾아서, 더 빠른 경로로 인하여 이미 close에 담긴경우 스킵
                if (closeList.Contains(node))
                {
                    continue;
                }


                // 방문.
                closeList.Add(node);
                // 목적지다.
                if (node.Y == dest.Y && node.X == dest.X)
                {
                    break;
                }

                // 상하좌우 등 이동할 수 있는 좌표인지 확인하고 예약
                for (int i = 0; i < _deltaY.Length; i++)
                {
                    Pos next = new Pos(node.Y + _deltaY[i], node.X + _deltaX[i]);

                    // 너무 멀면 스킵
                    if (Math.Abs(pos.Y - next.Y) + Math.Abs(pos.X - next.X) > maxDist)
                    {
                        continue;
                    }

                    // 유효 범위를 벗어나면 스킵
                    // 벽으로 막혀도.

                    if (next.Y != dest.Y || next.X != dest.X)
                    {
                        if (CanGo(Pos2Cell(next), checkObject) == false)
                        {
                            continue;
                        }
                    }

                    if (closeList.Contains(next))
                    {
                        continue;
                    }

                    int g = 0; // node.G + _cost[i];
                    int h = 10 * ((dest.Y - next.Y) * (dest.Y - next.Y) + (dest.X - next.X) * (dest.X - next.X));

                    // 다른 경로에서 더 빠른 길 찾으면 스킵
                    int value = 0;
                    if (!openList.TryGetValue(next, out value))
                    {
                        value = Int32.MaxValue;
                    }

                    if (value < g + h)
                    {
                        continue;
                    }

                    // 예약 진행
                    if (openList.TryAdd(next, g + h) == false)
                    {
                        openList[next] = g + h;
                    }

                    pq.Push(new PQNode()
                    {
                        F = g + h, G = g, Y = next.Y, X = next.X
                    });

                    if (parent.TryAdd(next, node) == false)
                    {
                        parent[next] = node;
                    }
                }
            }

            return(CalcCellPathFromParent(parent, dest));
        }