GetPartsInPart() hitbox not detecting all of the parts inside of it

Hello, everyone!

I’m working on a fighting game, and I’ve been struggling with this issue for at least two days now. I wanted to switch from a .Touched:Connect() hitbox method to a GetPartsInPart() hitbox method, and I thought it was all going to be fine.

Here’s what went wrong though.


In this clip, you can see I’m swinging the dagger at the NPC and it does nothing. Here’s what my output looks like.

You can see that the script prints out what it detects as a hit, and it detects mostly myself. But nowhere in there does it ever detect any part of the NPC, which is what really has me stumped. (Also, ignore the red text showing through the bottom of the screenshot, it’s from a completely unrelated script.)

Here’s the part of my script that’s messing up. This is a function that will fire separately from the swinging animations and all that, this is purely designed for damaging a humanoid if it detects one inside the hitbox. I left some comments in to help you guys understand what’s going on.

local function Attack()
			if db == true then -- db = debounce, simple
				if not canHit then -- canHit controls whether or not you can damage someone
					canHit = true
					local effect = script.Parent.Handle.Blood -- Irrelevant effects
					local btrail = script.Parent.Handle.BloodTrail
					
					local hits = ws:GetPartsInPart(g) -- The variable "g" refers to the hitbox that refuses to detect properly. And this is where it all goes downhill...
					
					print("attack launched")
					
					for i = 1, #hits do
						
						print(hits[i].Name ..", child of ".. hits[i].Parent.Name)
					
						if hits[i].Parent ~= char and hits[i].Parent:FindFirstChild("Humanoid") and hits[i].Parent:FindFirstChild("Dashing") and char.Stunned.Value == false then -- "Dashing" is a value inside the enemy character, meaning that if it is set to true then the enemy is invulnerable to damage. Stunned is a value inside of my own character, and it's here to make sure I can't attack when I'm stunned from someone else's attack.
							print("check 1 success")
							if hits[i].Parent.Dashing.Value == false then
								print("check 2 success")
						local hitSFX = Instance.new("Sound",hits[i].Parent.Head); -- irrelevant stuff from this point down
hitSFX.SoundId = "rbxassetid://566593606"; hitSFX:Play()
						hits[i].Parent.Humanoid:TakeDamage(5)

-- More stuff happens after this point, but it shouldn't be important.
-- If it ends up being important I can provide the whole script, but it is a bit hard to read 'cause I'm a novice.

Any and all help is appreciated. Sorry if my code is messy or anything like that, and like I said I can provide the rest of it if any of you think that it’s important. This snippet of code comes from a normal script by the way.

5 Likes

Tell me what this prints:

local function Attack()
	if db == true then -- db = debounce, simple
		if not canHit then -- canHit controls whether or not you can damage someone
			canHit = true
			local effect = script.Parent.Handle.Blood -- Irrelevant effects
			local btrail = script.Parent.Handle.BloodTrail

			local hits = ws:GetPartsInPart(g) -- The variable "g" refers to the hitbox that refuses to detect properly. And this is where it all goes downhill...

			for i = 1, #hits do
				print(hits[i]:FindFirstAncestorWhichIsA('Model'))

				if hits[i].Parent ~= char and hits[i].Parent:FindFirstChild("Humanoid") and hits[i].Parent:FindFirstChild("Dashing") and char.Stunned.Value == false then -- "Dashing" is a value inside the enemy character, meaning that if it is set to true then the enemy is invulnerable to damage. Stunned is a value inside of my own character, and it's here to make sure I can't attack when I'm stunned from someone else's attack.
					print("check 1 success")
					if hits[i].Parent.Dashing.Value == false then
						print("check 2 success")
						local hitSFX = Instance.new("Sound",hits[i].Parent.Head); -- irrelevant stuff from this point down
						hitSFX.SoundId = "rbxassetid://566593606"; hitSFX:Play()
						hits[i].Parent.Humanoid:TakeDamage(5)

						-- More stuff happens after this point, but it shouldn't be important.
						-- If it ends up being important I can provide the whole script, but it is a bit hard to read 'cause I'm a novice.

Also, I have quite a few tips for you.

Use more guard clauses, so instead of doing this:

local function Attack()
	if db == true then
		--//Main logic, will contain a lot of code
	end
end

Do this instead, it will improve the readability of your code:

local function Attack()
	if not db then
		return
	end
	
	--//Main logic, will contain a lot of code
end

workspace:GetPartsInParts() also accepts a second argument that is an OverlapParams. You can configure your OverlapParams to ignore any parts from your character, which will help with performance.

It would also help if you post your entire code, because there could be some parts that are important.

3 Likes

Thank you for the tips! I’ll keep these in mind when programming further down the line.

With how you changed the print, it printed this:
image

I took your advice and added an OverlapParams argument that blacklisted objects from my character, and it printed this instead:
image
I only clicked once, but it put the NPC in a loop of getting hit and the lifesteal status effect activating.


It seems like narrowing it down using OverlapParams seemed to do the trick of getting the hitbox to detect the NPC, but the damage loop wasn’t a problem I had before switching to GetPartsInPart() hitboxes.

I’m looking into it myself right now, since I feel like this is something more within my capability of troubleshooting and fixing, but by all means if you want to investigate my script then go ahead.

local tool = script.Parent

local hitbox = tool.HitboxPart

local g

-- hitbox weld stuff
tool.Equipped:Connect(function()


	local char = tool.Parent
	local root = char:WaitForChild("HumanoidRootPart")

	if root ~= nil and root:FindFirstChild("HitboxPart") ~= nil then
		root:FindFirstChild("HitboxPart"):Destroy()
	end

	if root ~= nil then
		g = hitbox:Clone()
		g.Anchored = false
		g.Parent = root
		local W = Instance.new("Weld")
		g.CFrame = root.CFrame * CFrame.new(0,0,-2.5)
		W.Part0 = root
		W.Part1 = g
		W.C0 = root.CFrame:Inverse()
		W.C1 = g.CFrame:Inverse()
		W.Parent = g

		--[[local Y = Instance.new("Weld")
		Y.Part0 = root
		Y.Part1 = g
		Y.C0 = CFrame.new(0, 0, 0)
		Y.Parent = Y.Part0--]]
	end

-- restore a new hitbox
	if tool:FindFirstChild("HitboxPart") == nil then
		local newhit = g:Clone()
		newhit:ClearAllChildren()
		newhit.Parent = tool
		newhit.Anchored = true
	end

end)

-- get rid of the old hitbox
tool.Unequipped:Connect(function()
	if g then g:Destroy()
		g = nil
	end
	end)






-- more variables
local db = false

local canHit = false

local randomSlash = 1

local equip
local slash
local idle

-- folders
local anims = script.Parent.Animations
local sounds = script.Parent.Sounds

local ws = game:GetService("Workspace")



-- start up the animation stuff
script.Parent.Equipped:Connect(function()
	sounds.Equip:Play()
	local humanoid = script.Parent.Parent:FindFirstChild("Humanoid")
	if not equip then equip = humanoid:LoadAnimation(anims.Equip) end
	equip:Play()
	if not idle then idle = humanoid:LoadAnimation(anims.Idle) end
	idle.Priority = Enum.AnimationPriority.Movement
	idle:Play()
end)

