The yielding is coming from this section:
local startTime = os.clock()
while os.clock() - startTime < Duration do
if #detectedTargets > 0 then
break
end
runservice.Heartbeat:Wait()
end
If you dont want the function to yield, you’ll need to wrap the function’s code in a task.spawn then have the function also take a “callback” function to run on the results.
It’s not possible to have a function that returns stuff in the future not yield, so you need to have it not return and thing and instead also take a function to run on the targets or return an event and fire the event when the targets are found.
Here are those options:
function module.CreateHitbox(Size, Duration, Cframe, char, isAOE, targetsFunction)
local connection
local overlap = OverlapParams.new()
overlap.MaxParts = 100
overlap.FilterType = Enum.RaycastFilterType.Include
overlap.FilterDescendantsInstances = workspace.Enemies:GetChildren()
-- visual
local hitbox = Instance.new("Part")
hitbox.Parent = workspace
hitbox.Size = Size
hitbox.CFrame = Cframe
hitbox.Anchored = true
hitbox.Transparency = 0.5
hitbox.BrickColor = BrickColor.new("Really red")
hitbox.CanCollide = false
game.Debris:AddItem(hitbox, Duration)
local damagedTargets = {}
local detectedTargets = {}
connection = runservice.Heartbeat:Connect(function()
local hitParts = workspace:GetPartBoundsInBox(Cframe, Size, overlap)
for _, part in ipairs(hitParts) do
if not damagedTargets[part.Parent] and part.Parent ~= char then
damagedTargets[part.Parent] = true
table.insert(detectedTargets, part.Parent)
if not isAOE then
break
end
end
end
end)
task.spawn(function()
local startTime = os.clock()
while os.clock() - startTime < Duration do
if #detectedTargets > 0 then
break
end
runservice.Heartbeat:Wait()
end
connection:Disconnect()
if isAOE then
targetsFunction(detectedTargets)
else
targetsFunction({detectedTargets[1]})
end
end)
end
Example usage:
local function destroyTargets(targets)
for _, target in ipairs(targets) do
target:Destroy()
end
end
module.CreateHitbox(Size, Duration, Cframe, char, isAOE, destroyTargets)
With an event:
function module.CreateHitbox(Size, Duration, Cframe, char, isAOE)
local connection
local overlap = OverlapParams.new()
overlap.MaxParts = 100
overlap.FilterType = Enum.RaycastFilterType.Include
overlap.FilterDescendantsInstances = workspace.Enemies:GetChildren()
-- visual
local hitbox = Instance.new("Part")
hitbox.Parent = workspace
hitbox.Size = Size
hitbox.CFrame = Cframe
hitbox.Anchored = true
hitbox.Transparency = 0.5
hitbox.BrickColor = BrickColor.new("Really red")
hitbox.CanCollide = false
game.Debris:AddItem(hitbox, Duration)
local damagedTargets = {}
local detectedTargets = {}
connection = runservice.Heartbeat:Connect(function()
local hitParts = workspace:GetPartBoundsInBox(Cframe, Size, overlap)
for _, part in ipairs(hitParts) do
if not damagedTargets[part.Parent] and part.Parent ~= char then
damagedTargets[part.Parent] = true
table.insert(detectedTargets, part.Parent)
if not isAOE then
break
end
end
end
end)
local bindable = Instance.new("BindableEvent")
task.spawn(function()
local startTime = os.clock()
while os.clock() - startTime < Duration do
if #detectedTargets > 0 then
break
end
runservice.Heartbeat:Wait()
end
connection:Disconnect()
if isAOE then
bindable:Fire(detectedTargets)
else
bindable:Fire({detectedTargets[1]})
end
end)
return bindable.Event
end
Example usage:
local gotTarget = module.CreateHitbox(Size, Duration, Cframe, char, isAOE)
gotTarget:Once(function(targets)
for _, target in ipairs(targets) do
target:Destroy()
end
end)