Touched event not stability and have bad reaction

Hello.
I made rocket system for my helicopter.
Rockets pushed by LinearVelocity.

I have touched event for detect when rocket touched something.
But its very unstability and lazy.
Now it turns out that the rocket is flying, hits somewhere and the Touched event does not react in time, which causes the rocket to bounce and explode in another place. At the same time, when a rocket hits something, it becomes Anchored. That is, it bounces off due to the fact that the Touched event did not work on time.

Moreover, I tried to make a separate Part and search for Touched through it, but it doesn’t help. Even if it’s too long and big. Apparently, due to the speed of the rocket (Velocity 300 ), it does not work properly.

1 Like

Maybe try to use raycasting instead of the touched event?

Try turning CanCollide off or use a different method

dont use .Touched events and instead do constant and small spatial queries infront of the missile and once it finds something other than the missile detonate it (this can be achieved with OverlapParams.new()), but that might be very expensive if youre firing 300 missiles at once

if youre more concerned on performance just fire 1 or more raycasts and if youre firing more raycasts then face it in different directions. this will be easy/hard to do depending on if you want to rotate the vector or just find it with :VectorToWorldSpace().

  1. raycasts
    from the missile fire raycasts facing the missiles LookVector and if you want more, again, take the CFrame of the part and use :VectorToWorldSpace() to figure out any inbetweens between the LookVector and wherever else you want to face (this can be found from the CFrame of the missile), and if you want to give it a larger detection radius just multiply the vector of the raycasts
  2. shapecasts via workspace:GetPartBoundsInBox()
    figure out some CFrame facing in the direction of the missile but is positioned directly ahead of the missile, then make a bounding box of your preferred size. if anything but the missile is in there then detonate. if youre lazy just use OverlapParams and then have the bounding box
    slightly larger than the missile, this will include the missile
  3. shapecasts via workspace:GetPartBoundsInRadius()
    literally just get the position of the missile, put a radius and detonate if something else is found. this requires using OverlapParams because its semi obvious that the missile will be apart of the query
2 Likes

I’ve tried with RayCast, but at speed they can’t keep up with the rocket and end up behind it

bind it to like .Stepped or something, if this happens you are most definitely using while true do or even worse while wait() do.

if youre wondering what :VectorToWorldSpace() does


rotation matrices are a pain to understand but to think of them intuitively, treat every 3 columns as a vector. suddenly you unlock the secrets to life as you then realize that the rotation matrices, when represented as vectors, basically give you 3 vectors that tell you where the object is facing

what is also sudden is that the transformations for rotation matrices line up with how you now think of rotation matrices

remember however that in Roblox coordinate systems, front faces 0, 0, -1 and not 0, 0, 1, which explains why you see in the documentation for CFrames, specifically under the documentation for LookVectors, this:

The forward-direction component of the CFrame object’s orientation, equivalent to the negated ZVector or the negated third column of the rotation matrix.

so keep that in mind, probably a bit too much to cram into anyone’s head but it’s still very important to understand when coming to rotations

then again CFrame.fromOrientation() exists so if you want to use whatever works for you then go ahead

the rocket still manages to bounce off the point of impact (

local function detonateRocket(rocket, hitPart)
	if not rocket:GetAttribute("hasHit") then
		rocket:SetAttribute("hasHit", true)
		print("Ракета " .. rocket.Name .. " попала в " .. (hitPart and hitPart.Name or "неизвестный объект"))
		rocket.DR.Engine.LinearVelocity.Enabled = false
		rocket.DR.Anchored = true -- Фиксируем на месте
		rocket.DR.Transparency = 1 -- Делаем невидимой
		rocket.DR.CanCollide = false -- Отключаем столкновения
		if rocket.DR.Engine:FindFirstChild("Sound") then
			rocket.DR.Engine.Sound:Destroy()
		end
		rocket.DR.Engine.ParticleEmitter:Destroy()
		rocket.DRElements.Transparency = 1 -- Делаем невидимой
		rocket.DRElements.Anchored = true -- Фиксируем на месте
		rocket.DRElements.CanCollide = false -- Отключаем столкновения
		rocket.RayHolder.ExplosionVFX.Sound:Play()

		-- Запускаем эффекты взрыва
		for _, effect in ipairs(explosionEffects) do
			local emitter = rocket.RayHolder.ExplosionVFX:FindFirstChild(effect.name)
			if emitter and emitter:IsA("ParticleEmitter") then
				print("Найден эмиттер: " .. effect.name .. " для ракеты " .. rocket.Name)
				if effect.delay > 0 then
					task.delay(effect.delay, function()
						emitter:Emit(effect.emitCount)
						print("Эффект " .. effect.name .. " запущен с задержкой " .. effect.delay .. " для " .. rocket.Name)
					end)
				else
					emitter:Emit(effect.emitCount)
					print("Эффект " .. effect.name .. " запущен сразу для " .. rocket.Name)
				end
			else
				warn("Эффект " .. effect.name .. " не найден или не является ParticleEmitter в ракете " .. rocket.Name)
			end
		end

		-- Удаляем ракету после завершения всех эффектов
		task.delay(8, function()
			rocket:Destroy()
		end)
	end
end

-- Функция для настройки параметров Raycast
local function createRaycastParams(rocket)
	local raycastParams = RaycastParams.new()
	raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
	raycastParams.FilterDescendantsInstances = {helicopter, rocket} -- Игнорируем вертолёт и саму ракету
	return raycastParams
end

-- Функция для проверки лучей
local function checkRays(rocket, rayHolder, raycastParams)
	local rayLength = 30 -- Длина луча (настраивайте по необходимости)
	local rayOrigin = rayHolder.Position -- Начальная точка луча

	-- Определяем направления лучей
	local directions = {
		rayHolder.CFrame.LookVector, -- Основной луч (вперёд)
		rayHolder.CFrame:VectorToWorldSpace(Vector3.new(0.2, 0, -1)), -- Немного вправо
		rayHolder.CFrame:VectorToWorldSpace(Vector3.new(-0.2, 0, -1)), -- Немного влево
		rayHolder.CFrame:VectorToWorldSpace(Vector3.new(0, 0.2, -1)), -- Немного вверх
		rayHolder.CFrame:VectorToWorldSpace(Vector3.new(0, -0.2, -1)) -- Немного вниз
	}

	-- Проверяем каждый луч
	for i, direction in ipairs(directions) do
		local rayDirection = direction * rayLength
		local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)

		if raycastResult then
			local hitPart = raycastResult.Instance
			print("Ракета " .. rocket.Name .. " (луч " .. i .. ") обнаружила объект: " .. hitPart.Name)
			detonateRocket(rocket, hitPart)
			return true -- Прерываем проверку, если нашли попадание
		end
	end
	return false
end

-- Функция для запуска проверки лучей для ракеты
local activeRockets = {} -- Таблица для хранения активных подключений Heartbeat для ракет
local function startRayChecking(rocket)
	local rayHolder = rocket:WaitForChild("RayHolder")
	if not rayHolder then
		warn("RayHolder не найден в ракете " .. rocket.Name)
		return
	end

	local raycastParams = createRaycastParams(rocket)

	-- Подключаем Heartbeat для проверки лучей
	local connection
	connection = RunService.Heartbeat:Connect(function()
		if rocket and rocket.Parent then -- Проверяем, существует ли ракета
			if not rocket:GetAttribute("hasHit") then -- Проверяем, не взорвалась ли ракета
				local hit = checkRays(rocket, rayHolder, raycastParams)
				if hit then
					-- Если попали, отключаем Heartbeat
					if connection then
						connection:Disconnect()
						activeRockets[rocket] = nil
						print("Raycast Heartbeat отключен для ракеты " .. rocket.Name)
					end
				end
			else
				-- Если ракета взорвалась, отключаем Heartbeat
				if connection then
					connection:Disconnect()
					activeRockets[rocket] = nil
					print("Raycast Heartbeat отключен для ракеты " .. rocket.Name)
				end
			end
		else
			-- Если ракета удалена, отключаем Heartbeat
			if connection then
				connection:Disconnect()
				activeRockets[rocket] = nil
				print("Raycast Heartbeat отключен для ракеты " .. rocket.Name .. " (ракета удалена)")
			end
		end
	end)

	-- Сохраняем подключение в таблице
	activeRockets[rocket] = connection
end

I increased the RayLenght and now the rocket explodes in the place where it hit, but, true, this length is a little too long, that is, it explodes a little short of the point of contact, but I think this is not critical for the rocket, since an explosion occurs anyway.
But if there is a way to make sure that the explosion site is exactly at the point of contact, then it would be good

just use shapecasts then

also ignore the character filler down here
CHARACTERS CHARACTERS CHARACTERS

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.