-- light attack function
script.Parent.Activated:Connect(function()
	
	local char = tool.Parent
	
	if char.Stunned.Value == false and char.Dashing.Value == false and not db then
		db = true
		idle:Stop()
		
		
		local function Attack()
			if db == true then
				if not canHit then
					canHit = true
					local effect = script.Parent.Handle.Blood
					local btrail = script.Parent.Handle.BloodTrail
					
					local oparams = OverlapParams.new()
					oparams.FilterType = Enum.RaycastFilterType.Exclude
					oparams.FilterDescendantsInstances = {char}

					local hits = ws:GetPartsInPart(g,oparams)

					for i = 1, #hits do
						print(hits[i]:FindFirstAncestorWhichIsA('Model'))

						if hits[i].Parent ~= char and hits[i].Parent:FindFirstChild("Humanoid") and hits[i].Parent:FindFirstChild("Dashing") and char.Stunned.Value == false then
							print("check 1 success")
							if hits[i].Parent.Dashing.Value == false then
								print("check 2 success")
								local hitSFX = Instance.new("Sound",hits[i].Parent.Head);
								hitSFX.SoundId = "rbxassetid://566593606"; hitSFX:Play()
								hits[i].Parent.Humanoid:TakeDamage(5)
						
						-- I don't know any better way to do this
						local function stunhum()
							hits[i].Parent:FindFirstChild("Stunned").Value = true
							hits[i].Parent.Humanoid.WalkSpeed = hits[i].Parent.Humanoid.WalkSpeed / 2
							local stunnum = math.random(1,4)
							if stunnum == 1 then
								local stunanim = hits[i].Parent.Humanoid:LoadAnimation(anims.Damaged1)
								stunanim:Play()
							elseif stunnum == 2 then
								local stunanim = hits[i].Parent.Humanoid:LoadAnimation(anims.Damaged2)
								stunanim:Play()
							elseif stunnum == 3 then
								local stunanim = hits[i].Parent.Humanoid:LoadAnimation(anims.Damaged3)
								stunanim:Play()
								
							elseif stunnum == 4 then
								local stunanim = hits[i].Parent.Humanoid:LoadAnimation(anims.Damaged4)
								stunanim:Play()
							end
							
							local lspart1 = tool.Handle.BLOOD02:Clone()
							local lspart2 = tool.Handle.BLOOD03:Clone()
							local lssound = tool.Sounds.Lifesteal:Clone()
							lspart1.Parent = hits[i].Parent.Torso
							lspart2.Parent = hits[i].Parent.Torso
							lssound.Parent = hits[i].Parent.Torso
							
							delay(.5,function()
								hits[i].Parent:FindFirstChild("Stunned").Value = false
								hits[i].Parent.Humanoid.WalkSpeed = hits[i].Parent.Humanoid.WalkSpeed * 2
							end)
							-- blood drain stuff, kinda messy
							delay(2,function()
								hits[i].Parent.Humanoid:TakeDamage(1)
								char.Humanoid:TakeDamage(-1)
								lssound:Play()
							end)
							delay(2.1,function()
								hits[i].Parent.Humanoid:TakeDamage(1)
								char.Humanoid:TakeDamage(-1)
							end)
							delay(2.2,function()
								hits[i].Parent.Humanoid:TakeDamage(1)
								char.Humanoid:TakeDamage(-1)
							end)
							delay(2.3,function()
								hits[i].Parent.Humanoid:TakeDamage(1)
								char.Humanoid:TakeDamage(-1)
							end)
							delay(2.4,function()
								hits[i].Parent.Humanoid:TakeDamage(1)
								char.Humanoid:TakeDamage(-1)
							end)
							
							delay(4,function()
								lspart1:Destroy()
								lspart2:Destroy()
								lssound:Destroy()
							end)
							end
						
						
						stunhum()

						
						effect.Enabled = true
						btrail.Enabled = true
						
						local slashfx = tool.Effects.Slash.Attachment:Clone()
						slashfx.Parent = hits[i].Parent:FindFirstChild("HumanoidRootPart")
						local r = math.random(-360,360)
						slashfx.slash.Rotation = NumberRange.new(r,r)
						wait(0.3)
								slashfx:Destroy()
								
					end
					wait(0.4)
					effect.Enabled = false
					btrail.Enabled = false
					canHit = false
					end
					end
					end
			end
		end
		
		local char = tool.Parent
		local root = char:WaitForChild("HumanoidRootPart")
		g = root:FindFirstChild("HitboxPart")
		
		Attack()
		-- slashes arent so random anymore
			script.Parent.Handle.Trail.Enabled = true
		local humanoid = script.Parent.Parent:FindFirstChild("Humanoid")
		if not slash then
			if randomSlash == 1 then
				slash = humanoid:LoadAnimation(anims.Attack1)
				randomSlash = 2
			elseif randomSlash == 2 then
				slash = humanoid:LoadAnimation(anims.Attack2)
				randomSlash = 3
			elseif randomSlash == 3 then
				slash = humanoid:LoadAnimation(anims.Attack3)
				randomSlash = 4
			elseif randomSlash == 4 then
				slash = humanoid:LoadAnimation(anims.Attack4)
				randomSlash = 1
			end
		end
		slash:Play()
		local val = tool.Parent.Attacking
		val.Value = true
		wait(.2)
		sounds.Slash:Play()
		wait(.4)
		if slash then
			slash = nil
		end
		script.Parent.Handle.Trail.Enabled = false
		db = false
		idle:Play()
		val.Value = false
	end
end)
-- stop animations
script.Parent.Unequipped:Connect(function()
	if idle then idle:Stop() end
	if equip then equip:Stop()
		if slash then slash:Stop() end
	end
end)

Just looking at all those repeated delays makes me feel guilty. I hope it’s not too hard to read. I feel bad whenever I post my code on here, knowing it’s probably a pain to examine, so don’t feel pressured to help any further. This is already a huge step in the right direction, so thank you for that.

3 Likes

It’s all good, don’t worry about it. It’s better to post your code than to not get an answer at all. Just make sure to keep improving.

I believe the problem is that the hitbox registers multiple parts from the NPC, so it damages the NPC multiple times. A way to fix this is adding a table of enemies already hit, so that it only damages them once.

Fixed code:

--//Variables
local tool = script.Parent
local hitbox = tool.HitboxPart
local anims = tool.Animations
local sounds = tool.Sounds

--//Controls
local db = false
local canHit = false
local randomSlash = 1
local equip
local slash
local idle
local g
local ws = workspace
local oparams = OverlapParams.new()
oparams.FilterType = Enum.RaycastFilterType.Exclude

-- hitbox weld stuff
tool.Equipped:Connect(function()
	local char = tool.Parent
	local root = char:WaitForChild("HumanoidRootPart")

	if root ~= nil and root:FindFirstChild("HitboxPart") ~= nil then
		root:FindFirstChild("HitboxPart"):Destroy()
	end

	if root ~= nil then
		g = hitbox:Clone()
		g.Anchored = false
		g.Parent = root
		local W = Instance.new("Weld")
		g.CFrame = root.CFrame * CFrame.new(0,0,-2.5)
		W.Part0 = root
		W.Part1 = g
		W.C0 = root.CFrame:Inverse()
		W.C1 = g.CFrame:Inverse()
		W.Parent = g

		--[[local Y = Instance.new("Weld")
		Y.Part0 = root
		Y.Part1 = g
		Y.C0 = CFrame.new(0, 0, 0)
		Y.Parent = Y.Part0--]]
	end

	-- restore a new hitbox
	if tool:FindFirstChild("HitboxPart") == nil then
		local newhit = g:Clone()
		newhit:ClearAllChildren()
		newhit.Parent = tool
		newhit.Anchored = true
	end

end)

-- get rid of the old hitbox
tool.Unequipped:Connect(function()
	if g then g:Destroy()
		g = nil
	end
end)

-- start up the animation stuff
tool.Equipped:Connect(function()
	sounds.Equip:Play()
	local humanoid = tool.Parent:FindFirstChild("Humanoid")
	if not equip then equip = humanoid:LoadAnimation(anims.Equip) end
	equip:Play()
	if not idle then idle = humanoid:LoadAnimation(anims.Idle) end
	idle.Priority = Enum.AnimationPriority.Movement
	idle:Play()
end)

