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

alexgear

Новичок
15 Авг 2017
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?
 
Мы не шаттл строим, вычисления все эти мизерные для современных процессоров, ниче просидать не будет.
Вот пример, как в свое время я реализовывал столкновение.
 
Вполне может и проседать. Приходилось оптимизировать чистую математику, потому что реально тормозило.

Бери деревья в круге один раз вписывая нужный луч в круг, если он не слишком большой длины и затем внутри фильтруй еще раз по длине перпендикуляра к линии. Если луч слишком длинный можно делить на несколько кругов и собирать результат из них.
 
Мм, интересное решение. Спасибо за ответы! Пойду попробую.
 
Всё получилось, фпс не проседает ни на единицу. Спасибо! Не знаю, может, тупой перебор через 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
 
Последнее редактирование модератором:
Именно то, что я имел в виду, да. Я немного слукавил, в моем случае фпс проседал из-за создания объекта Vector (помог перевод на обычные пары чисел, скорее всего валв не используют пул и вручную выделяют память через какой-нибудь new), но факт есть факт, о производительности трястись постоянно хоть и не нужно, но забывать тоже не стоит. (Алсо проседание фпс на сервере вызывает намного более уродливые лаги, чем если бы проседала панорама на клиенте, например)
 
Реклама: