private MoveDirection ComputeDirection(OperationBluehole.Content.Int2D currentPos, OperationBluehole.Content.Int2D nextPos) { int xDiff = nextPos.x - currentPos.x; if (xDiff != 0) { if (xDiff > 0) { return(MoveDirection.Right); } else { return(MoveDirection.Left); } } int yDiff = nextPos.y - currentPos.y; if (yDiff != 0) { if (yDiff > 0) { return(MoveDirection.Up); } else { return(MoveDirection.Down); } } return(MoveDirection.Stay); }
public bool MovePlayer(Int2D position) { Int2D newPosition = position; // 임시 사용 중 // 해당 영역에 몬스터 있으면 덮어 쓰지 말고 다르게 처리할 것 // 전투를 하든가...뭐 그런 식으로 /* * while ( map[position.y, position.x].party != null ) * { * Int2D tempPosition; * tempPosition.x = newPosition.x + random.Next(-3, 3); * tempPosition.y = newPosition.y + random.Next(-3, 3); * * if ( map[position.y, position.x].objectType != MapObjectType.TILE || map[position.y, position.x].party != null ) * continue; * * newPosition = tempPosition; * } */ map[newPosition.y, newPosition.x].party = map[playerPosition.y, playerPosition.x].party; map[playerPosition.y, playerPosition.x].party = null; playerPosition = newPosition; return(true); }
// 맵 생성! private void GenerateMap(List <Party> mobs, List <Item> items, Party users) { // 맵 상의 임의의 영역에 대해서 // 각 영역은 멤버로 자신이 생성된 방향(horizontal, verical)과 영역좌표(AABB)를 가진다 // 부모 영역에 대한 참조와 트리에서의 depth정보도 가진다. // 만약 자신의 depth가 upper bound보다 작으면 아래의 작업을 수행한다 // 자신의 반대 방향으로 임의의 위치에서 다시 잘라서 해당 영역을 자식으로 추가 DungeonTreeNode root = new DungeonTreeNode(); root.SetRoot(size, random, map, mobs, items, zoneList, userLevel); root.GenerateRecursivly(); // player party와 ring 배치 - 맵 전체를 기반으로 RingOfErrethAkbe ring = new RingOfErrethAkbe(); playerPosition = root.RegisterParty(users, true); ringPosition = root.RegisterGameObject(ring); items.Add(ring); zoneList[map[ringPosition.y, ringPosition.x].zoneId].items.Add(ring); // PrintOutMAP(); // Console.WriteLine( "distance between player and ring" ); // Console.WriteLine( " :" + Math.Abs( playerPosition.x - ringPosition.x ) + " / "+ Math.Abs( playerPosition.y - ringPosition.y ) ); }
public int GetZoneId(Int2D position) { return(zoneList .Where(z => z.lowerBoundary.x <= position.x && position.x <= z.upperBoundary.x && z.lowerBoundary.y <= position.y && position.y <= z.upperBoundary.y) .Select(z => z.zoneId) .First()); }
public Int2D RegisterParty(Party party, bool isUsers = false) { Int2D position = new Int2D(-1, -1); while (true) { position = GetRandomInternalPosition(); if (map[position.y, position.x] != null && map[position.y, position.x].objectType == MapObjectType.TILE && map[position.y, position.x].party == null) { // 플레이어가 아이템 위에서 시작하지 않도록 제어 if (map[position.y, position.x].gameObject != null && isUsers) { continue; } map[position.y, position.x].party = party; party.position = position; break; } } return(position); }
public DungeonZone(int zoneId, Int2D lowerBoundary, Int2D upperBoundary) { this.zoneId = zoneId; this.lowerBoundary = lowerBoundary; this.upperBoundary = upperBoundary; centerPosition.x = (lowerBoundary.x + upperBoundary.x) / 2; centerPosition.y = (lowerBoundary.y + upperBoundary.y) / 2; }
public void Test() { Int2D start = new Int2D(); bool stop = false; for (int i = 0; i < mapSize; ++i) { for (int j = 0; j < mapSize; ++j) { if (dungeonMaster.GetMapInfo()[i, j].objectType == MapObjectType.TILE) { start.x = j; start.y = i; Teleport(start); Console.WriteLine("start : " + position.x + "," + position.y); stop = true; break; } } if (stop) { break; } } stop = false; Int2D end = new Int2D(); for (int i = mapSize - 1; i >= 0; --i) { for (int j = mapSize - 1; j >= 0; --j) { if (dungeonMaster.GetMapInfo()[i, j].objectType == MapObjectType.TILE) { end.x = j; end.y = i; Console.WriteLine("dest : " + end.x + "," + end.y); var runningTime = Stopwatch.StartNew(); MakePath(end); Console.WriteLine("[Simulation : " + runningTime.ElapsedMilliseconds + " ms]"); stop = true; break; } } if (stop) { break; } } }
public void Init(Int2D position) { isRingDiscovered = false; this.position = position; // 존 방문 기록도 업데이트하고, 첫 movePath 계산도 해둔다 currentZoneId = dungeonMaster.GetZoneId(position); dungeonZoneHistory.Push(currentZoneId); exploredZone.Add(currentZoneId); UpdateDestination(); }
// 조심해! // FOR DEBUG!!!! public void Teleport(Int2D destination) { position = destination; // 현재 존 정보 업데이트 할 것 int currentZoneId = dungeonMaster.GetZoneId(position); if (currentZoneId != dungeonZoneHistory.Peek()) { dungeonZoneHistory.Push(currentZoneId); exploredZone.Add(currentZoneId); } }
private void AllocateObjects(DungeonZone zone) { // 아이템과 몹 배치 int tileCount = (upperBoundary.y - lowerBoundary.y - 1) * (upperBoundary.x - lowerBoundary.x - 1); int mobCount = (int)(tileCount * Config.MOB_DENSITY); for (int i = 0; i < mobCount; ++i) { // 몹 생성하고 mobs.Add(GeneratoMobParty()); int idx = mobs.Count - 1; zone.mobs.Add(mobs[idx]); // 등록 Int2D mobPosition = RegisterParty(mobs[idx]); } int itemCOunt = (int)(tileCount * Config.ITEM_DENSITY); for (int i = 0; i < itemCOunt; ++i) { // 아이템 생성하고 Item newItem = new ItemToken(); ((ItemToken)newItem).GenerateRandomToken( usersLevel + random.Next( (int)(-usersLevel * Config.MOB_REWARD_ITEM_RANGE), (int)(usersLevel * Config.MOB_REWARD_ITEM_RANGE) ), ItemToken.equipTypePool[random.Next(ItemToken.equipTypePool.Length)]); items.Add(newItem); int idx = items.Count - 1; zone.items.Add(items[idx]); // 등록 Int2D itemPosition = RegisterGameObject(items[idx]); } }
public Int2D RegisterGameObject(GameObject obj) { Int2D position = new Int2D(-1, -1); while (true) { position = GetRandomInternalPosition(); if (map[position.y, position.x] != null && map[position.y, position.x].objectType == MapObjectType.TILE && map[position.y, position.x].gameObject == null) { // 조심해! // item에 자신의 idx 기록은 안 해도 되려나... map[position.y, position.x].gameObject = obj; obj.position = position; break; } } return(position); }
public int GetZoneId(Int2D position) { return(dungeon.GetZoneId(position)); }
public Int2D(Int2D rhs) { this.x = rhs.x; this.y = rhs.y; }
private void MakePath(Int2D destination) { // Debug.WriteLine( "start to make the path" ); // Debug.WriteLine( "start : " + position.x + " / " + position.y ); // Debug.WriteLine( "dest : " + destination.x + " / " + destination.y ); // 조심해!!! // priority_queue가 없어서 일단 list로 구현 // List<ExploerNode> openSet = new List<ExploerNode>(); MinHeap <ExploerNode> openSet = new MinHeap <ExploerNode>(); for (int i = 0; i < mapSize; ++i) { for (int j = 0; j < mapSize; ++j) { map[i, j].Reset(); } } map[position.y, position.x].gScore = 0; map[position.y, position.x].fScore = map[position.y, position.x].gScore + GetHeuristicScore(position, destination); map[position.y, position.x].isOpened = true; // openSet.Add( map[position.y, position.x] ); openSet.Push(map[position.y, position.x]); while (openSet.Count > 0) { // ExploerNode current = openSet.Min(); ExploerNode current = openSet.Peek(); // Debug.WriteLine( "current : " + current.position.x + " / " + current.position.y ); if (current.position.Equals(destination)) { currentMovePath.Push(currentDestination); // 최종 목적지를 일단 넣고 그 사이를 채움 ReconstructPath(current); currentMovePath.Pop(); // 현재 위치는 빼자 break; } // openSet.Remove( openSet.Min() ); openSet.Pop(); current.isClosed = true; // 조심해! // 배열을 하나 새로 만드는 것이 어색하다 // 맨 끝 지점들에는 안 가니까 예외 처리는 생략 List <ExploerNode> neigborNodes = new List <ExploerNode> { map[current.position.y - 1, current.position.x], map[current.position.y + 1, current.position.x], map[current.position.y, current.position.x - 1], map[current.position.y, current.position.x + 1] }; for (int i = 0; i < neigborNodes.Count; ++i) { ExploerNode neighbor = neigborNodes[i]; if (neighbor.isClosed) { continue; } float gScoreTentative = current.gScore + Math.Abs(destination.x - current.position.x) + Math.Abs(destination.y - current.position.y); if (!neighbor.isOpened || gScoreTentative < neighbor.gScore) { neighbor.cameFrom = current; neighbor.gScore = gScoreTentative; neighbor.fScore = neighbor.gScore + GetHeuristicScore(neighbor.position, destination); if (!neighbor.isOpened) { neighbor.isOpened = true; // openSet.Add( neighbor ); openSet.Push(neighbor); } else { openSet.DecreaseKeyValue(neighbor); } // openSet.Sort( new NodeComp() ); } } } // Debug.WriteLine( "end!!!!" ); }
private float GetHeuristicScore(Int2D target, Int2D goal) { return((float)Math.Sqrt(Math.Pow(goal.x - target.x, 2) + Math.Pow(goal.y - target.y, 2))); // return Math.Abs( goal.x - target.x ) + Math.Abs( goal.y - target.y ); }
public bool Move(MoveDiretion direction, GameRecord record) { switch (direction) { case MoveDiretion.DOWN: position = new Int2D(position.x, position.y + 1); break; case MoveDiretion.LEFT: position = new Int2D(position.x - 1, position.y); break; case MoveDiretion.RIGHT: position = new Int2D(position.x + 1, position.y); break; case MoveDiretion.UP: position = new Int2D(position.x, position.y - 1); break; default: break; } // 일단 도착했으니까 제거 if (position.Equals(currentMovePath.Peek())) { currentMovePath.Pop(); } // 몹이 있는지 확인한다 // 있으면 일단 전투부터 요청 Party target = dungeonMaster.GetMapObject(position.x, position.y).party; if (target != null && target.partyType == PartyType.MOB) { if (!dungeonMaster.StartBattle(target)) { record.lastPosition = position; return(false); } } // 아이템 있는지 확인한다 Item item = (Item)dungeonMaster.GetMapObject(position.x, position.y).gameObject; if (item != null) { if (item.code == ItemCode.Ring) { isRingDiscovered = true; } else { dungeonMaster.LootItem(item, currentZoneId); UpdateDestination(); } } // 현재 존 정보 업데이트 할 것 int newZoneId = dungeonMaster.GetZoneId(position); if (currentZoneId != newZoneId) { // 영역이 바뀌었다! currentZoneId = newZoneId; UpdateDestination(); // 처음 가보는 곳이면 일단 스택에도 넣고, 가봤다고 기록도 하자 if (!exploredZone.Contains(currentZoneId)) { dungeonZoneHistory.Push(currentZoneId); exploredZone.Add(currentZoneId); } } return(true); }