-- light attack function
tool.Activated:Connect(function()
	local char = tool.Parent
	
	if char.stunned.Value or char.Dashing.Value or db then
		return
	end
	
	db = true
	idle:Stop()
	
	local humanoidsDamaged = {}

	local function Attack()
		if not db or canHit then
			return
		end
		
		canHit = true
		
		local effect = tool.Handle.Blood
		local btrail = tool.Handle.BloodTrail

		oparams.FilterDescendantsInstances = {char}

		local hits = ws:GetPartsInPart(g, oparams)
		
		for i, part in ipairs(hits) do
			if part.Parent ~= char and part.Parent:FindFirstChild("Humanoid") and part.Parent:FindFirstChild("Dashing") and char.Stunned.Value == false then
				if not table.find(humanoidsDamaged, part.Parent.Humanoid) and part.Parent.Dashing.Value == false then
					table.insert(humanoidsDamaged, part.Parent.Humanoid)
					print("Humanoid damaged")
					local hitSFX = Instance.new("Sound",part.Parent.Head);
					hitSFX.SoundId = "rbxassetid://566593606"; hitSFX:Play()
					part.Parent.Humanoid:TakeDamage(5)

					-- I don't know any better way to do this
					local function stunhum()
						part.Parent:FindFirstChild("Stunned").Value = true
						part.Parent.Humanoid.WalkSpeed = part.Parent.Humanoid.WalkSpeed / 2
						local stunnum = math.random(1,4)
						if stunnum == 1 then
							local stunanim = part.Parent.Humanoid:LoadAnimation(anims.Damaged1)
							stunanim:Play()
						elseif stunnum == 2 then
							local stunanim = part.Parent.Humanoid:LoadAnimation(anims.Damaged2)
							stunanim:Play()
						elseif stunnum == 3 then
							local stunanim = part.Parent.Humanoid:LoadAnimation(anims.Damaged3)
							stunanim:Play()

						elseif stunnum == 4 then
							local stunanim = part.Parent.Humanoid:LoadAnimation(anims.Damaged4)
							stunanim:Play()
						end

						local lspart1 = tool.Handle.BLOOD02:Clone()
						local lspart2 = tool.Handle.BLOOD03:Clone()
						local lssound = tool.Sounds.Lifesteal:Clone()
						lspart1.Parent = part.Parent.Torso
						lspart2.Parent = part.Parent.Torso
						lssound.Parent = part.Parent.Torso

						task.delay(.5,function()
							part.Parent:FindFirstChild("Stunned").Value = false
							part.Parent.Humanoid.WalkSpeed = part.Parent.Humanoid.WalkSpeed * 2
						end)

						for i = 0, 4 do
							task.delay(2 + i / 10, function()
								part.Parent.Humanoid:TakeDamage(1)
								char.Humanoid:TakeDamage(-1)
							end)
						end

						task.delay(2, lssound.Play, lssound)

						task.delay(4, function()
							lspart1:Destroy()
							lspart2:Destroy()
							lssound:Destroy()
						end)
					end


					stunhum()

					effect.Enabled = true
					btrail.Enabled = true

					local slashfx = tool.Effects.Slash.Attachment:Clone()
					slashfx.Parent = part.Parent:FindFirstChild("HumanoidRootPart")

					local r = math.random(-360,360)
					slashfx.slash.Rotation = NumberRange.new(r,r)

					task.wait(0.3)
					slashfx:Destroy()
				end

				task.wait(0.4)
				effect.Enabled = false
				btrail.Enabled = false
				canHit = false
			end
		end
	end

	local char = tool.Parent
	local root = char:WaitForChild("HumanoidRootPart")
	g = root:FindFirstChild("HitboxPart")

	Attack()
	-- slashes arent so random anymore
	tool.Handle.Trail.Enabled = true
	local humanoid = tool.Parent:FindFirstChild("Humanoid")
	
	if not slash then
		if randomSlash == 1 then
			slash = humanoid:LoadAnimation(anims.Attack1)
			randomSlash = 2
		elseif randomSlash == 2 then
			slash = humanoid:LoadAnimation(anims.Attack2)
			randomSlash = 3
		elseif randomSlash == 3 then
			slash = humanoid:LoadAnimation(anims.Attack3)
			randomSlash = 4
		elseif randomSlash == 4 then
			slash = humanoid:LoadAnimation(anims.Attack4)
			randomSlash = 1
		end
	end
	
	slash:Play()
	
	local val = tool.Parent.Attacking
	val.Value = true
	
	task.wait(.2)
	sounds.Slash:Play()
	
	task.wait(.4)
	
	if slash then
		slash = nil
	end
	
	tool.Handle.Trail.Enabled = false
	idle:Play()
	val.Value = false
	
	db = false
end)

tool.Unequipped:Connect(function()
	if idle then 
		idle:Stop() 
	end
	
	if equip then 
		equip:Stop()
		
		if slash then
			slash:Stop() 
		end
	end
end)
3 Likes

I replaced the code, and there was one initial error which was just a variable typo, but that was an easy fix. Now, though, it seems to be back to an issue with recognizing the NPC’s body. No errors in the output, and I put a couple prints in the script to debug it and it didn’t seem to make it past the for loop.

Prints:
image

Output:
image

I hate to bug you again, but after trying to troubleshoot it myself I’m stumped as to why it isn’t getting detected again. Any ideas?

1 Like

Could you tell me what this prints?

--//Variables
local tool = script.Parent
local hitbox = tool.HitboxPart
local anims = tool.Animations
local sounds = tool.Sounds

--//Controls
local db = false
local canHit = false
local randomSlash = 1
local equip
local slash
local idle
local g
local ws = workspace
local oparams = OverlapParams.new()
oparams.FilterType = Enum.RaycastFilterType.Exclude

-- hitbox weld stuff
tool.Equipped:Connect(function()
	local char = tool.Parent
	local root = char:WaitForChild("HumanoidRootPart")

	if root ~= nil and root:FindFirstChild("HitboxPart") ~= nil then
		root:FindFirstChild("HitboxPart"):Destroy()
	end

	if root ~= nil then
		g = hitbox:Clone()
		g.Anchored = false
		g.Parent = root
		local W = Instance.new("Weld")
		g.CFrame = root.CFrame * CFrame.new(0,0,-2.5)
		W.Part0 = root
		W.Part1 = g
		W.C0 = root.CFrame:Inverse()
		W.C1 = g.CFrame:Inverse()
		W.Parent = g

		--[[local Y = Instance.new("Weld")
		Y.Part0 = root
		Y.Part1 = g
		Y.C0 = CFrame.new(0, 0, 0)
		Y.Parent = Y.Part0--]]
	end

	-- restore a new hitbox
	if tool:FindFirstChild("HitboxPart") == nil then
		local newhit = g:Clone()
		newhit:ClearAllChildren()
		newhit.Parent = tool
		newhit.Anchored = true
	end

end)

-- get rid of the old hitbox
tool.Unequipped:Connect(function()
	if g then g:Destroy()
		g = nil
	end
end)

-- start up the animation stuff
tool.Equipped:Connect(function()
	sounds.Equip:Play()
	local humanoid = tool.Parent:FindFirstChild("Humanoid")
	if not equip then equip = humanoid:LoadAnimation(anims.Equip) end
	equip:Play()
	if not idle then idle = humanoid:LoadAnimation(anims.Idle) end
	idle.Priority = Enum.AnimationPriority.Movement
	idle:Play()
end)

-- light attack function
tool.Activated:Connect(function()
	local char = tool.Parent

	if char.stunned.Value or char.Dashing.Value or db then
		return
	end

	db = true
	idle:Stop()

	local function Attack()
		if not db or canHit then
			return
		end

		canHit = true

		local effect = tool.Handle.Blood
		local btrail = tool.Handle.BloodTrail
		local humanoidsDamaged = {}

		oparams.FilterDescendantsInstances = {char}

		local hits = ws:GetPartsInPart(g, oparams)
		print(hits)

		for i, part in ipairs(hits) do
			if part.Parent ~= char and part.Parent:FindFirstChild("Humanoid") and part.Parent:FindFirstChild("Dashing") and char.Stunned.Value == false then
				if not table.find(humanoidsDamaged, part.Parent.Humanoid) and part.Parent.Dashing.Value == false then
					table.insert(humanoidsDamaged, part.Parent.Humanoid)
					print("Humanoid damaged")
					local hitSFX = Instance.new("Sound",part.Parent.Head);
					hitSFX.SoundId = "rbxassetid://566593606"; hitSFX:Play()
					part.Parent.Humanoid:TakeDamage(5)

					-- I don't know any better way to do this
					local function stunhum()
						part.Parent:FindFirstChild("Stunned").Value = true
						part.Parent.Humanoid.WalkSpeed = part.Parent.Humanoid.WalkSpeed / 2
						
						local stunnum = math.random(1, 4)
						local stunanim = part.Parent.Humanoid:LoadAnimation(anims["Damaged".. stunnum])
						stunanim:Play()

						local lspart1 = tool.Handle.BLOOD02:Clone()
						local lspart2 = tool.Handle.BLOOD03:Clone()
						local lssound = tool.Sounds.Lifesteal:Clone()
						lspart1.Parent = part.Parent.Torso
						lspart2.Parent = part.Parent.Torso
						lssound.Parent = part.Parent.Torso

						task.delay(.5,function()
							part.Parent:FindFirstChild("Stunned").Value = false
							part.Parent.Humanoid.WalkSpeed = part.Parent.Humanoid.WalkSpeed * 2
						end)

						for i = 0, 4 do
							task.delay(2 + i / 10, function()
								part.Parent.Humanoid:TakeDamage(1)
								char.Humanoid:TakeDamage(-1)
							end)
						end

						task.delay(2, lssound.Play, lssound)

						task.delay(4, function()
							lspart1:Destroy()
							lspart2:Destroy()
							lssound:Destroy()
						end)
					end


					stunhum()

					effect.Enabled = true
					btrail.Enabled = true

					local slashfx = tool.Effects.Slash.Attachment:Clone()
					slashfx.Parent = part.Parent:FindFirstChild("HumanoidRootPart")

					local r = math.random(-360,360)
					slashfx.slash.Rotation = NumberRange.new(r)

					task.wait(0.3)
					slashfx:Destroy()
				end

				task.wait(0.4)
				effect.Enabled = false
				btrail.Enabled = false
				canHit = false
			end
		end
	end

	local char = tool.Parent
	local root = char:WaitForChild("HumanoidRootPart")
	g = root:FindFirstChild("HitboxPart")

	Attack()
	-- slashes arent so random anymore
	tool.Handle.Trail.Enabled = true
	local humanoid = tool.Parent:FindFirstChild("Humanoid")

	if not slash then
		slash = humanoid:LoadAnimation(anims["Attack".. randomSlash])
		
		if randomSlash == 4 then
			randomSlash = 1
		else
			randomSlash += 1
		end
	end

	slash:Play()

	local val = tool.Parent.Attacking
	val.Value = true

	task.wait(.2)
	sounds.Slash:Play()

	task.wait(.4)

	if slash then
		slash = nil
	end

	tool.Handle.Trail.Enabled = false
	idle:Play()
	val.Value = false

	db = false
end)

