예제 #1
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));
        }
예제 #2
0
 Pos Cell2Pos(Vector2Int cell)
 {
     // CellPos -> ArrayPos
     return(new Pos(MaxY - cell.y, cell.x - MinX));
 }
예제 #3
0
        public bool ApplyMove(GameObject gameObject, Vector2Int dest, bool checkObjects = true, bool collision = true)
        {
            if (gameObject.Room == null)
            {
                return(false);
            }

            if (gameObject.Room.Map != this)
            {
                return(false);
            }


            PositionInfo posInfo = gameObject.PosInfo;

            if (CanGo(dest, checkObjects) == false)
            {
                return(false);
            }

            if (collision)
            {
                {
                    int x = posInfo.PosX - MinX;
                    int y = MaxY - posInfo.PosY;

                    if (_objects[y, x] == gameObject)
                    {
                        _objects[y, x] = null;
                    }
                }
                {
                    int x = dest.x - MinX;
                    int y = MaxY - dest.y;
                    _objects[y, x] = gameObject;
                }
            }

            // Zone
            GameObjectType type = ObjectManager.GetObjectTypeById(gameObject.Id);

            if (type == GameObjectType.Player)
            {
                Player player = (Player)gameObject;

                Zone now   = gameObject.Room.GetZone(gameObject.CellPos);
                Zone after = gameObject.Room.GetZone(dest);

                if (now != after)
                {
                    now.Players.Remove(player);
                    after.Players.Add(player);
                }
            }
            else if (type == GameObjectType.Monster)
            {
                Monster monster = (Monster)gameObject;

                Zone now   = gameObject.Room.GetZone(gameObject.CellPos);
                Zone after = gameObject.Room.GetZone(dest);

                if (now != after)
                {
                    now.Monsters.Remove(monster);
                    after.Monsters.Add(monster);
                }
            }
            else if (type == GameObjectType.Projectile)
            {
                Projectile projectile = (Projectile)gameObject;

                Zone now   = gameObject.Room.GetZone(gameObject.CellPos);
                Zone after = gameObject.Room.GetZone(dest);

                if (now != after)
                {
                    now.Projectiles.Remove(projectile);
                    after.Projectiles.Add(projectile);
                }
            }



            // 실제 좌표 이동
            posInfo.PosX = dest.x;
            posInfo.PosY = dest.y;

            return(true);
        }