This is a continuation of another issue I’ve had. I have a script that spawns a model with a hitbox. I then have another script that detects the hitbox and applies damage. The issue is that half of the time when I start a test in studio, the hitbox script wont work unless there’s already a hitbox in existence, which is demonstrated in the video where the first test it works as intended, but the second time it has the issue. (Ignore that I don’t take damage, I hadn’t implemented it yet at the time of the video.)
Here is the script that clones/spawns the model.
game.ReplicatedStorage.RemoteEvent.OnServerEvent:Connect(function(player,mousehit)
local model = workspace.Model:Clone()
model.Hitbox:AddTag("hitbox")
model.Parent = workspace
model.PrimaryPart.Position = mousehit.Position
model.Stars.Position = mousehit.Position
model.Hitbox.Position = mousehit.Position
local stuff = model:GetDescendants()
for i, v in pairs(stuff) do
if v:IsA("ParticleEmitter") then
local emitcount = v:GetAttribute("EmitCount")
local waittime = v:GetAttribute("EmitDelay")
local emittime = v:GetAttribute("EmitDuration")
task.spawn(function()
task.wait(2.25)
model:Destroy()
end)
if waittime == 0 and emittime == 0 then
task.spawn(function()
task.wait(0.01)
v:Emit(emitcount)
end)
elseif waittime > 0 and emittime == 0 then task.spawn(function()
task.wait(waittime)
v:Emit(emitcount)
end)
else
task.spawn(function()
v.Enabled = true
task.wait(emittime)
v.Enabled = false
end)
end
end
if v:IsA("Sound") then
v:Play()
end
end
end)
And here is the script that detects and handles hitbox logic:
local cs = game:GetService("CollectionService")
game.ReplicatedStorage.RemoteEvent.OnServerEvent:Connect(function()
local hitbox = cs:GetTagged("hitbox")
for i, v in pairs(hitbox) do
local parts = game.Workspace:GetPartsInPart(v)
print(parts)
for i, part in pairs(parts) do
if part.Parent:FindFirstChild("Humanoid") then
part.Parent.Humanoid.Health = 0
end
end
v:Destroy()
end
end)
Also, let me know if there’s anything different I should be doing in my coding as I’m a new scripter with only about 2 months of experience.
If these are the same remote events, the problem is probably that it’s undetermined which block of code runs first, since they’re responding to the same event.
So for example, the GetTagged code might run first and see no hitboxes, then the Model:Clone() code would run and add the hitbox, but nothing would happen because the hitbox code already finished.
I would update the hitbox logic to start when a hitbox tag is added using events:
local cs = game:GetService("CollectionService")
local HITBOX_TAG = "hitbox"
local function onHitboxAdded(hitbox)
-- Your hitbox code here (the get parts in stuff)
end
local initialHitboxes = cs:GetTagged(HITBOX_TAG)
-- Run the hitbox code for every already existing hitbox
for _, hitbox in ipairs(initialHitboxes) do
onHitboxAdded(hitbox)
end
-- Run the hitbox code for every future hitbox
cs.GetInstanceAddedSignal(HITBOX_TAG):Connect(onHitboxAdded)
This way the hitbox code runs directly after a hitbox is added, instead of before or after a hitbox is added for every hitbox.
You can merge both event handlers into one. You already wrote the cloning part to not yield which is fantastic. You can just do the hitbox logic at the end of the cloning handler. Something like this:
v:Play()
end
end
local parts = game.Workspace:GetPartsInPart(model.Hitbox)
print(parts)
for i, part in pairs(parts) do
if part.Parent:FindFirstChild("Humanoid") then
part.Parent.Humanoid.Health = 0
end
end
end)
You don’t need to loop through existing hitboxes or track them with tags because they can be used for part detection instantly. If you have clients that also need the hitbox for something, you can just destroy it with the rest of model. There’s no rush since this check only happens once it’s created.
nitpick
I notice you spawn new threads that wait before doing stuff. You can try using task.delay to save a line of code. If you’re just destroying something after a moment, the Debris service is even more reasonable.