tool.Unequipped:Connect(function()
	if idle then 
		idle:Stop() 
	end

	if equip then 
		equip:Stop()

		if slash then
			slash:Stop() 
		end
	end
end)
1 Like

image

Empty curly brackets

1 Like

Okay, I’ve reverted to before I added some tidiness because I probably caused a logic error while doing so.

Try this:

local tool = script.Parent

local hitbox = tool.HitboxPart

local g

-- hitbox weld stuff
tool.Equipped:Connect(function()


	local char = tool.Parent
	local root = char:WaitForChild("HumanoidRootPart")

	if root ~= nil and root:FindFirstChild("HitboxPart") ~= nil then
		root:FindFirstChild("HitboxPart"):Destroy()
	end

	if root ~= nil then
		g = hitbox:Clone()
		g.Anchored = false
		g.Parent = root
		local W = Instance.new("Weld")
		g.CFrame = root.CFrame * CFrame.new(0,0,-2.5)
		W.Part0 = root
		W.Part1 = g
		W.C0 = root.CFrame:Inverse()
		W.C1 = g.CFrame:Inverse()
		W.Parent = g

		--[[local Y = Instance.new("Weld")
		Y.Part0 = root
		Y.Part1 = g
		Y.C0 = CFrame.new(0, 0, 0)
		Y.Parent = Y.Part0--]]
	end

	-- restore a new hitbox
	if tool:FindFirstChild("HitboxPart") == nil then
		local newhit = g:Clone()
		newhit:ClearAllChildren()
		newhit.Parent = tool
		newhit.Anchored = true
	end

end)

-- get rid of the old hitbox
tool.Unequipped:Connect(function()
	if g then g:Destroy()
		g = nil
	end
end)






-- more variables
local db = false

local canHit = false

local randomSlash = 1

local equip
local slash
local idle

-- folders
local anims = script.Parent.Animations
local sounds = script.Parent.Sounds

local ws = game:GetService("Workspace")



-- start up the animation stuff
script.Parent.Equipped:Connect(function()
	sounds.Equip:Play()
	local humanoid = script.Parent.Parent:FindFirstChild("Humanoid")
	if not equip then equip = humanoid:LoadAnimation(anims.Equip) end
	equip:Play()
	if not idle then idle = humanoid:LoadAnimation(anims.Idle) end
	idle.Priority = Enum.AnimationPriority.Movement
	idle:Play()
end)

-- light attack function
script.Parent.Activated:Connect(function()

	local char = tool.Parent

	if char.Stunned.Value == false and char.Dashing.Value == false and not db then
		db = true
		idle:Stop()


		local function Attack()
			if db == true then
				if not canHit then
					canHit = true
					local effect = script.Parent.Handle.Blood
					local btrail = script.Parent.Handle.BloodTrail

					local oparams = OverlapParams.new()
					oparams.FilterType = Enum.RaycastFilterType.Exclude
					oparams.FilterDescendantsInstances = {char}
					
					local humanoidsDamaged = {}

					local hits = ws:GetPartsInPart(g,oparams)

					for i = 1, #hits do
						local character = hits[i]:FindFirstAncestorWhichIsA('Model')
						local humanoid = character and character:FindFirstChildWhichIsA("Humanoid")
						
						if humanoid then
							print(character.Name)
						end
						
						if character ~= char and humanoid and hits[i].Parent:FindFirstChild("Dashing") and char.Stunned.Value == false then
							print("check 1 success")
							if hits[i].Parent.Dashing.Value == false and not table.find(humanoidsDamaged, humanoid) then
								table.insert(humanoidsDamaged, humanoid)
								print("check 2 success")
								local hitSFX = Instance.new("Sound",hits[i].Parent.Head);
								hitSFX.SoundId = "rbxassetid://566593606"; hitSFX:Play()
								hits[i].Parent.Humanoid:TakeDamage(5)

								-- I don't know any better way to do this
								local function stunhum()
									hits[i].Parent:FindFirstChild("Stunned").Value = true
									hits[i].Parent.Humanoid.WalkSpeed = hits[i].Parent.Humanoid.WalkSpeed / 2
									local stunnum = math.random(1, 4)
									local stunanim = hits[i].Parent.Humanoid:LoadAnimation(anims["Damaged".. stunnum])
									stunanim:Play()

									local lspart1 = tool.Handle.BLOOD02:Clone()
									local lspart2 = tool.Handle.BLOOD03:Clone()
									local lssound = tool.Sounds.Lifesteal:Clone()
									lspart1.Parent = hits[i].Parent.Torso
									lspart2.Parent = hits[i].Parent.Torso
									lssound.Parent = hits[i].Parent.Torso

									task.delay(.5,function()
										hits[i].Parent:FindFirstChild("Stunned").Value = false
										hits[i].Parent.Humanoid.WalkSpeed = hits[i].Parent.Humanoid.WalkSpeed * 2
									end)
									-- blood drain stuff, kinda messy
									task.delay(2,function()
										hits[i].Parent.Humanoid:TakeDamage(1)
										char.Humanoid:TakeDamage(-1)
										lssound:Play()
									end)
									task.delay(2.1,function()
										hits[i].Parent.Humanoid:TakeDamage(1)
										char.Humanoid:TakeDamage(-1)
									end)
									task.delay(2.2,function()
										hits[i].Parent.Humanoid:TakeDamage(1)
										char.Humanoid:TakeDamage(-1)
									end)
									task.delay(2.3,function()
										hits[i].Parent.Humanoid:TakeDamage(1)
										char.Humanoid:TakeDamage(-1)
									end)
									task.delay(2.4,function()
										hits[i].Parent.Humanoid:TakeDamage(1)
										char.Humanoid:TakeDamage(-1)
									end)

									task.delay(4,function()
										lspart1:Destroy()
										lspart2:Destroy()
										lssound:Destroy()
									end)
								end


								stunhum()


								effect.Enabled = true
								btrail.Enabled = true

								local slashfx = tool.Effects.Slash.Attachment:Clone()
								slashfx.Parent = hits[i].Parent:FindFirstChild("HumanoidRootPart")
								local r = math.random(-360,360)
								slashfx.slash.Rotation = NumberRange.new(r)
								task.wait(0.3)
								slashfx:Destroy()

							end
							task.wait(0.4)
							effect.Enabled = false
							btrail.Enabled = false
							canHit = false
						end
					end
				end
			end
		end

		local char = tool.Parent
		local root = char:WaitForChild("HumanoidRootPart")
		g = root:FindFirstChild("HitboxPart")

		Attack()
		-- slashes arent so random anymore
		script.Parent.Handle.Trail.Enabled = true
		local humanoid = script.Parent.Parent:FindFirstChild("Humanoid")
		
		if not slash then
			slash = humanoid:LoadAnimation(anims["Attack".. randomSlash])
			
			if randomSlash == 4 then
				randomSlash = 1
			else
				randomSlash += 1
			end
		end
		
		slash:Play()
		local val = tool.Parent.Attacking
		val.Value = true
		task.wait(.2)
		sounds.Slash:Play()
		task.wait(.4)
		if slash then
			slash = nil
		end
		script.Parent.Handle.Trail.Enabled = false
		db = false
		idle:Play()
		val.Value = false
	end
end)
-- stop animations
script.Parent.Unequipped:Connect(function()
	if idle then idle:Stop() end
	if equip then equip:Stop()
		if slash then slash:Stop() end
	end
end)
1 Like

