Weapon Randomly One Shots

Weapon randomly one shots. Not sure why. This isnt a tool but a model attached to player via motor 6d. I have posted about this before, yet i have changed my script so i thought i should ask again. Please any ideas?

local function stopSwing() 
	task.wait(.2)
	swingCheck = false
	debounce = false
	damageCount = 0
	hitboxTrue = false
	hitBoxCount = 0
end
script.Parent.SwordCombatRemote.OnServerEvent:Connect(function(player)
	if swingCheck then return end
	swingCheck = true
	local character = player.Character
	if character.IsRagdoll.Value then
		swingCheck = false
		return
	end
	local Hum = character:WaitForChild("Humanoid")
	if Combo == 1 then
		playAnim = Hum:LoadAnimation(anim)
		playAnim:Play()
		Combo = 2
	elseif Combo == 2 then
		playAnim = Hum:LoadAnimation(anim2)
		playAnim:Play()
		Combo = 1
	end
	task.wait(0.25)
	sound:Play()
	if hitboxTrue == false then
		hitboxTrue = true
		hitBoxCount += 1
		print(hitBoxCount)
		if hitBoxCount < 2 then
			print("made", character.Name)
			local physicalBox = Instance.new("Part", character)
			physicalBox.Name = "Hitbox"
			physicalBox.Transparency = 0.6
			physicalBox.Anchored = false
			physicalBox.CanCollide = false
			physicalBox.Size = Vector3.new(5.5, 2.5, 5.5)
			physicalBox.Massless = true
			physicalBox.CFrame = character.HumanoidRootPart.CFrame * CFrame.new(0, 0, -3.5)
			physicalBox.Parent = character.HumanoidRootPart

			local weld = Instance.new("WeldConstraint")
			weld.Part0 = character.HumanoidRootPart
			weld.Part1 = physicalBox
			weld.Parent = character.HumanoidRootPart
			game.Debris:AddItem(weld, 0.5)
			game.Debris:AddItem(physicalBox, 0.5)
			local affected = {}
			local TouchEvent
			task.wait()
			TouchEvent = physicalBox.Touched:Connect(function(hit) 
				if debounce == true then
					return
				else 
					debounce = true
				end
				if hit.Parent:FindFirstChild("Humanoid") ~= nil then
					if hit.Parent ~= character then
						if character:FindFirstChild("IsRagdoll").Value == false then
							if game.Players:GetPlayerFromCharacter(hit.Parent):WaitForChild("Bool").Invincible.Value == false then
								if not table.find(affected, hit.Parent) then
									table.insert(affected, hit.Parent)
									if damageCount < 2 then
										TouchEvent:Disconnect()
										physicalBox:Destroy()
										damageCount += 1 
										print(damageCount, "player hit.")
										hit.Parent:FindFirstChild("Humanoid"):TakeDamage(12)
										swordRagdoll(hit.Parent, character)
										local attacker = game.Players:GetPlayerFromCharacter(character)
										if attacker and attacker:FindFirstChild("leaderstats") then
											attacker.leaderstats.Hits.Value += 1
										end

									end
								end
							end
						end
					end
				end
				debounce = false
			end)
		end
	end
	playAnim.Stopped:Connect(stopSwing)
end)

This is because when you use a .Touched event, it will fire multiple times even if the weapon touched the player 1 time

ive added multiple debounces tho to stop it from running, and the function disconnects after a hit

I recommend debugging your script and checking the scope of your variables. It’s likely that you are setting them but when you go to read them it’s reading a different version of them. I don’t recommend storing variables in a function nor having a function in a function. Instead have the touch function edit a variable and then when your event is called check the variable. Also for the debounces I recommend adding a delay even just a task.wait(0.1) and you will see a noticeable difference.

I recommend using GetpartsInPart or GetPartsBoundInBox and a heartbeat loop as touched is semi ping reliant.

Oh and, PLEASE add comments and spacing. Your code is kind of hard to read.

Sorry i’m a bit confused on the “scope” of variables, could you explain a bit more?

Would this run better?

local function stopSwing() 
	task.wait(.2)
	swingCheck = false
	found = false
end
function hit(hitbox, character)
	while found == false do
		wait(.1)
		local foundparts = workspace:GetPartsInPart(hitbox)
		for i, part in ipairs(foundparts) do
			if found == true then return end
			if part.Parent:FindFirstChild("Humanoid") then
				if part.Parent ~= character then
					found = true
					print("fOUND")
				end
			end
		end
	end
