Как мне сохранить список объектов в пути по порядку?

#java #path #arraylist

#java #путь #arraylist

Вопрос:

Я работаю над игрой tower Defense и хочу, чтобы обороняющиеся башни стреляли по атакующему юниту, который находится дальше всех по пути в пределах его досягаемости. Я программирую его на Java и использую ArrayLists для хранения объектов.

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

Когда объект добавляется в блок, он добавляется в конец arraylist. Таким образом, объекты, которые были добавлены ранее, находятся в начале списка, а недавно добавленные объекты — в конце списка.

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

Это хорошая идея или мне следует попробовать что-то другое? Я могу опубликовать часть кода, если это поможет.

Ответ №1:

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

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

Вариант 1 (посредственный):

Используйте a, Map<Integer, Set<Enemy>> откуда берется целое число 0 - BLOCK_DEPTH , и каждый увидит врагов, перепрыгивающих из одного набора в другой. Здесь нет сортировки; просто перераспределение указателя. Вам также просто нужно сделать map.get(0) и добавить это в nextMap.get(BLOCK_DEPTH)

Вариант 2 (лучше?):

Используйте SortedSet , который реализует компаратор на основе Enemy.position, где position — целое число из 0 - BLOCK_DEPTH . У каждого врага есть прослушиватель, который обновляет его позицию по тику, а затем вы начинаете каждый тик, удаляя элементы из набора, в то время как Enemy.position равен 0, перенося их в следующий набор.

Комментарии:

1. Я внедряю ваш второй вариант прямо сейчас, похоже, он будет работать хорошо. Мой единственный вопрос в том, останется ли набор деревьев в порядке, даже если я обновлю позиции атакующих юнитов?

2. Я реализовал это с отдельным набором деревьев для каждого блока, и большую часть времени это работает, но иногда, когда блок пытается удалить объект из своего набора деревьев, этого не происходит. Через некоторые точки останова я вижу, что объект находится в наборе деревьев и передается следующему блоку, но каким-то образом treeset.remove(unit) возвращает false .

3. Я полагаю, что порядок в наборе деревьев вычисляется по мере необходимости — т. Е. Когда вы пытаетесь выполнить итерацию по нему или когда вы извлекаете наименьшее значение. Вот почему я думаю, что это работает для вас. ArrayList постоянно беспокоится о порядке. Вы заботитесь только о том, чтобы получить «наименьший» из каждого набора и переместить их в следующий. Если TreeSet.remove() возвращает false , это означает, что объект не был в этом наборе. Мне пришлось бы просмотреть код, чтобы выяснить, что там не так, хотя, возможно, это другая тема.

4. Спасибо за вашу помощь, я опубликовал новый вопрос о treeset.remove с частью кода. «Проблема с compareTo и TreeSet»

Ответ №2:

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

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

 public static double Get2DDistance(float x1, float y1, float x2, float y2) {
    float dx = x2 - x1;
    float dy = y2 - y1;
    double distance = Math.sqrt(dx * dx   dy * dy);
    return distance;
}
  

Комментарии:

1. На самом деле, поскольку у вас, скорее всего, будут создаваться объекты в одном и том же месте. Вам нужно будет вычислить расстояние только один раз для каждой точки возрождения. Затем назначьте расстояние до каждого объекта, который появляется в этой точке.