Same problem, and nothing printed.

1 Like

That’s really weird then, could you try the code from where it worked?

1 Like


I changed the code back to as it was the first time that the hits registered, and this is what happens. I thought it might have hit him 6 times because that’s the amount of body parts he has, but it only sliced him 5 times. And what confuses me even more is that the slash animation plays AFTER the attack has already run its course, so I’m honestly clueless as to what’s going wrong, or why it’s being so difficult with acknowledging parts in its radius. I might end up switching to a different hitbox solution at this rate, but I wouldn’t know where to start.

1 Like

Hmm, the thing I’m confused about how it’s not printing anything (meaning no parts in parts) but somehow works when we switch it back?

Tell me what this prints, I made a really barebones implementation but I hope it works:

local tool = script.Parent

local hitbox = tool.HitboxPart

local g

-- hitbox weld stuff
tool.Equipped:Connect(function()


	local char = tool.Parent
	local root = char:WaitForChild("HumanoidRootPart")

	if root ~= nil and root:FindFirstChild("HitboxPart") ~= nil then
		root:FindFirstChild("HitboxPart"):Destroy()
	end

	if root ~= nil then
		g = hitbox:Clone()
		g.Anchored = false
		g.Parent = root
		local W = Instance.new("Weld")
		g.CFrame = root.CFrame * CFrame.new(0,0,-2.5)
		W.Part0 = root
		W.Part1 = g
		W.C0 = root.CFrame:Inverse()
		W.C1 = g.CFrame:Inverse()
		W.Parent = g

		--[[local Y = Instance.new("Weld")
		Y.Part0 = root
		Y.Part1 = g
		Y.C0 = CFrame.new(0, 0, 0)
		Y.Parent = Y.Part0--]]
	end

	-- restore a new hitbox
	if tool:FindFirstChild("HitboxPart") == nil then
		local newhit = g:Clone()
		newhit:ClearAllChildren()
		newhit.Parent = tool
		newhit.Anchored = true
	end

end)

-- get rid of the old hitbox
tool.Unequipped:Connect(function()
	if g then g:Destroy()
		g = nil
	end
end)






-- more variables
local db = false

local canHit = false

local randomSlash = 1

local equip
local slash
local idle

-- folders
local anims = script.Parent.Animations
local sounds = script.Parent.Sounds

local ws = game:GetService("Workspace")



-- start up the animation stuff
script.Parent.Equipped:Connect(function()
	sounds.Equip:Play()
	local humanoid = script.Parent.Parent:FindFirstChild("Humanoid")
	if not equip then equip = humanoid:LoadAnimation(anims.Equip) end
	equip:Play()
	if not idle then idle = humanoid:LoadAnimation(anims.Idle) end
	idle.Priority = Enum.AnimationPriority.Movement
	idle:Play()
end)

-- light attack function
script.Parent.Activated:Connect(function()

	local char = tool.Parent

	if char.Stunned.Value == false and char.Dashing.Value == false and not db then
		db = true
		idle:Stop()


		local function Attack()
			if db == true then
				if not canHit then
					canHit = true
					local effect = script.Parent.Handle.Blood
					local btrail = script.Parent.Handle.BloodTrail

					local oparams = OverlapParams.new()
					oparams.FilterType = Enum.RaycastFilterType.Exclude
					oparams.FilterDescendantsInstances = {char}

					local humanoidsDamaged = {}

					local hits = ws:GetPartsInPart(g,oparams)

					for i = 1, #hits do
						print(hits[i]:FindFirstAncestorWhichIsA('Model'))

						if hits[i].Parent ~= char and hits[i].Parent:FindFirstChild("Humanoid") and hits[i].Parent:FindFirstChild("Dashing") and char.Stunned.Value == false then
							print("check 1 success")
							if hits[i].Parent.Dashing.Value == false and not table.find(humanoidsDamaged, hits[i].Parent.Parent) then
								table.insert(humanoidsDamaged, hits[i].Parent.Parent)
								print("check 2 success")
								local hitSFX = Instance.new("Sound",hits[i].Parent.Head);
								hitSFX.SoundId = "rbxassetid://566593606"; hitSFX:Play()
								hits[i].Parent.Humanoid:TakeDamage(5)

								-- I don't know any better way to do this
								local function stunhum()
									hits[i].Parent:FindFirstChild("Stunned").Value = true
									hits[i].Parent.Humanoid.WalkSpeed = hits[i].Parent.Humanoid.WalkSpeed / 2
									local stunnum = math.random(1, 4)
									local stunanim = hits[i].Parent.Humanoid:LoadAnimation(anims["Damaged".. stunnum])
									stunanim:Play()

									local lspart1 = tool.Handle.BLOOD02:Clone()
									local lspart2 = tool.Handle.BLOOD03:Clone()
									local lssound = tool.Sounds.Lifesteal:Clone()
									lspart1.Parent = hits[i].Parent.Torso
									lspart2.Parent = hits[i].Parent.Torso
									lssound.Parent = hits[i].Parent.Torso

									task.delay(.5,function()
										hits[i].Parent:FindFirstChild("Stunned").Value = false
										hits[i].Parent.Humanoid.WalkSpeed = hits[i].Parent.Humanoid.WalkSpeed * 2
									end)
									-- blood drain stuff, kinda messy
									task.delay(2,function()
										hits[i].Parent.Humanoid:TakeDamage(1)
										char.Humanoid:TakeDamage(-1)
										lssound:Play()
									end)
									task.delay(2.1,function()
										hits[i].Parent.Humanoid:TakeDamage(1)
										char.Humanoid:TakeDamage(-1)
									end)
									task.delay(2.2,function()
										hits[i].Parent.Humanoid:TakeDamage(1)
										char.Humanoid:TakeDamage(-1)
									end)
									task.delay(2.3,function()
										hits[i].Parent.Humanoid:TakeDamage(1)
										char.Humanoid:TakeDamage(-1)
									end)
									task.delay(2.4,function()
										hits[i].Parent.Humanoid:TakeDamage(1)
										char.Humanoid:TakeDamage(-1)
									end)

									task.delay(4,function()
										lspart1:Destroy()
										lspart2:Destroy()
										lssound:Destroy()
									end)
								end


								stunhum()


								effect.Enabled = true
								btrail.Enabled = true

								local slashfx = tool.Effects.Slash.Attachment:Clone()
								slashfx.Parent = hits[i].Parent:FindFirstChild("HumanoidRootPart")
								local r = math.random(-360,360)
								slashfx.slash.Rotation = NumberRange.new(r)
								task.wait(0.3)
								slashfx:Destroy()

							end
							task.wait(0.4)
							effect.Enabled = false
							btrail.Enabled = false
							canHit = false
						end
					end
				end
			end
		end

		local char = tool.Parent
		local root = char:WaitForChild("HumanoidRootPart")
		g = root:FindFirstChild("HitboxPart")

		Attack()
		-- slashes arent so random anymore
		script.Parent.Handle.Trail.Enabled = true
		local humanoid = script.Parent.Parent:FindFirstChild("Humanoid")

		if not slash then
			slash = humanoid:LoadAnimation(anims["Attack".. randomSlash])

			if randomSlash == 4 then
				randomSlash = 1
			else
				randomSlash += 1
			end
		end

		slash:Play()
		local val = tool.Parent.Attacking
		val.Value = true
		task.wait(.2)
		sounds.Slash:Play()
		task.wait(.4)
		if slash then
			slash = nil
		end
		script.Parent.Handle.Trail.Enabled = false
		db = false
		idle:Play()
		val.Value = false
	end
end)
-- stop animations
script.Parent.Unequipped:Connect(function()
	if idle then idle:Stop() end
	if equip then equip:Stop()
		if slash then slash:Stop() end
	end
end)
1 Like

