Определение конечного местоположения для движения ИИ в группах в 2D RTS

8

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

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

  • Попытка 1: Скажите всем выбранным солдатам, чтобы они двигались к координатам, по которым щелкала мышь. Это имеет странное поведение, что все солдаты сгруппируются вокруг цели неестественно.
  • Попытка 2: найдите средние координаты всех выбранных солдат, затем найдите смещение от этой центральной точки для каждого солдата и, наконец, переведите это смещение вокруг координат мыши. Это прекрасно работает, за исключением того, что если выбранные вами солдаты находятся далеко друг от друга, они не приблизятся к цели.
  • Попытка 3: Постройте сетку вокруг координат мыши и поместите каждого выбранного солдата в ячейку сетки. Если каждый солдат добирается до назначенной клетки, это прекрасно работает. Однако солдат назначают в ячейки сетки в том порядке, в котором они были созданы, поэтому иногда они сталкиваются (т.е. все солдаты с правой стороны будут пытаться перейти на левую сторону), что выглядит неестественно.
  • Попытка 4: используйте сетку, как раньше, но сначала рассортируйте солдат по локации, чтобы они выстроились в линию, то есть, если вы нажмете ниже группы, то солдаты в нижней части группы окажутся в нижней части сетки, когда они достичь их назначения. Это работает довольно хорошо, но иногда случаются глюки, и я не уверен, почему.

Вот функция, которая определяет координаты пункта назначения:

function moveSelectedSoldiersToMouse() {
  var w = 0, h = 0, selected = [];
  // Get information about the selected soldiers.
  myTeam.soldiers.forEach(function(soldier) {
    if (soldier.selected) {
      selected.push(soldier);
      w += soldier.width;
      h += soldier.height;
    }
  });
  var numSelected = selected.length, k = -1;
  if (!numSelected) return;
  // Build a grid of evenly spaced soldiers.
  var sqrt = Math.sqrt(numSelected),
      rows = Math.ceil(sqrt),
      cols = Math.ceil(sqrt),
      x = Mouse.Coords.worldX(),
      y = Mouse.Coords.worldY(),
      iw = Math.ceil(w / numSelected), // grid cell width
      ih = Math.ceil(h / numSelected), // grid cell height
      wg = iw*1.2, // width of gap between cells
      hg = ih*1.2; // height of gap between cells
  if ((rows-1)*cols >= numSelected) rows--;
  w = iw * cols + wg * (cols-1); // total width of group
  h = ih * rows + hg * (rows-1); // total height of group
  // Sort by location to avoid soldiers getting in each others' way.
  selected.sort(function(a, b) {
    // Round to 10's digit; specific locations can be off by a pixel or so
    var ax = a.x.round(-1), ay = a.y.round(-1), bx = b.x.round(-1), by = b.y.round(-1);
    return ay - by || ax - bx;
  });
  // Place the grid over the mouse and send soldiers there.
  for (var i = 0; i < rows; i++) {
    for (var j = 0; j < cols; j++) {
      var s = selected[++k];
      if (s) {
        var mx = x + j * (iw+wg) - w * 0.5 + s.width * 0.5,
            my = y + i * (ih+hg) - h * 0.5 + s.height * 0.5;
        // Finally, move to the end destination coordinates
        s.moveTo(mx, my);
      }
    }
  }
}

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

У меня вопрос: есть ли лучший способ определить местоположение цели для каждого солдата, чтобы перейти к?

IceCreamYou
источник
То, что называется «стекаются», может быть очень полезным для вас и может предоставить вам тот тип функциональности, который вы ищете. Попробуйте: processing.org/examples/flocking.html или просто Google "flocking" или "Boids". Это может привести вас в правильном направлении.
Дин Найт
2
Связанный: gamedev.stackexchange.com/questions/44361 Я бы сказал, что "глюки", которые вы испытываете, происходят от юнитов, которые пытаются перейти в положение, которое уже было заявлено. Убедитесь, что позиция, в которую они перемещаются, уже не является целью для другого подразделения, и у вас должны быть довольно приличные результаты.
MichaelHouse
@DeanKnight, я знаю о том, как работает поведение флокирования, но это определяет, как боты попадают из точки А в точку Б, а не какова точка В.
IceCreamYou
@ Byte56: спасибо за ссылку. Я не буквально помещаю единицы в слоты сетки - в реализации нет возможности для нескольких единиц быть направленными в одно и то же место. Похоже, проблема в том, что сортировка иногда путается.
IceCreamYou
1
Другая идея: поиск роя роев . В этом случае вы не дадите каждому юниту другую конечную точку; вы бы просто остановили их, когда не было пути к конечной точке (потому что все другие блоки находятся на пути), или вообще не останавливались бы, и обнаружение столкновений выполняло свою работу.
BlueRaja - Дэнни Пфлугхофт

