CustomGames.ru - Dota 2 пользовательские игры

Поиск деревьев вдоль линии

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн alexgear

  • 3
  • Мощь: 0
Привет! У меня такая задача: нужно обнаружить деревья, стоящие на пути вдоль линии. Делаю скилл в виде луча, который будет сталкиваться с первым попавшимся на пути деревом. Вернее сказать даже с первым вообще попавшимся энтитем. Сначала хотел заюзать TraceLine или TraceHull, которые вроде хорошо подходят под задачу, но похоже, что они игнорируют деревья. Другим вариантом может быть использование чего-то вроде
Код
local trees = FindUnitsInLine(DOTA_TEAM_NOTEAM, startPos, endPos, nil, 30, DOTA_UNIT_TARGET_TEAM_BOTH, DOTA_UNIT_TARGET_TREE, DOTA_UNIT_TARGET_FLAG_NONE)
или лучше сразу
Код
local entities = FindUnitsInLine(DOTA_TEAM_NOTEAM, startPos, endPos, nil, 30, DOTA_UNIT_TARGET_TEAM_BOTH, DOTA_UNIT_TARGET_ALL + DOTA_UNIT_TARGET_TREE, DOTA_UNIT_TARGET_FLAG_NONE)
чтоб найти вообще всех на пути.
Однако почему-то эта функция безразлична к деревьям даже при флаге DOTA_UNIT_TARGET_TREE. Пробовал выкрутить радиус в 1000, но один результат отрицательный.
На крайняк остаётся делать GetAllTreesAroundPoint в цикле, смещая центр каждый раз по ходу луча, но мне кажется, это будет слишком затратная операция, потому что просчёт луча должен происходить по несколько десятков раз в секунду, да ещё и помножить это на то, что несколько игроков могут одновременно выпускать лучи. Вообще не пробовал этот вариант, может, GetAllTreesAroundPoint достаточно оптимизирован, чтоб не просаживать фпс даже при таком количестве вызовов в секунду, но что-то сомневаюсь я.
В общем, в основном вопрос таков: как заставить FindUnitsInLine принимать флаг DOTA_UNIT_TARGET_TREE и соответственно видеть деревья? Ну или вообще как можно обнаруживать деревья, попадающиеся на определённой линии на карте? Где найти эдакую GetAllTreesAlongLine по аналогии с существующей GetAllTreesAroundPoint?

Оффлайн Илья

  • Супермодератор
  • 2142
  • Мощь: 21
Re: Поиск деревьев вдоль линии
« Ответ #1 : 16-08-2017, 09:37:53 »
Мы не шаттл строим, вычисления все эти мизерные для современных процессоров, ниче просидать не будет.
Вот пример, как в свое время я реализовывал столкновение.

Оффлайн MahouShoujo

  • Продвинутый
  • 204
  • Мощь: 4
Re: Поиск деревьев вдоль линии
« Ответ #2 : 16-08-2017, 10:07:24 »
Вполне может и проседать. Приходилось оптимизировать чистую математику, потому что реально тормозило.

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

Оффлайн alexgear

  • 3
  • Мощь: 0
Re: Поиск деревьев вдоль линии
« Ответ #3 : 16-08-2017, 10:22:17 »
Мм, интересное решение. Спасибо за ответы! Пойду попробую.

Оффлайн alexgear

  • 3
  • Мощь: 0
Re: Поиск деревьев вдоль линии
« Ответ #4 : 16-08-2017, 12:37:26 »
Всё получилось, фпс не проседает ни на единицу. Спасибо! Не знаю, может, тупой перебор через GetAllTreesAroundPoint с маленькими радиусами тоже бы не просаживал фпс, но всё же так должно получиться производительнее. Получившийся код:
Спойлер
Код
BEAM_MAX_LENGTH = 2500
BEAM_COLLISION_WIDTH = 80
BEAM_TREE_DETECTION_STEPS = 5
BEAM_TREE_DETECTION_RADIUS = (BEAM_MAX_LENGTH / BEAM_TREE_DETECTION_STEPS) / 2

function Beams:OnBeamsThink(player)
local heroEntity = player:GetAssignedHero()
local origin = heroEntity:GetAbsOrigin()
local forward = heroEntity:GetForwardVector():Normalized()
local startPos = origin + forward * 100
local endPos = origin + forward * BEAM_MAX_LENGTH
--[[ ............... ]]
local minDistance = BEAM_MAX_LENGTH
local step = (endPos - startPos) / BEAM_TREE_DETECTION_STEPS
local offset = step / 2
for i = 0, BEAM_TREE_DETECTION_STEPS - 1 do
local center = startPos + offset + step * i
local trees = GridNav:GetAllTreesAroundPoint(center, BEAM_TREE_DETECTION_RADIUS, true)
for _, tree in pairs(trees) do
local treeOrigin = tree:GetAbsOrigin()
local h = CalcDistanceToLineSegment2D(treeOrigin, startPos, endPos)
if h <= BEAM_COLLISION_WIDTH then
local distance = #(treeOrigin - startPos)
if distance < minDistance then
minDistance = distance
end
end
end
if minDistance < BEAM_MAX_LENGTH then
break
end
end
--[[ В minDistance лежит расстояние до ближайшего дерева или макс. длина луча. ]]
end
[свернуть]

Оффлайн MahouShoujo

  • Продвинутый
  • 204
  • Мощь: 4
Re: Поиск деревьев вдоль линии
« Ответ #5 : 16-08-2017, 14:16:32 »
Именно то, что я имел в виду, да. Я немного слукавил, в моем случае фпс проседал из-за создания объекта Vector (помог перевод на обычные пары чисел, скорее всего валв не используют пул и вручную выделяют память через какой-нибудь new), но факт есть факт, о производительности трястись постоянно хоть и не нужно, но забывать тоже не стоит. (Алсо проседание фпс на сервере вызывает намного более уродливые лаги, чем если бы проседала панорама на клиенте, например)