I think we’re finally getting closer to a solution!

image
This is what it printed, and it actually only hit the NPC once. Here’s a video:


However, after a few hits it seems to stop working again. (Had to reset my character to record the first video)

2 Likes

Do you mean it only works once? Or does it actually work multiple times and then stops?

2 Likes

I just went and tested it, and on multiple occasions it didn’t even hit him at all. On one test, I was able to hit him enough times to kill him and once he respawned it wouldn’t let me damage him again. When I WAS hitting him though, just imagine the first video of my last post but played over multiple times and that’s what it was like.

I’m so lost at this point, I can’t even start to theorize on what the issue COULD be.

1 Like

I moved the functions around so could you try this?

local tool = script.Parent

local hitbox = tool.HitboxPart

local g

-- hitbox weld stuff
tool.Equipped:Connect(function()


	local char = tool.Parent
	local root = char:WaitForChild("HumanoidRootPart")

	if root ~= nil and root:FindFirstChild("HitboxPart") ~= nil then
		root:FindFirstChild("HitboxPart"):Destroy()
	end

	if root ~= nil then
		g = hitbox:Clone()
		g.Anchored = false
		g.Parent = root
		local W = Instance.new("Weld")
		g.CFrame = root.CFrame * CFrame.new(0,0,-2.5)
		W.Part0 = root
		W.Part1 = g
		W.C0 = root.CFrame:Inverse()
		W.C1 = g.CFrame:Inverse()
		W.Parent = g

		--[[local Y = Instance.new("Weld")
		Y.Part0 = root
		Y.Part1 = g
		Y.C0 = CFrame.new(0, 0, 0)
		Y.Parent = Y.Part0--]]
	end

	-- restore a new hitbox
	if tool:FindFirstChild("HitboxPart") == nil then
		local newhit = g:Clone()
		newhit:ClearAllChildren()
		newhit.Parent = tool
		newhit.Anchored = true
	end

end)

-- get rid of the old hitbox
tool.Unequipped:Connect(function()
	if g then g:Destroy()
		g = nil
	end
end)






-- more variables
local db = false

local canHit = false

local randomSlash = 1

local equip
local slash
local idle

-- folders
local anims = script.Parent.Animations
local sounds = script.Parent.Sounds

local ws = game:GetService("Workspace")

local function Attack(char)
	if canHit then
		return
	end
	
	canHit = true
	local effect = script.Parent.Handle.Blood
	local btrail = script.Parent.Handle.BloodTrail

	local oparams = OverlapParams.new()
	oparams.FilterType = Enum.RaycastFilterType.Exclude
	oparams.FilterDescendantsInstances = {char}

	local humanoidsDamaged = {}

	local hits = ws:GetPartsInPart(g,oparams)
	print("Parts found:", hits)
	print("Humanoids damaged:", humanoidsDamaged)

	for i = 1, #hits do
		print(hits[i]:FindFirstAncestorWhichIsA('Model'))

		if hits[i].Parent ~= char and hits[i].Parent:FindFirstChild("Humanoid") and hits[i].Parent:FindFirstChild("Dashing") and char.Stunned.Value == false then
			print("check 1 success")
			if hits[i].Parent.Dashing.Value == false and not table.find(humanoidsDamaged, hits[i].Parent.Parent) then
				table.insert(humanoidsDamaged, hits[i].Parent.Parent)
				print("check 2 success")
				local hitSFX = Instance.new("Sound",hits[i].Parent.Head);
				hitSFX.SoundId = "rbxassetid://566593606"; hitSFX:Play()
				hits[i].Parent.Humanoid:TakeDamage(5)

				-- I don't know any better way to do this
				local function stunhum()
					hits[i].Parent:FindFirstChild("Stunned").Value = true
					hits[i].Parent.Humanoid.WalkSpeed = hits[i].Parent.Humanoid.WalkSpeed / 2
					local stunnum = math.random(1, 4)
					local stunanim = hits[i].Parent.Humanoid:LoadAnimation(anims["Damaged".. stunnum])
					stunanim:Play()

					local lspart1 = tool.Handle.BLOOD02:Clone()
					local lspart2 = tool.Handle.BLOOD03:Clone()
					local lssound = tool.Sounds.Lifesteal:Clone()
					lspart1.Parent = hits[i].Parent.Torso
					lspart2.Parent = hits[i].Parent.Torso
					lssound.Parent = hits[i].Parent.Torso

					task.delay(.5,function()
						hits[i].Parent:FindFirstChild("Stunned").Value = false
						hits[i].Parent.Humanoid.WalkSpeed = hits[i].Parent.Humanoid.WalkSpeed * 2
					end)
					-- blood drain stuff, kinda messy
					task.delay(2,function()
						hits[i].Parent.Humanoid:TakeDamage(1)
						char.Humanoid:TakeDamage(-1)
						lssound:Play()
					end)
					task.delay(2.1,function()
						hits[i].Parent.Humanoid:TakeDamage(1)
						char.Humanoid:TakeDamage(-1)
					end)
					task.delay(2.2,function()
						hits[i].Parent.Humanoid:TakeDamage(1)
						char.Humanoid:TakeDamage(-1)
					end)
					task.delay(2.3,function()
						hits[i].Parent.Humanoid:TakeDamage(1)
						char.Humanoid:TakeDamage(-1)
					end)
					task.delay(2.4,function()
						hits[i].Parent.Humanoid:TakeDamage(1)
						char.Humanoid:TakeDamage(-1)
					end)

					task.delay(4,function()
						lspart1:Destroy()
						lspart2:Destroy()
						lssound:Destroy()
					end)
				end


				stunhum()


				effect.Enabled = true
				btrail.Enabled = true

				local slashfx = tool.Effects.Slash.Attachment:Clone()
				slashfx.Parent = hits[i].Parent:FindFirstChild("HumanoidRootPart")
				local r = math.random(-360,360)
				slashfx.slash.Rotation = NumberRange.new(r)
				task.wait(0.3)
				slashfx:Destroy()
			end
			
			task.wait(0.4)
			effect.Enabled = false
			btrail.Enabled = false
			canHit = false
		end
	end
end

-- start up the animation stuff
script.Parent.Equipped:Connect(function()
	sounds.Equip:Play()
	local humanoid = script.Parent.Parent:FindFirstChild("Humanoid")
	if not equip then equip = humanoid:LoadAnimation(anims.Equip) end
	equip:Play()
	if not idle then idle = humanoid:LoadAnimation(anims.Idle) end
	idle.Priority = Enum.AnimationPriority.Movement
	idle:Play()
end)

-- light attack function
script.Parent.Activated:Connect(function()

	local char = tool.Parent

	if char.Stunned.Value == false and char.Dashing.Value == false and not db then
		db = true
		idle:Stop()
		local char = tool.Parent
		local root = char:WaitForChild("HumanoidRootPart")
		g = root:FindFirstChild("HitboxPart")
		
		print("Started attack")
		Attack(char)	
		-- slashes arent so random anymore
		script.Parent.Handle.Trail.Enabled = true
		local humanoid = script.Parent.Parent:FindFirstChild("Humanoid")

		if not slash then
			slash = humanoid:LoadAnimation(anims["Attack".. randomSlash])

			if randomSlash == 4 then
				randomSlash = 1
			else
				randomSlash += 1
			end
		end

		slash:Play()
		local val = tool.Parent.Attacking
		val.Value = true
		task.wait(.2)
		sounds.Slash:Play()
		task.wait(.4)
		if slash then
			slash = nil
		end
		script.Parent.Handle.Trail.Enabled = false
		db = false
		idle:Play()
		val.Value = false
	end
end)
-- stop animations
script.Parent.Unequipped:Connect(function()
	if idle then idle:Stop() end
	if equip then equip:Stop()
		if slash then slash:Stop() end
	end
end)

Make sure to tell me anything that prints.