Ответы:

2

Вот мои предложения по вашим идеям:

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

Попытка 2: исправление для этого было бы взять среднее расстояние группы друг от друга, а затем сократить расстояние выбросов к этому, чтобы группа оказалась более сгруппированной, чем они были первоначально (метрика могла быть короче / дольше, чем в среднем, что бы это ни выглядело прилично, или, возможно, снова установите максимальный размер формы, исходя из количества / размера войск). Единственное, о чем вам следует беспокоиться, это когда вы изменяете путь выброса, вы ' Я должен проверить и убедиться, что он не мешает другим путям

Попытка 3: вы улучшили это в попытке 4

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

Попытка 4 кажется наиболее близкой к устранению фрезерного поведения в вашей задаче, но с точки зрения поддержания движения без каких-либо регулировок, кроме необходимых, моей любимой будет, вероятно, попытка 2.

Но как совершенно другое решение, вы можете иметь два типа объектов, когда дело доходит до поиска пути; каждый юнит, а также невидимый «отряд» объекта.

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

Юниты - Юниты полностью игнорируют цель и вместо этого используют поиск пути, чтобы держаться в пределах определенного расстояния (или формация, или любая другая метрика, заканчивающая тем, что движение выглядит лучше) от объекта отряда.

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

Дэвид М
источник
Отличный ответ. Спасибо за новые идеи. Подход Squad + Unit интересен, вероятно, требует, чтобы юниты могли двигаться быстрее в режиме «догоняющего»
IceCreamYou
Да, решение там - установить скорость движения объекта «отряда» немного ниже максимума, который могут перемещать отдельные юниты, чтобы позволить им перемещаться, если необходимо, не отставая.
Дэвид М
2

Попытка 3 может сработать, но она требует некоторой доработки.

Подумайте о концепции формирования (ваша сетка - это начало). Формация должна иметь местоположение (то есть координаты щелчка, или целевой солдат / здание) и вращение (это может быть фиксированным, случайным или детерминированным). Формирование должно иметь то же количество позиций, что и количество выбранных солдат.

Простым примером формирования может быть круг вокруг цели. Расставьте места на равных вокруг и увеличьте радиус круга, чтобы соответствовать всем солдатам, не сталкиваясь.

Следующая проблема состоит в том, чтобы решить, какой солдат идет на какую позицию в формировании. Простым решением может быть перемещение каждого солдата в положение, наиболее близкое к нему. Если тот уже «выбран» другим солдатом, займите следующую ближайшую позицию и т. Д.

Формации могут стать довольно интересными. Ниже приведено изображение «формирования рога быка», которое Шака Зулу с большим успехом использовал . (Изображение взято из TotalWar Formation Mod )

формирование рога быка

Willem
источник
«Следующая проблема состоит в том, чтобы решить, какой солдат идет на какую позицию в формировании». Собственно, в этом и заключается вся проблема этого вопроса. :) Голосовали за предложение о формировании круга вместо сетки, но это неэффективно для более чем нескольких солдат, и перемещение солдат в ближайшую к ним локацию вызывает больше конфликтов, чем мое решение выше по сортировке юнитов по локации.
IceCreamYou
0

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

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

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

спенсер
источник
Векторное решение, которое вы предлагаете, совпадает с моей попыткой 2 выше. Одним из требований этого вопроса является то, что выбранные единицы не могут быть в формировании.
IceCreamYou
И я написал о решении, в котором они не будут двигаться в формировании. (2-й абзац)
Спенсер