Рассчитать значения окружности - PullRequest
4 голосов
/ 25 октября 2011

У меня есть прямоугольная карта, хранящаяся в виде многомерного массива (т. Е. $map[row][col]), и я должен отследить, какие квадраты видит игрок, расположенные в любом месте на этой карте.

Видимость игрока круговая с неизвестным радиусом (но указывается во время выполнения), и мне нужны только целочисленные решения.

Я знаю, что формула окружности

x^2 + y^2 <= r^2

, но как я могу сохранить все?
Мне нужны эти значения, так как я могу "показать" квадраты карты.


Лучше всего будет многомерный массив (т. Е. __$sol[x][y]__).
Это фрагмент кода, который я использую.Это не исправлено, поскольку предполагается, что зрение - это квадрат, а не круг.

Расчет квадрата

$this->vision_offsets_2 = array();
//visibility given as r^2
$mx = (int)(sqrt($this->viewradius2));

$mxArr = range($mx * -1, $mx + 1);
foreach ($mxArr as $d_row)
{
    foreach ($mxArr as $d_col)
    {
         $this->vision_offsets_2[] = array($d_row, $d_col);
    }
}

Вот как я применяю это

    foreach($player as $bot)
    {
        foreach($visibility as $offset)
        {
            $vision_row = $offset[0] + $bot[0];
            $vision_col = $offset[1] + $bot[1];

            if(isset($map[$vision_row][$vision_col]))
            {
                if( $map[$vision_row][$vision_col] == UNSEEN) {
                    $map[$vision_row][$vision_col] =  LAND; }
            }
        }
    }

Здесь вы можете найти вид бота: как вы видите, это не идеальный круг.
Как я могу отследить его?Кстати, в этом примере радиус ^ 2 равен 55, оранжевый круг - игрок, коричневые квадраты - видимые.

bot view

Ответы [ 4 ]

1 голос
/ 25 октября 2011

Структура

Вы уже ссылаетесь на ландшафт в сетке.Сохраните объекты ландшафта в этих значениях сетки.Примените атрибуты к этим объектам.Проверьте что-то вроде

$map[$x][$y]->isVisible($player);

. Вам понадобятся некоторые методы для настройки зрения и тесты для проверки пользователя, который передается по списку пользователей, которые могут его видеть.Пока вы занимаетесь этим, настройте другие связанные методы в этих объектах (я вижу ссылки на землю ... isLand() и isWater() возможно?).

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

Math

Нам дана окружность.

double diameter = circumference / 3.14159
double radius = diameter / 2 //Normally done in one step / variable

Теперь мы должны знать расстояние между двумя точками, чтобы сравнить его.Давайте используем карту [4] [7] и карту [3] [9].

int x0 = 4;
int y0 = 7;
int x1 = 3;
int y1 = 9;

double distance = Math.sqrt(
        Math.pow(x0 - x1, 2) + 
        Math.pow(y0 - y1, 2)
        );

System.out.println(distance); //2.23606797749979

Тест distance > radius.

Тестирование каждого квадрата

  • Поместите вышеприведенное в метод: visibleFrom(Square target)
    • radius должна быть глобально доступной статической переменной при сравнении.
    • Ваш Square объект должен быть в состоянии передать свои координаты.
      • target.getX()
      • target.getY()
  • Можно выполнить некоторые оптимизации
    • Только проверять вещидля кругового расстояния, когда они находятся в квадрате.
    • Не проверяя ничего для кругового расстояния, когда чисто вдоль оси x или y.
    • Вычисление наибольшего квадрата, который вписывается внутрькруг и не отмеченные флажки в этом диапазоне для кругового расстояния.
  • Помните, что преждевременная оптимизация и переоптимизация - ловушки.
0 голосов
/ 25 октября 2011

Функция, подобная этой, скажет вам, видим ли квадрат карты (используя расстояние от центров квадратов в качестве метрики; если вы хотите определить видимость другим способом, что, вероятно, будет, вещи станут намного сложнее ):

function is_visible($mapX, $mapX, $playerX, $playerY, $r) {
    return sqrt(pow($mapX - $playerX, 2) + pow($mapY - $playerY, 2)) <= $r;
}

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

0 голосов
/ 25 октября 2011

Я думаю, что алгоритм рисования кругов Брезенхэма - это то, что вы ищете.

0 голосов
/ 25 октября 2011

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

 //You mentioned circumference, this will find out the circumference but I don't 
 //think you actually need it.
 $circumference_length = 2 * $visibility_range * 3.1415;

 //Plug in the player and target coordinates and how far you can see, this will
 //tell you if the player can see it.  This can be optimized using your object 
 //and player Objects.
 function canSee($player_x, $player_y, $vision_length, $target_x, $target_y){
      $difference_x = $target_x - $player_x;
      $difference_y = $target_y - $player_y;
      $distance = sqrt((pow($difference_x,2) + pow($difference_y, 2));

      if($vision < $distance){
          return false;
      } else {
          return true;
      } 

 }

Редактировать: В ответ на ваше разъяснение вы можете использовать вышеуказанную функцию, чтобы выяснить, следует ли показывать объекты местности или нет.

foreach($player as $bot)
{
    foreach($terrain_thing as $terrain)
    {
        //ASSUMING THAT [0] IS ALWAYS X AND [1] IS ALWAYS y, set a third variable
        //to indicate visibility
        $terrain["is_visible"] = canSee($bot[0], $bot[1], $visibility_range, $terrain[0], $terrain[1])


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