end
function newHitBox(character, playAnim)
	local physicalBox = Instance.new("Part", character)
	physicalBox.Name = "Hitbox"
	physicalBox.Transparency = 0.6
	physicalBox.Anchored = false
	physicalBox.CanCollide = false
	physicalBox.Size = Vector3.new(5.5, 2.5, 5.5)
	physicalBox.Massless = true
	physicalBox.CFrame = character.HumanoidRootPart.CFrame * CFrame.new(0, 0, -3.5)
	physicalBox.Parent = character.HumanoidRootPart

	local weld = Instance.new("WeldConstraint")
	weld.Part0 = character.HumanoidRootPart
	weld.Part1 = physicalBox
	weld.Parent = character.HumanoidRootPart
	game.Debris:AddItem(weld, 0.5)
	game.Debris:AddItem(physicalBox, 0.5)
	playAnim.Stopped:Connect(function()
		physicalBox:Destroy()
	end)
	hit(physicalBox, character)
end
script.Parent.SwordCombatRemote.OnServerEvent:Connect(function(player)
	print("got here")
	print(swingCheck)
	if swingCheck then return end
	swingCheck = true
	local character = player.Character
	if character.IsRagdoll.Value then
		swingCheck = false
		return
	end
	local Hum = character:WaitForChild("Humanoid")
	if Combo == 1 then
		playAnim = Hum:LoadAnimation(anim)
		playAnim:Play()
		Combo = 2
	elseif Combo == 2 then
		playAnim = Hum:LoadAnimation(anim2)
		playAnim:Play()
		Combo = 1
	end
	playAnim.Stopped:Connect(function()
		stopSwing()
	end)
	task.wait(0.2)
	newHitBox(character, playAnim)
	sound:Play()
end)
emphasized text

Oh yeah, that is SO much easier to read.

Also yeah, like that.

ended up being really weird so i used a raycast module and it works great now. thanks for helping though!

This would be creating multiple loops, good you worked it out though. And if you want to know what a ‘scope’ is, go to a part of your script and click right next to the numbers on the left, it will activate debugging and when that part of the script runs open ‘watch’. It will tell you the scope of all your variables at that part of the script. You should look it up as it can affect performance and cause issues down the line.
General gist of it though is a ‘scope’ is where certain variables/functions can be accessed and sometimes certain scopes only allow reading of variables but not writing of variables and if you do try it only affects that particular scope.
As an example when you create and then run a function, that function has it’s own scope which is why you have to define parameters, it can only use it’s own local variables, upvalues and globals. (Upvalues are variables defined in the upper scope such as the start of the script.)
Hope I was helpful!

The one shot still happens even with the module, so this leads me to believe it’s part of the event activating weirdly, like activating multiple swings at once, because there’s no way the module is also having the same error as me. I’m still using the same animation and on event loop, is there something wrong with that bit?

Going over the script before:

  1. You shouldn’t have any loops at all other than iterating over any candidate parts. As soon as a part is found you need to break the loop or check if you’ve already damaged that player. If multiple parts of the same player are found in the loop it will damage them multiple times. Since you’re raycasting now though, you shouldn’t have any loops at all.
  2. Any ‘hitboxes’ should already exist, creating and destroying them repeatedly is bad for performance. Since you’ve moved to raycasting I imagine you don’t need this anymore though.

Since you’re raycasting it should simply be:

script.Parent.SwordCombatRemote.OnServerEvent:Connect(function(player)
	if swingCheck then return end
	swingCheck = true
	local Ray = game.Workspace:Raycast(rayOrigin, rayDirection, Params) -- Or whatever
local character = Ray.Instance.Parent
if not character:FindFirstChild("Humanoid") then return end
	if Ray.Instance.Parent.IsRagdoll.Value then -- Checking Result
		swingCheck = false
		return
	end
	local Hum = character.Humanoid
	if Combo == 1 then
		playAnim = Hum:LoadAnimation(anim)
		playAnim:Play()
		Combo = 2
	elseif Combo == 2 then
		playAnim = Hum:LoadAnimation(anim2)
		playAnim:Play()
		Combo = 1
	end
	playAnim.Stopped:Connect(function()
		stopSwing()
	end)
	task.wait(0.2)
	hum.Health -= damage -- Whatever your damage value is here
	sound:Play()
end)

This is just an example of what it should look like. Don’t copy it 1:1 unless you want to but basically it should just be a straight, loopless script. Have any important values in this like swingCheck an upvalue, use the debugger if you come across any issues.
If you don’t know how to use the debugger heres a random youtube video I found:

It could be the ragdoll breaking your character. Have you tried setting the Humanoid’s RequiresNeck property to false? If you are using the Perfect Ragdoll module (which also uses IsRagdoll so thats why I am assuming) they have a setting in their script to disable that property.

that would explain a lot. as during the videos, if i play it back in slow mo the head comes off

1 Like

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