Я написал 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 вашего браузера при просмотре демонстрации и возиться с ней, чтобы изменить поведение солдат.
У меня вопрос: есть ли лучший способ определить местоположение цели для каждого солдата, чтобы перейти к?
источник
Ответы:
Вот мои предложения по вашим идеям:
Попытка 1: чтобы исправить эту ситуацию, вы можете реализовать «достаточно близкую» идею, предложенную Спенсером. Я бы сделал что-то вроде рисования пузыря вокруг конечной точки, который растет на основе отношения количества и размера уже существующих единиц. Скажем, пузырь начинает размером с одну единицу, затем, когда первая попадает туда, радиус удваивается для следующих двух единиц и т. Д.
Попытка 2: исправление для этого было бы взять среднее расстояние группы друг от друга, а затем сократить расстояние выбросов к этому, чтобы группа оказалась более сгруппированной, чем они были первоначально (метрика могла быть короче / дольше, чем в среднем, что бы это ни выглядело прилично, или, возможно, снова установите максимальный размер формы, исходя из количества / размера войск). Единственное, о чем вам следует беспокоиться, это когда вы изменяете путь выброса, вы ' Я должен проверить и убедиться, что он не мешает другим путям
Попытка 3: вы улучшили это в попытке 4
Попытка 4: Похоже, что это будет работать нормально, если вы обнаружите, что сбои сбрасывают его. Я бы порекомендовал поиграть с эффектами, отличными от простого формирования сетки, однако, чтобы движение выглядело немного более естественным, если только вы не придерживаетесь стиля реализма / милитаризма, в таком случае было бы неплохо сформировать их ». "до переезда, но это может раздражать игрока через некоторое время.
Попытка 4 кажется наиболее близкой к устранению фрезерного поведения в вашей задаче, но с точки зрения поддержания движения без каких-либо регулировок, кроме необходимых, моей любимой будет, вероятно, попытка 2.
Но как совершенно другое решение, вы можете иметь два типа объектов, когда дело доходит до поиска пути; каждый юнит, а также невидимый «отряд» объекта.
Отряд. Вы строите объект отряда в центре группы, как и другие решения, и используете свой путь, чтобы направить его к цели.
Юниты - Юниты полностью игнорируют цель и вместо этого используют поиск пути, чтобы держаться в пределах определенного расстояния (или формация, или любая другая метрика, заканчивающая тем, что движение выглядит лучше) от объекта отряда.
Это разделяет различные аспекты поиска пути и позволяет настраивать обе стороны изолированно для большего контроля над тем, как это выглядит.
источник
Попытка 3 может сработать, но она требует некоторой доработки.
Подумайте о концепции формирования (ваша сетка - это начало). Формация должна иметь местоположение (то есть координаты щелчка, или целевой солдат / здание) и вращение (это может быть фиксированным, случайным или детерминированным). Формирование должно иметь то же количество позиций, что и количество выбранных солдат.
Простым примером формирования может быть круг вокруг цели. Расставьте места на равных вокруг и увеличьте радиус круга, чтобы соответствовать всем солдатам, не сталкиваясь.
Следующая проблема состоит в том, чтобы решить, какой солдат идет на какую позицию в формировании. Простым решением может быть перемещение каждого солдата в положение, наиболее близкое к нему. Если тот уже «выбран» другим солдатом, займите следующую ближайшую позицию и т. Д.
Формации могут стать довольно интересными. Ниже приведено изображение «формирования рога быка», которое Шака Зулу с большим успехом использовал . (Изображение взято из TotalWar Formation Mod )
источник
При щелчке пользователя нарисуйте вектор от каждого солдата до выбранного места. Получите средний векторный угол из векторов, нарисованных для каждого солдата, и переместите каждого солдата на длину его отдельного вектора в этом направлении под тем же углом. Это должно создать видимость отрядов, движущихся в строю до точки, и не дать скоплениям сгуститься.
Если вы хотите, чтобы отряды вышли из строения, вы можете направить угол каждого солдата прямо в выбранное место. Однако без столкновения единицы начнут сходиться. Чтобы противостоять этому, добавьте столкновение и заставьте юниты перестать двигаться, как только они «приблизятся» к точке, по которой щелкнули. Первые прибывшие юниты будут точно в точке, а последним прибывшим должны быть направлены прекратить движение, когда они будут достаточно близко или по прошествии определенного количества времени.
Вы можете рассчитать длину пути и скорость юнита, чтобы определить, когда должен прибыть один юнит, и затем заставить юнит перестать двигаться, если он превышает это время на определенную величину. Вам нужно немного поиграть с этим номером.
источник