2013-07-08 2 views
0

После прочтения Red Blob Games «отлично» article on heaxgon tile maps and their coordinates.Запрос на «окружающие гексагональные плитки» на основе осевых координат

Мне интересно, как можно было бы написать SQL-запрос, который возвращает плитки вокруг центрированной плитке до диапазона X. (предполагая, что «осевой координаты» рассматривается в статье)

Простая идея, которую я первый был был

WHERE x BETWEEN tile_x - 1 AND tile_x + 1 AND y BETWEEN tile_y - 1 AND tile_y + 1 

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

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

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

+0

без вложения * реальный * мысли в этом, вам нужно добавить дополнительный test - «разделяет край с плиткой». – GalacticCowboy

ответ

0

После некоторых более чтений, я обнаружил, что в статье я связан на самом деле alread решает эту проблему, хотя и несколько скрытый, так что вот более «прямой» ответ.

(Тем не менее, Терье Д.Ответ на него работает нормально, я просто публикую это, потому что чувствую, что это немного легче понять, чем «колдовство» его ответа)

В article from Red Blob Games он фактически описывает формулу, которая вычисляет расстояние между двумя заданными гексами:

function hex_distance(Hex(q1, r1), Hex(q2, r2)) { 
    return (abs(q1 - q2) + abs(r1 - r2) 
      + abs(q1 + r1 - q2 - r2))/2; 
} 

Я перевел это в функцию в MySQL

CREATE FUNCTION `rangeBetweenTiles`(tile1q int, tile1r int, tile2q int, tile2r int) RETURNS int(11) 
DETERMINISTIC 
BEGIN 
RETURN (abs(tile1q - tile2q) + abs(tile1r - tile2r) 
     + abs(tile1q + tile1r - tile2q - tile2r))/2; 
END 

И использовать это в другой функции:

CREATE FUNCTION `isInRange`(tile1q int, tile1r int, tile2q int, tile2r int, `range` Int) RETURNS tinyint(1) 
DETERMINISTIC 
BEGIN 
RETURN rangeBetweenTiles(tile1q, tile1r, tile2q, tile2r) <= `range`; 
END 

, которые затем могут быть использованы очень легко в операторе отбора:

select * 
from tiles 
where isInRange(:tile_q, :tile_r, positionQ, positionR, :n) 

И это работает прекрасно для любого :n

1

Из диаграмм в связанной статье, кажется, что-то вроде

where (x between tile_x and tile_x + 1) and (y between tile_y - 1 and tile_y + 1) 
or (x = tile_x - 1) and (y = tile_y) 

должен работать

Если вы хотите, чтобы найти плитку (tile_x, tile_y) в пределах расстояния n от данной плитки (x, y), он будет проще, если координата x будет изменена путем добавления 0.5 в координату x каждой строки, имеющей нечетное расстояние от данной плитки, так что симметрия увеличивается:

 -1.5 -0.5 0.5 1.5             
     -2 -1 0 1 2             
    -2.5 -1.5 -0.5 0.5 1.5 2.5            
-3 -2 -1 0 1 2 3            
    -2.5 -1.5 -0.5 0.5 1.5 2.5            
     -2 -1 0 1 2             
     -1.5 -0.5 0.5 1.5             

Это может быть достигнуто с помощью выражения tile_x + 0.5 * tile_y%2

По мере увеличения числа плиток в пределах заданного расстояния уменьшается на одну
от строки к строке, пределы (модифицированный) координаты х в заданном
строка - n - abs(tile_y - y)/2.

Тогда плитка находится на расстоянии п, если

abs(tile_y - y) <= n              
and abs(tile_x - x + 0.5 * (tile_y-y)%2) <= n - abs(tile_y - y)/2    

В SQL:

SELECT tile_x, tile_y              
FROM tiles                 
WHERE ABS(tile_y - y) <= n             
AND ABS(tile_x - x +0.5*(tile_y-y)%2) + ABS(tile_y - y)/2 <= n    
+0

Это хорошо работает для 'n = 1', но когда я пытаюсь использовать его для' n = 2', это дает мне очень странные результаты - количество возвращаемых фрагментов верное (19), но оно также возвращает меня, например. '(-2, -1)', который, если вы посмотрите на диаграмму, находится не в диапазоне от 2 до центра (0,0) –

+0

@Florian Peschka Как диаграмма имеет нули в нечетных рядах строк _right_ из остальных, 0,5 следует _added_, а не вычитаться. Соответственно, ответ исправляется. –

+0

Отлично, спасибо .. –