NPCs glitched in the floor on client but normal on server

I want to fling NPCs out of cannons onto a battlefield and I am launching them by changing the AssemblyLinearVelocity of their HumanoidRootParts. It works well on the server, however on the client it is very glitchy and they get stuck in the floor. I don’t even know where to start to fix this issue.

Heres my code:

local cannon = script.Parent.Parent

script.Parent.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") then
		local hum = hit.Parent.Humanoid
		local hmr = hit.Parent.HumanoidRootPart
		hum.Sit = true
		hmr.Anchored = true
		hmr.CFrame = cannon.Tip.CFrame
		wait(1)
		hmr.Position += cannon.Tip.CFrame.LookVector*2
		hmr.Anchored = false
		hmr.AssemblyLinearVelocity = cannon.Tip.CFrame.LookVector * math.random(100,120)
		hmr.Touched:Wait()
		hmr.CFrame = hmr.CFrame
		hum.Sit = false
	end
end)

1 Like

No idea what’s happening but try this anyways:

hmr:SetNetworkOwner(nil) -- set network owner to the server

No clue my self what is going on. Maybe a network ownership thing? Anyway.

Your code is bad. Please take some of the following advice with you:

  1. DONT EVER use deprecated functions/types/anything like wait, if it is deprecated then don’t use it. Use task.wait here instead.
  2. Why are you slapping all your code within the if statement? Just have it check if there is no humanoid:
if not hit.Parent:FindFirstChild("Humanoid") then -- can also do == nil but its longer
    print("No humanoid :(")
return -- exit and stop running (might not be needed but its a habit of mine)
end

-- logic for functionality here

I like the way you said it

Your code is bad.

Anyways I didn’t know that wait() was depreciated so thanks for telling me. I really work in my own bubble, I work on my own projects and never really collaborate with people so I don’t know the best practices.

Why would I beat around the bush :man_shrugging:

That’s fine but you should practice bettering your code structure and learning common code practices. It is pretty easy to learn and understand if you understand the fundementals. Just look on the resources category or literally just lookup guard clauses and other best practices.

looks like the npcs are falling with an offset, likely from their humanoidRootPart.

Youre changing the npcs cframe by manually changing the position of the humanoidRootPart, I dont know why, but roblox doesnt like this and usaully starts to mess up the rig when you do that, maybe it doesnt update the root motor6D or something, im not too sure of an internal explaination

But use PivotTo to move the characters cframe/position around

local cannon = script.Parent.Parent
local tipPart = cannon.Tip

script.Parent.Touched:Connect(function(hit: BasePart)
	
	local character = hit.Parent :: Model
	local humanoid = character:FindFirstChildOfClass("Humanoid")
	
	if humanoid then
		
		local rootpart = character:WaitForChild("HumanoidRootPart") :: BasePart
		
		humanoid.Sit = true
		rootpart.Anchored = true
		character:PivotTo(tipPart.CFrame)

		task.delay(1, function()
			
			character:PivotTo(tipPart.CFrame * CFrame.new(0, 0, -1)) --CFrame.new(0, 0, -1) moves the character 1 stud forwards
			rootpart.Anchored = false
			rootpart.AssemblyLinearVelocity = cannon.Tip.CFrame.LookVector * math.random(100,120)
			
			humanoid.Touched:Wait()
			
			humanoid.Sit = false
		end)
	end
end)

This should fix the issue

Still didn’t work for some reason. Heres the code after I edited it:

script.Parent.Touched:Connect(function(hit)
	if not hit.Parent:FindFirstChild("Humanoid") then return end
	local hum = hit.Parent.Humanoid
	local hmr = hit.Parent.HumanoidRootPart
	hum.Sit = true
	hmr.Anchored = true
	hit.Parent:PivotTo(cannon.Tip.CFrame)
	task.wait(1)
	hit.Parent:PivotTo(cannon.Tip.CFrame * CFrame.new(cannon.Tip.CFrame.LookVector*2))
	hmr.Anchored = false
	hmr.AssemblyLinearVelocity = cannon.Tip.CFrame.LookVector * math.random(100,120)
	hmr.Touched:Wait()
	hum.Sit = false
	hum.Jump = true
end)

does it give the same result, or does the script just break

Little bit different, not much. Stops any type of false read from these two…

local hum = hit.Parent.Humanoid
local hmr = hit.Parent.HumanoidRootPart
local cannon = script.Parent.Parent
local char, db = nil, true

script.Parent.Touched:Connect(function(hit)
	if not db then return end char = hit.Parent
	if char:FindFirstChild("Humanoid") and db then 
		db = false

		local hum = char.Humanoid
		local hmr = char.HumanoidRootPart
		hum.Sit = true
		hmr.Anchored = true
		hmr.CFrame = cannon.Tip.CFrame
		task.wait(1)
		hmr.Position += cannon.Tip.CFrame.LookVector * 2
		hmr.Anchored = false
		hmr.AssemblyLinearVelocity = cannon.Tip.CFrame.LookVector * math.random(100,120)
		hmr.Touched:Wait()
		hmr.CFrame = hmr.CFrame
		hum.Sit = false
		
		task.wait(2)
		db = true
	end
end

When a player or NPC touches something, it usually happens many times with multiple parts. Hit can rapidly change the outcome of hit.Parent. So you use a debounce (db). I’m not sure about the rest of it, but that part wouldn’t work as you intended, especially without the debounce. I’m sure you were getting double fires or more.

I know you used Humanoid here to make sure it was the right kind of touch but, that would be true many times, firing for each one. Place a print(hit) in there and you’ll be shocked how many times that goes off.

3 Likes

This was the problem thank you!!!

1 Like

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