Can you also show me the code you used in your original .Touched script?

It printed this.
image
Same issue with no detection.

However, I did come up with something myself last night and I think I was pretty close. Instead of using the hitbox that was welded to the player’s rootpart, I cloned and repositioned a preset hitbox which was inside of the tool, and put it inside one of my workspace folders and used CFrame to position it in front of the player. I figured the welded hitbox method might be inefficient for GetPartsInPart() detection, so I tried this and tested it. I was actually able to get a few hits in. I got excited, but after enough hits it stopped creating new hitboxes.

Here’s the code that somewhat works. The hitbox spawning stuff you can find in the Attack() function, and the only other thing I changed was replacing some task.waits with task.delays later in the script, which fixed the dissonance between the swing animation and the Attack() function.

local tool = script.Parent

local hitbox = tool.HitboxPart

local g

-- hitbox weld stuff
tool.Equipped:Connect(function()


	local char = tool.Parent
	local root = char:WaitForChild("HumanoidRootPart")

	if root ~= nil and root:FindFirstChild("HitboxPart") ~= nil then
		root:FindFirstChild("HitboxPart"):Destroy()
	end

	if root ~= nil then
		g = hitbox:Clone()
		g.Anchored = false
		g.Parent = root
		local W = Instance.new("Weld")
		g.CFrame = root.CFrame * CFrame.new(0,0,-2.5)
		W.Part0 = root
		W.Part1 = g
		W.C0 = root.CFrame:Inverse()
		W.C1 = g.CFrame:Inverse()
		W.Parent = g

		--[[local Y = Instance.new("Weld")
		Y.Part0 = root
		Y.Part1 = g
		Y.C0 = CFrame.new(0, 0, 0)
		Y.Parent = Y.Part0--]]
	end

	-- restore a new hitbox
	if tool:FindFirstChild("HitboxPart") == nil then
		local newhit = g:Clone()
		newhit:ClearAllChildren()
		newhit.Parent = tool
		newhit.Anchored = true
	end

end)

-- get rid of the old hitbox
tool.Unequipped:Connect(function()
	if g then g:Destroy()
		g = nil
	end
end)






-- more variables
local db = false

local canHit = false

local randomSlash = 1

local equip
local slash
local idle

-- folders
local anims = script.Parent.Animations
local sounds = script.Parent.Sounds

local ws = game:GetService("Workspace")

local box = tool.box


-- start up the animation stuff
script.Parent.Equipped:Connect(function()
	sounds.Equip:Play()
	local humanoid = script.Parent.Parent:FindFirstChild("Humanoid")
	if not equip then equip = humanoid:LoadAnimation(anims.Equip) end
	equip:Play()
	if not idle then idle = humanoid:LoadAnimation(anims.Idle) end
	idle.Priority = Enum.AnimationPriority.Movement
	idle:Play()
end)

-- light attack function
script.Parent.Activated:Connect(function()

	local char = tool.Parent

	if char.Stunned.Value == false and char.Dashing.Value == false and not db then
		db = true
		idle:Stop()


		local function Attack()
			if db == true then
				if not canHit then
					canHit = true
					local effect = script.Parent.Handle.Blood
					local btrail = script.Parent.Handle.BloodTrail

					local oparams = OverlapParams.new()
					oparams.FilterType = Enum.RaycastFilterType.Exclude
					oparams.FilterDescendantsInstances = {char}

					local humanoidsDamaged = {}
					
					local boxc = box:Clone() -- box is an identical version of the original hitbox, but anchored and unwelded. its parent is the tool.	
					box.Parent = ws.Scripted -- Scripted is a folder in the workspace
					box.CFrame = char.HumanoidRootPart.CFrame * CFrame.new(0,0,-3.5)
						
					local hits = ws:GetPartsInPart(box,oparams)

					for i = 1, #hits do
						print(hits[i]:FindFirstAncestorWhichIsA('Model'))

						if hits[i].Parent ~= char and hits[i].Parent:FindFirstChild("Humanoid") and hits[i].Parent:FindFirstChild("Dashing") and char.Stunned.Value == false then
							print("check 1 success")
							if hits[i].Parent.Dashing.Value == false and not table.find(humanoidsDamaged, hits[i].Parent.Parent) then
								table.insert(humanoidsDamaged, hits[i].Parent.Parent)
								print("check 2 success")
								local hitSFX = Instance.new("Sound",hits[i].Parent.Head);
								hitSFX.SoundId = "rbxassetid://566593606"; hitSFX:Play()
								hits[i].Parent.Humanoid:TakeDamage(5)

								-- I don't know any better way to do this
								local function stunhum()
									hits[i].Parent:FindFirstChild("Stunned").Value = true
									hits[i].Parent.Humanoid.WalkSpeed = hits[i].Parent.Humanoid.WalkSpeed / 2
									local stunnum = math.random(1, 4)
									local stunanim = hits[i].Parent.Humanoid:LoadAnimation(anims["Damaged".. stunnum])
									stunanim:Play()

									local lspart1 = tool.Handle.BLOOD02:Clone()
									local lspart2 = tool.Handle.BLOOD03:Clone()
									local lssound = tool.Sounds.Lifesteal:Clone()
									lspart1.Parent = hits[i].Parent.Torso
									lspart2.Parent = hits[i].Parent.Torso
									lssound.Parent = hits[i].Parent.Torso

									task.delay(.5,function()
										hits[i].Parent:FindFirstChild("Stunned").Value = false
										hits[i].Parent.Humanoid.WalkSpeed = hits[i].Parent.Humanoid.WalkSpeed * 2
									end)
									-- blood drain stuff, kinda messy
									task.delay(2,function()
										hits[i].Parent.Humanoid:TakeDamage(1)
										char.Humanoid:TakeDamage(-1)
										lssound:Play()
									end)
									task.delay(2.1,function()
										hits[i].Parent.Humanoid:TakeDamage(1)
										char.Humanoid:TakeDamage(-1)
									end)
									task.delay(2.2,function()
										hits[i].Parent.Humanoid:TakeDamage(1)
										char.Humanoid:TakeDamage(-1)
									end)
									task.delay(2.3,function()
										hits[i].Parent.Humanoid:TakeDamage(1)
										char.Humanoid:TakeDamage(-1)
									end)
									task.delay(2.4,function()
										hits[i].Parent.Humanoid:TakeDamage(1)
										char.Humanoid:TakeDamage(-1)
									end)

									task.delay(4,function()
										lspart1:Destroy()
										lspart2:Destroy()
										lssound:Destroy()
									end)
								end


								stunhum()


								effect.Enabled = true
								btrail.Enabled = true

								local slashfx = tool.Effects.Slash.Attachment:Clone()
								slashfx.Parent = hits[i].Parent:FindFirstChild("HumanoidRootPart")
								local r = math.random(-360,360)
								slashfx.slash.Rotation = NumberRange.new(r)
								task.delay(0.3,function()
									slashfx:Destroy()
								end)

							end
							task.delay(0.4,function()
								effect.Enabled = false
								btrail.Enabled = false
								canHit = false
								box.Parent = tool
							end)
							end
						
					end
				end
			end
		end

		local char = tool.Parent
		local root = char:WaitForChild("HumanoidRootPart")
		g = root:FindFirstChild("HitboxPart")

		Attack()
		-- slashes arent so random anymore
		script.Parent.Handle.Trail.Enabled = true
		local humanoid = script.Parent.Parent:FindFirstChild("Humanoid")

		if not slash then
			slash = humanoid:LoadAnimation(anims["Attack".. randomSlash])

			if randomSlash == 4 then
				randomSlash = 1
			else
				randomSlash += 1
			end
		end

		slash:Play()
		local val = tool.Parent.Attacking
		val.Value = true
		task.wait(.2)
		sounds.Slash:Play()
		task.wait(.4)
		if slash then
			slash = nil
		end
		script.Parent.Handle.Trail.Enabled = false
		db = false
		idle:Play()
		val.Value = false
	end
end)
-- stop animations
script.Parent.Unequipped:Connect(function()
	if idle then idle:Stop() end
	if equip then equip:Stop()
		if slash then slash:Stop() end
	end
end)

Here’s what that prints:
image

The issue seems to be something with the cleanup of the clones. There were a couple leftover in the Scripted folder, and I could see them sitting out in the open after I was done fighting the NPC. That’s right when it stopped summoning new clones.
image
image

