2014-10-14 3 views
0

Я разрабатываю игровой сервер, и в настоящее время мне нужно, чтобы зрители были в зоне, однако я боюсь, что тот, который я использую, действительно уродлив и «медленный» «но я еще не испытывал никаких показов производительности, поскольку я тестирую его локально не на реальном сервере.Получить данные из массива X, Y, Z в пределах заданного радиуса

Это мой GetSpectators Функция:

public void GetSpectators(ref HashSet<Player> Players, Coordinate_t coordinate, bool MultiFloor = false) 
     { 
      for (int x = coordinate.X - 11; x != coordinate.X + 11; x++) 
      { 
       for (int y = coordinate.Y - 11; y != coordinate.Y + 11; y++) 
       { 
        if (MultiFloor) 
        { 
         for (int z = coordinate.Z - 2; z != coordinate.Z + 2; z++) 
         { 
          Tile tile = GetTile(x, y, z); 
          if (tile != null) 
          { 
           foreach (Player p in tile.Creatures) 
           { 
            Players.Add(p); 
           } 
          } 
         } 
        } 
        else 
        { 
         Tile tile = GetTile(x, y, coordinate.Z); 
         if (tile != null) 
         { 
          foreach (Player p in tile.Creatures) 
          { 
           Players.Add(p); 
          } 
         } 
        } 
       } 
      } 
     } 

Я этот класс Map, который держит этот другой словарь с классом плитки, каждая плитка представлена ​​с X, Y и координаты Z, каждая плитка содержит список этот класс называется Player, у некоторых плит есть игроки, которых нет.

мне нужен хороший способ, а не уродливые, чтобы получить например:

Все игроки в пределах х = 100, Y = 100, Z = 7 в радиусе 11, например.

+1

Не отвечаю на ваш вопрос: вам не нужно передавать 'Players'' ref', так как вы не назначаете новый экземпляр HashSet для 'Игроков' внутри метода. – kennyzx

+0

Кроме того, 'Игроки' должны быть' игроки', а 'MultiFloor' должен быть' multiFloor'. – Jedidja

ответ

1

Я думаю, что было бы разумно, чтобы ссылаться на плитки в вашем Player классе, если вы этого не делаете, а затем передать все игроки методу GetSpectators() ...

Что-то вроде ...

public class Player 
{ 
    // a reference to the tile that the player is currently on. 
    public Tile CurrentTile { get; set; } 
} 

Это позволит вам пройти через игроков, а не столько плит. И это должно быть более чистым и более эффективным, чтобы найти игроков так, как вы хотите, без всякой петли. Например:

public List<Player> GetSpectators(Hashset<Player> playersInGame, Coordinate coord) 
{ 
    var playersInRange = new List<Player>(); 

    // iterate through each player. 
    foreach (var p in playersInGame) 
    { 
     // check if the tile the player is sitting on is in range of radius given. 
     if ((p.CurrentTile.X < coord.X + 6 || p.CurrentTile.X > coord.X - 6) 
      && 
      (p.CurrentTile.Y < coord.Y + 6 || p.CurrentTile.Y > coord.Y - 6)) 
     { 
      // Player is within radius. 
      playersInRange.Add(p); 
     } 
    } 

    return playersInRange; 
} 

Вы можете добавить дополнительную проверку для координаты Z и любых других условных операторов. Но, как вы можете видеть, это позволит вам использовать один цикл, а не 3 вложенных цикла. Вы можете или не можете найти это полезным. Но я надеюсь, что это поможет.

+0

Спасибо! Это действительно спасло мою программу от 1 ~ 2% использования каждый раз, когда игрок переходил на плитки! ! –

0

Вы можете использовать уравнение окружности, чтобы проверить, находится ли игрок в заданном радиусе от другого игрока

т.е.
if 
x1=100,y1=100,z=7 and r=11 

then 
(x-x1)^2+(y-y1)^2+(z-z1)^2=r^2. 

любой точки, которые удовлетворяют этому уравнению будет лежать в области.

+0

Учитывая сказанное, что это *** круговое уравнение *** работает со всей квадратной площадью (например, на видимой карте игрока), это означает, что быстрее просто перебрать список , чем для (x ...? –

+0

Да, сложность времени будет равна O (n), где n - нет. Меньше, чем 3 вложенных цикла – SeeTheC