Method supposed to run on every character only works for one

Hello, I have been having a serious issue with my game lately. The problem is that I made a script for punching on every player’s character, yet something odd happens.

Intended result: Both players are able to punch eachother with their own different hitboxes

Actual result: When in a local server with two players, it seems the last one who joined gets priority for every player, meaning that the last player (call them player2) can punch for itself, yet when player1 (plr who joined before) tries to punch, it plays the animation and hitbox on player2

A notable issue is that when player1 dies the priority is transferred to them and the glitch happens to player2.

Video:

Code:

--ServerScriptService
local SS = game:GetService("ServerStorage")
local RepStorage = game:GetService("ReplicatedStorage")
local Plrs = game:GetService("Players")
local RunService = game:GetService("RunService")

local Events = RepStorage:WaitForChild("Events")
local PunchEvent = Events:WaitForChild("PunchEvent")

local HitboxClass = require(RepStorage:WaitForChild("Modules"):WaitForChild("HitboxClass"))
local HitboxTypes = require(RepStorage:WaitForChild("Modules"):WaitForChild("HitboxClass"):WaitForChild("Types"))

local Animations = SS:WaitForChild("Animations")
local PlrAnims = Animations:WaitForChild("Player")

local LoadedAnims = {}

local combo = 0
local hand = 0
local maxComboTime = 2
local comboTime = 0
local Range = 5
local debounce = false

Plrs.PlayerAdded:Connect(function(plr)
	print(plr.Name,"joined")
	plr.CharacterAppearanceLoaded:Connect(function(char)
		local humanoid:Humanoid = char:WaitForChild("Humanoid")
		local animator:Animator = humanoid:WaitForChild("Animator")
		local HumanoidRootPart:Part = char:WaitForChild("HumanoidRootPart")
		
		local function getAnim(plr:Player,name:string)
			for i,v in pairs(LoadedAnims[plr.Name]) do
				if v.Name == name then
					return v
				end
			end
		end

		local function stopAllPlayingAnims(time)
			for _, v:AnimationTrack in pairs(animator:GetPlayingAnimationTracks()) do
				if time == nil then
					v:Stop()
				else
					v:Stop(time)
				end
			end
		end
		
		local AnimFolder = Instance.new("Folder")
		AnimFolder.Parent = char
		AnimFolder.Name = "AnimFolder"
		
		local tempTable = {}
		for _, anim:Animation in pairs(PlrAnims:GetChildren()) do
			local newAnim = Instance.new("Animation")
			newAnim.Parent = AnimFolder
			newAnim.AnimationId = anim.AnimationId
			newAnim.Name = anim.Name

			local loadedAnim = animator:LoadAnimation(newAnim)
			
			table.insert(tempTable, loadedAnim)
		end
		LoadedAnims[plr.Name] = tempTable
		
		print("Loaded animations:",LoadedAnims)

		PunchLeft = getAnim(plr,"PunchLeft")
		PunchRight = getAnim(plr,"PunchRight")
		Uppercut = getAnim(plr,"Uppercut")
		Dropkick = getAnim(plr,"Dropkick")
		
		local hitboxParams:HitboxTypes.HitboxParams = {
			SizeOrPart = Vector3.new(3,4,3.5),
			InitialPosition = plr.Character.HumanoidRootPart.CFrame + plr.Character.HumanoidRootPart.CFrame.LookVector * Range/2,
			DebounceTime = 0.5,
			Debug = true,
			UseClient = plr,
			Blacklist = {char}
		}
		
		checkHitbox = HitboxClass.new(hitboxParams)
		
		checkHitbox:WeldTo(HumanoidRootPart, CFrame.new(0,0,-2))
		
		checkHitbox.HitSomeone:Connect(function(hitChars)
			print("hit someone")
			combo += 1
			comboTime = 0
			print(combo)
			
			if combo == 3 then
				Uppercut:Play(0.1, 5, 1.5)
			elseif combo == 4 then
				Dropkick:Play(0.1, 5, 1.5)
				combo = 0
			end
			
			for _, hitChar in pairs(hitChars) do
				local hitHumanoid = hitChar:FindFirstChildOfClass("Humanoid")
				local hitPlr = Plrs:GetPlayerFromCharacter(hitChar)
				hitHumanoid.Health -= 5
				
				getAnim(hitPlr,"Hit"):Play()
			end
		end)

		task.spawn(function()
			while true do
				wait(1)
				if combo > 0 then
					comboTime += 1

					if comboTime >= maxComboTime then
						combo = 0
					end
				end
			end
		end)
		
		wait(5)
		PunchLeft:Play()
	end)
end)

