Подтвердить что ты не робот

Эффективное получение изометрических позиций сетки в ограничивающей коробке

Isometric Grid

У меня есть изометрическая сетчатая система, которая координирует начало с [0,0] в левом углу сетки (угол, показанный на приведенном выше изображении), где x увеличивается в сторону нижней части изображения, а y увеличивается в направлении вверх (поэтому [0, высота] будет верхним углом, а [ширина, 0] будет нижним углом в форме бриллианта с шириной и высотой, являющейся размером сетки, то есть 200 х 200 квадратов).

В любом случае мне нужна помощь в получении массива изометрических позиций сетки, которые содержатся в синем поле, показанном на изображении. За исключением повторения каждого x, y экрана pos и получения соответствующей позиции сетки (см. Этот вопрос, который я поставил ранее о том, как преобразовать из положения экрана в сетку positon Получить строку/столбец на изометрическая сетка.) Я не уверен, как добиться этого эффективно.

Возник вопрос, который я нашел ранее, это почти то же самое Ссылка здесь. Ответ состоял в том, чтобы сделать сетку изображением с разными цветами для каждого квадрата сетки а затем определить, какие цвета присутствовали под квадратом, я реализовал это решение, но он довольно медленный! Я почти думаю, что проверка положения сетки для каждого пикселя в окне выбора будет быстрее. Почему, почему javascript настолько медленен при циклировании!

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

Пожалуйста, дайте мне знать, если вам нужна дополнительная информация.

Изменить: К сожалению, предоставленные ответы не работали до сих пор, так как выбор похож на наличие выделенной области с бриллиантами на квадратной сетке, на самом деле нет верхнего левого, нижнего правого угла для повторения, если я не пропустил точку ответы? Я оптимизировал подход рендеринга, но при большом выборе, он по-прежнему добавляет заметное падение кадров, поскольку он проходит через весь цвет проверки пикселей и получает соответствующий квадрат

4b9b3361

Ответ 1

Линейная алгебра - это ответ. Здесь представлены две системы координат: координаты экрана и изометрические координаты. Преобразование углов выбранной области из экранных координат в изометрические координаты значительно поможет вам.

Пусть theta - угол между осями x и y изометрических координат, измеренный на экране, а единица - длина пикселя одного шага в изометрических координатах. Тогда

var c = Math.cos(theta/2);
var s = Math.sin(theta/2);
var origin = [oX, oY]; //the pixel coordinates of (0, 0)
var unit = 20;
var iso2Screen = function(iso) {
  var screenX = origin[0] + unit * (iso[0] * c + iso[1] * c);
  var screenY = origin[1] + unit * (iso[0] * -s + iso[1] * s);
  return [screenX, screenY];
}

Инвертируя это соотношение, получим

