#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. На самом деле, поскольку у вас, скорее всего, будут создаваться объекты в одном и том же месте. Вам нужно будет вычислить расстояние только один раз для каждой точки возрождения. Затем назначьте расстояние до каждого объекта, который появляется в этой точке.