PunchEvent.OnServerEvent:Connect(function(plr)
	if debounce then return end
	debounce = true
	
	if combo < 3 then
		if hand == 0 then
			hand = 1
			PunchLeft:Play(0.1, 5, 1.5)
		elseif hand == 1 then
			hand = 0
			PunchRight:Play(0.1, 5, 1.5)
		end
	end

	checkHitbox:Start()
	task.wait(0.2)
	checkHitbox:Stop()

	task.wait(0.2)
	debounce = false
end)
--StarterCharacterScripts
local CAS = game:GetService("ContextActionService")
local UIS = game:GetService("UserInputService")
local RepStorage = game:GetService("ReplicatedStorage")
local Plrs = game:GetService("Players")

local plr = Plrs.LocalPlayer
local char = plr.Character
local humanoid:Humanoid = char:WaitForChild("Humanoid")
local HumanoidRootPart:Part = char:WaitForChild("HumanoidRootPart")

local jumpUsage = 1

local PunchEvent = RepStorage:WaitForChild("Events"):WaitForChild("PunchEvent")

CAS:BindAction("Punch", function(actionName, inputState, inputObject)
	if inputState == Enum.UserInputState.Begin then
		PunchEvent:FireServer()
	end
end, true, Enum.UserInputType.MouseButton1, Enum.KeyCode.ButtonR2)
1 Like

Yup! Its because you are using a single hitbox object for every player.
When a new player joins the game that hitbox is overriden to the new player’s hitbox object!

Solution:

Try making a table where you can index each Player’s Hitbox such as:

|

never forget to free the hitbox memory as soon as you are done with them!

Like this!!!

Additionally I recommend the Janitor Module by howmanysmall for easy memory management.

After you connect your hitboxes objects to your Janitor you could link the Janitor to the player as Janitor:LinkToInstance(Player) to forget about having to release the hitbox memory yourself!

Hopefully that explains it all, please tell me if you need any more help.

Ahhh, thank you so much! I will try this out. I had actually tried putting the event inside the characterloaded event but that had the same issue, so I just took it out. This makes much more since now, though. Thank you! I will mark this as solution if it works out. : D

Small question, if i were to want to use janitor on that playerhitbox element in the table, how would I implement that?

Also, I tried putting all the hitboxes in a table like you said, but it doesn’t seem to do anything.
I also put the PunchEvent listener back inside .CharacterAppearabceLoaded

Sorry if I am acting dumb and the solution is in front of me i am tired right now

Code:

--- This is all inside of the .CharacterAppearanceLoaded Event
-- checkHitbox has been renamed to punchHitbox

        local tempHitbox = HitboxClass.new(hitboxParams)
		PlrHitboxes[plr.Name] = tempHitbox
		
		local punchHitbox = PlrHitboxes[plr.Name]
		
		newJanitor:Add(punchHitbox,"Destroy")

Good morning. I am not sleep deprived anymore (for now) and I found that I was calling the player’s animation wrong, from the player argument in PlayerAdded and not the player argument from the RemoteEvent… I am stupid… Thank you so much for the help! Also thanks for introducing me to Janitor I will be using it a lot lol

New code: (it’s a lot)

 	 	local SS = game:GetService("ServerStorage")
local RepStorage = game:GetService("ReplicatedStorage")
local Plrs = game:GetService("Players")
local RunService = game:GetService("RunService")

local Events = RepStorage:WaitForChild("Events")
local PunchEvent = Events:WaitForChild("PunchEvent")

local Janitor = require(RepStorage:WaitForChild("Modules"):WaitForChild("Janitor"))
local HitboxClass = require(RepStorage:WaitForChild("Modules"):WaitForChild("HitboxClass"))
local HitboxTypes = require(RepStorage:WaitForChild("Modules"):WaitForChild("HitboxClass"):WaitForChild("Types"))

local Animations = SS:WaitForChild("Animations")
local PlrAnims = Animations:WaitForChild("Player")

local LoadedAnims = {}
local PlrHitboxes = {}