I think it has something to do with the boxc variable being sloppily reassigned to something new, and then it messes up the whole function. And, something I just noticed when writing this is that the original box disappeared from the tool. I was way too tired to figure it out last night, so I called it a day knowing most of the issues were fixed.

image

Here’s the code in my original .Touched script, if you’re still wondering about that.


local tool = script.Parent

local hitbox = tool.HitboxPart

local g

tool.Equipped:Connect(function()


	local char = tool.Parent
	local root = char:WaitForChild("HumanoidRootPart")

	if root ~= nil and root:FindFirstChild("HitboxPart") ~= nil then
		root:FindFirstChild("HitboxPart"):Destroy()
	end

	if root ~= nil then
		g = hitbox:Clone()
		g.Anchored = false
		g.Parent = root
		local W = Instance.new("Weld")
		g.CFrame = root.CFrame * CFrame.new(0,0,-2.5)
		W.Part0 = root
		W.Part1 = g
		W.C0 = root.CFrame:Inverse()
		W.C1 = g.CFrame:Inverse()
		W.Parent = g

		--[[local Y = Instance.new("Weld")
		Y.Part0 = root
		Y.Part1 = g
		Y.C0 = CFrame.new(0, 0, 0)
		Y.Parent = Y.Part0--]]
	end

	if tool:FindFirstChild("HitboxPart") == nil then
		local newhit = g:Clone()
		newhit:ClearAllChildren()
		newhit.Parent = tool
		newhit.Anchored = true
	end

end)

tool.Unequipped:Connect(function()
	if g then g:Destroy()
		g = nil
	end
	end)







local db = false

local canHit = false

local randomSlash = 1

local equip
local slash
local idle

local anims = script.Parent.Animations
local sounds = script.Parent.Sounds




script.Parent.Equipped:Connect(function()
	sounds.Equip:Play()
	local humanoid = script.Parent.Parent:FindFirstChild("Humanoid")
	if not equip then equip = humanoid:LoadAnimation(anims.Equip) end
	equip:Play()
	if not idle then idle = humanoid:LoadAnimation(anims.Idle) end
	idle.Priority = Enum.AnimationPriority.Movement
	idle:Play()
end)


script.Parent.Activated:Connect(function()
	
	local char = tool.Parent
	
	if char.Stunned.Value == false and not db then
		db = true
		idle:Stop()
		
		
		local function Attack(hit)
			if db then
				if not canHit then
					canHit = true
					local effect = script.Parent.Handle.Blood
					local btrail = script.Parent.Handle.BloodTrail
					if hit.Parent:FindFirstChild("Humanoid") and hit.Parent:FindFirstChild("Dashing").Value == false and char.Stunned.Value == false then
						local hitSFX = Instance.new("Sound",hit.Parent.Head); hitSFX.SoundId = "rbxassetid://566593606"; hitSFX:Play()
						hit.Parent.Humanoid:TakeDamage(5)
						
						
						local function stunhum()
							hit.Parent:FindFirstChild("Stunned").Value = true
							hit.Parent.Humanoid.WalkSpeed = hit.Parent.Humanoid.WalkSpeed / 2
							local stunnum = math.random(1,4)
							if stunnum == 1 then
								local stunanim = hit.Parent.Humanoid:LoadAnimation(anims.Damaged1)
								stunanim:Play()
							elseif stunnum == 2 then
								local stunanim = hit.Parent.Humanoid:LoadAnimation(anims.Damaged2)
								stunanim:Play()
							elseif stunnum == 3 then
								local stunanim = hit.Parent.Humanoid:LoadAnimation(anims.Damaged3)
								stunanim:Play()
								
							elseif stunnum == 4 then
								local stunanim = hit.Parent.Humanoid:LoadAnimation(anims.Damaged4)
								stunanim:Play()
							end
							
							local lspart1 = tool.Handle.BLOOD02:Clone()
							local lspart2 = tool.Handle.BLOOD03:Clone()
							local lssound = tool.Sounds.Lifesteal:Clone()
							lspart1.Parent = hit.Parent.Torso
							lspart2.Parent = hit.Parent.Torso
							lssound.Parent = hit.Parent.Torso
							
							delay(.5,function()
								hit.Parent:FindFirstChild("Stunned").Value = false
								hit.Parent.Humanoid.WalkSpeed = hit.Parent.Humanoid.WalkSpeed * 2
							end)
							
							delay(2,function()
								hit.Parent.Humanoid:TakeDamage(1)
								char.Humanoid:TakeDamage(-1)
								lssound:Play()
							end)
							delay(2.1,function()
								hit.Parent.Humanoid:TakeDamage(1)
								char.Humanoid:TakeDamage(-1)
							end)
							delay(2.2,function()
								hit.Parent.Humanoid:TakeDamage(1)
								char.Humanoid:TakeDamage(-1)
							end)
							delay(2.3,function()
								hit.Parent.Humanoid:TakeDamage(1)
								char.Humanoid:TakeDamage(-1)
							end)
							delay(2.4,function()
								hit.Parent.Humanoid:TakeDamage(1)
								char.Humanoid:TakeDamage(-1)
							end)
							
							delay(4,function()
								lspart1:Destroy()
								lspart2:Destroy()
								lssound:Destroy()
							end)
						end
						
						
						stunhum()

						
						effect.Enabled = true
						btrail.Enabled = true
						
						local slashfx = tool.Effects.Slash.Attachment:Clone()
						slashfx.Parent = hit.Parent:FindFirstChild("HumanoidRootPart")
						local r = math.random(-360,360)
						slashfx.slash.Rotation = NumberRange.new(r,r)
						wait(0.3)
						slashfx:Destroy()

					end
					wait(0.4)
					effect.Enabled = false
					btrail.Enabled = false
					canHit = false
				end
			end
		end
		
		local char = tool.Parent
		local root = char:WaitForChild("HumanoidRootPart")
		g = root:FindFirstChild("HitboxPart")
		
		g.Touched:Connect(Attack)
		
			script.Parent.Handle.Trail.Enabled = true
		local humanoid = script.Parent.Parent:FindFirstChild("Humanoid")
		if not slash then
			if randomSlash == 1 then
				slash = humanoid:LoadAnimation(anims.Attack1)
				randomSlash = 2
			elseif randomSlash == 2 then
				slash = humanoid:LoadAnimation(anims.Attack2)
				randomSlash = 3
			elseif randomSlash == 3 then
				slash = humanoid:LoadAnimation(anims.Attack3)
				randomSlash = 4
			elseif randomSlash == 4 then
				slash = humanoid:LoadAnimation(anims.Attack4)
				randomSlash = 1
			end
		end
		slash:Play()
		local val = tool.Parent.Attacking
		val.Value = true
		wait(.2)
		sounds.Slash:Play()
		wait(.4)
		if slash then
			slash = nil
		end
		script.Parent.Handle.Trail.Enabled = false
		db = false
		idle:Play()
		val.Value = false
	end
end)


script.Parent.Unequipped:Connect(function()
	if idle then idle:Stop() end
	if equip then equip:Stop()
		if slash then slash:Stop() end
	end
end)


Yea this is definitely why it returned nothing. Also I realized a major logic problem in your script. canHit decides whether or not you can use your weapon right? But you have a problem with assigning values to it.

The part that turns canHit back to false is in here:

if hits[i].Parent ~= char and hits[i].Parent:FindFirstChild("Humanoid") and hits[i].Parent:FindFirstChild("Dashing") and char.Stunned.Value == false then

end

The problem is that let’s say this if statement doesn’t follow through, and your canHit still stays as true. This means you can never attack again, because when the function runs, it checks if canHit is false (which it will never be, because you set it to true). Find a way to fix that logic problem, because it’s almost definitely the reason why you’re experiencing this lack of attack functionality (among some other things you already figured out).

1 Like

Thank you so much for pointing that out! I fixed the cloning and canHit issues and now the weapon works like a charm.

Thanks again for all your help, man. I’m super grateful for your dedication to helping me get this script working, and all the things I learned like guard clauses and tables, which I had never used before. I probably would’ve just grit my teeth and stuck with the .Touched hitboxes if not for you, so I can’t thank you enough for that.

Case closed, have a good one Katrist.

2 Likes