var screen2Iso = function(screen) {
  var isoX = ((screen[0] - origin[0]) / c - (screen[1] - origin[1]) / s) / unit;
  var isoY = ((screen[0] - origin[0]) / c + (screen[1] - origin[1]) / s) / unit;

Теперь преобразуйте координаты экрана каждого угла окна выбора в изометрические координаты и получите минимальные и максимальные значения x и y.

var cornersScreen = ...//4-element array of 2-element arrays
var cornersIso = [];
for(var i = 0; i < 4; i++) {
  cornersIso.push(screen2Iso(cornersScreen[i]));
}
var minX, maxX, minY, maxY;
minX = Math.min(cornersIso[0][0], cornersIso[1][0], cornersIso[2][0], cornersIso[3][0]);
maxX = Math.max(cornersIso[0][0], cornersIso[1][0], cornersIso[2][0], cornersIso[3][0]);
minY = Math.min(cornersIso[0][1], cornersIso[1][1], cornersIso[2][1], cornersIso[3][1]);
maxY = Math.max(cornersIso[0][1], cornersIso[1][1], cornersIso[2][1], cornersIso[3][1]);

Все выбранные изометрические точки лежат внутри изометрического блока [minX, maxX] x [minY, maxY], но не все точки в этом поле находятся внутри выделения.

Вы могли бы сделать много разных вещей, чтобы отсеять точки в этом поле, которые не находятся в выборе; Я предлагаю выполнить итерацию по целочисленным значениям изометрических x и y, преобразование изометрических координат в координаты экрана, а затем тестирование, чтобы увидеть, находится ли эта координата экрана в окне выбора, с помощью:

var sMinX, sMaxX, sMinY, sMaxY;
sMinX = Math.min(cornersScreen[0][0], cornersScreen[1][0], cornersScreen[2][0], cornersScreen[3][0]);
sMaxX = Math.max(cornersScreen[0][0], cornersScreen[1][0], cornersScreen[2][0], cornersScreen[3][0]);
sMinY = Math.min(cornersScreen[0][1], cornersScreen[1][1], cornersScreen[2][1], cornersScreen[3][1]);
sMaxY = Math.max(cornersScreen[0][1], cornersScreen[1][1], cornersScreen[2][1], cornersScreen[3][1]);
var selectedPoints = [];
for(var x = Math.floor(minX); x <= Math.ceil(maxX); x++) {
  for(var y = Math.floor(minY); x <= Math.ceil(maxY); y++) {
    var iso = [x,y];
    var screen = iso2Screen(iso);
    if(screen[0] >= sMinX && screen[0] <= sMaxX && screen[1] >= sMinY && screen[1] <= sMaxY) {
      selectedPoints.push(iso);
    }
  }
}

Ответ 2

Я участвую в играх XNA для хобби. Я работаю над классической 2D-игрой, основанной на квадратах (Project Squared). Эта ваша игра напомнила мне о моей работе, поэтому я решил помочь вам.

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

Сначала вы должны знать, какой квадрат (позиция на сетке) находится в начале "синего квадрата" (вероятно, поля выбора) и окончания выбора. Итак, теперь вы знаете начало и конец вашего списка.

Так как в вашей игре квадраты, вероятно, имеют статический размер (или вы увеличиваете масштаб камеры, но никогда не увеличиваете ширину/высоту), вы можете легко вычислить, какие квадраты находятся в вашем окне выбора.

Теперь вы знаете, что ваши квадраты перемещены на 45 ° r/l.

(Я говорю о XNA, например, coordsys - вверху 0,0)

If ( selectedStartSquare.selectionY <= square.height )
    startY = selectedStartSquare.selectionY
else startY = selectedStartSquare.selectionY + 1; 

if (selectedEndSquare.selectionY > square.height)
    endY = -||-.selectionY
else endY = -||- + 1;

это даст вам начальные и конечные индексы высоты квадратов. То же самое нужно сделать для индексов X.

Теперь у вас есть все, что нужно, чтобы получить все квадраты. Перейдите через X из выбранногоStartSquare.X в endX и введите Y с циклом из выбранногоStartSquare.Y в конец, но каждый раз меняйте начало (startYIndex ++ каждый цикл)

Это просто яркий пример, так как я никогда не работал с изометрическими играми. Это, вероятно, потребует некоторой настройки, но я "думаю!" это должно сработать. (Написал это перед сном и даже без бумаги, так как я уже был в постели... удачи)

Извините за мой английский, я из Хорватии, так что...

Ответ 3

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

Вот альтернатива:

Легкий способ уменьшить число квадратов сетки для проверки - найти координаты углов синего квадрата в сетчатых координатах. В вашем примере вам нужно будет только проверить квадраты, где 1<x<13 and 3<y<16.

alvaro дает короткий и краткий ответ как проверить, находится ли точка внутри поля.

Ответ 4

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

Например, если ваши плитки 32x16, вы начинаете в углу и двигаетесь вдоль 32, а затем, когда вы достигаете конца, пройдите по следующей строке.

tile spacing

например, в странном виде псевдокода...

var altRow = false;
var selectedTiles = [];
for (int y = selectorBox.top; y < selectorBox.top+selectorBox.height; y+=TILE_HEIGHT/2) {
    for (int x = selectorBox.left ; x < selectorBox.left+selectorBox.width; x+= TILE_WIDTH) {
        selectedTiles.add(tileAtPoint(x + (altRow ? - TILE_WIDTH/2 : 0), y);
    }
    altRow = !altRow;
}

Ответ 5

Мой подход, который я не видел никого другого: 1. Преобразуйте прямоугольник выбора в сетку (получите положение плитки каждого из углов) 2. Теперь мы имеем 2d-задачу, которая: находим все точки в преобразованном ромбе.

Это можно сделать аналогично: http://en.wikipedia.org/wiki/Flood_fill

Но может быть, что-то вроде этого лучше:

1. Start at the topmost
2. Go down
3. Go right until we encounter the edge (can be calculated from the rombus line)
4. Do the same thing but go left.
5. Go to 2 until we are at the middle
6. Go right and down.
7. Go right until we encouter the edge
8. Go left and down.
9. Go left until we encouter the edge
10. Go to 6 until we are at the bottom

В каждом плитке, который мы посещаем, мы добавляем его.

Теперь единственная проблема заключается в том, чтобы определить, встретили ли мы ребро...

Ответ 6

Я предполагаю, что вы можете получить координаты углов выбора, отображаемых на квадраты сетки iso. Это дает вам проблему построения графика с помощью простого алгебраического теста для решения. Если мы начнем с углов в изо-квадратах (x1, y1) и (x2, y2), мы знаем, что нам нужно протестировать вдоль линий с наклоном 1 и -1, проходящими через эти точки,

поэтому четыре строки: y-y1 = x-x1, y-y1 = x1-x, y-y2 = x-x2, y-y2 = x2-x. Они встречаются на изо-квадратах, содержащих углы поля выбора, с которого вы начали.

Если для удобства считать, что x2 и y2 больше, чем x1 и y1, нам нужно только перебирать изо-сетку для значений от x1 до x2 и y1 до y2, принимая только изо-квадраты, y-координаты меньше, чем обе "большие" линии, и меньше, чем две "меньшие" линии.