local combo = 1
local hand = 0
local maxComboTime = 2
local comboTime = 0
local Range = 5
local debounce = false

Plrs.PlayerAdded:Connect(function(plr)
	print(plr.Name,"joined")
	local newJanitor = Janitor.new()
	newJanitor:LinkToInstance(plr)
	plr.CharacterAppearanceLoaded:Connect(function(char)
		local humanoid:Humanoid = char:WaitForChild("Humanoid")
		local animator:Animator = humanoid:WaitForChild("Animator")
		local HumanoidRootPart:Part = char:WaitForChild("HumanoidRootPart")
		
		local function getAnim(plr:Player,name:string)
			if not plr then return end
			
			for i,v in pairs(LoadedAnims[plr.Name]) do
				if v.Name == name then
					return v
				end
			end
		end
		
		local function stopAllPlayingAnims(time)
			for _, v:AnimationTrack in pairs(animator:GetPlayingAnimationTracks()) do
				if time == nil then
					v:Stop()
				else
					v:Stop(time)
				end
			end
		end
		
		local AnimFolder = Instance.new("Folder")
		AnimFolder.Parent = char
		AnimFolder.Name = "AnimFolder"
		
		local tempTable = {}
		for _, anim:Animation in pairs(PlrAnims:GetChildren()) do
			local newAnim = Instance.new("Animation")
			newAnim.Parent = AnimFolder
			newAnim.AnimationId = anim.AnimationId
			newAnim.Name = anim.Name

			local loadedAnim = animator:LoadAnimation(newAnim)
			
			table.insert(tempTable, loadedAnim)
		end
		LoadedAnims[plr.Name] = tempTable
		
		print("Loaded animations:",LoadedAnims)
		
		local hitboxParams:HitboxTypes.HitboxParams = {
			SizeOrPart = Vector3.new(3,4,3.5),
			InitialPosition = plr.Character.HumanoidRootPart.CFrame + plr.Character.HumanoidRootPart.CFrame.LookVector * Range/2,
			DebounceTime = 0.5,
			Debug = true,
			UseClient = plr,
			Blacklist = {char}
		}
		
		task.spawn(function()
			while true do
				wait(1)
				if combo > 0 then
					comboTime += 1

					if comboTime >= maxComboTime then
						combo = 1
					end
				end
			end
		end)
		
		local tempHitbox = HitboxClass.new(hitboxParams)
		PlrHitboxes[plr.Name] = tempHitbox
		
		local punchHitbox = PlrHitboxes[plr.Name]
		
		newJanitor:Add(punchHitbox,"Destroy")
		punchHitbox:WeldTo(HumanoidRootPart, CFrame.new(0,0,-2))

		punchHitbox.HitSomeone:Connect(function(hitChars)
			print("hit someone")
			combo += 1
			comboTime = 0
			print(combo)

			for _, hitChar in pairs(hitChars) do
				local hitHumanoid = hitChar:FindFirstChildOfClass("Humanoid")
				local hitPlr = Plrs:GetPlayerFromCharacter(hitChar)
				hitHumanoid.Health -= 5
				
				local hitAnim = getAnim(hitPlr,"Hit")
				if hitAnim ~= nil then 
					hitAnim:Play()
				end
			end
		end)
		
		PunchEvent.OnServerEvent:Connect(function(punchingPlr)
			if debounce then return end
			debounce = true
			
			local PunchLeft = getAnim(punchingPlr,"PunchLeft")
			local PunchRight = getAnim(punchingPlr,"PunchRight")
			local Uppercut = getAnim(punchingPlr,"Uppercut")
			local Dropkick = getAnim(punchingPlr,"Dropkick")

			if combo < 3 then
				if hand == 0 then
					hand = 1
					PunchLeft:Play(0.1, 5, 1.5)
				elseif hand == 1 then
					hand = 0
					PunchRight:Play(0.1, 5, 1.5)
				end
			elseif combo == 3 then
				Uppercut:Play(0.1, 5, 1.5)
			elseif combo == 4 then
				Dropkick:Play(0.1, 5, 1.5)
				combo = 0
			end
			
			local punchHitbox2 = PlrHitboxes[punchingPlr.Name]
			
			punchHitbox2:Start()
			task.wait(0.2)
			punchHitbox2:Stop()
			
			punchHitbox2 = nil
			task.wait(0.2)
			debounce = false
		end)
	end)
end)

1 Like

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