How do I fix issue where newly created part doesn't immediately start moving with given velocity?

This is the example code I used to reproduce this issue/phenomena.
The wait function is just so there is eanough time to witness the issue.

My expectation is that when the part is created, it will be given a velocity by “ApplyImpulse”, and thus will move immediately as it appears in the world.
But instead, there is a ~1/3 of the second delay before the part actually starts moving. So it is just stationary, frozen in air for a period of time. When in reality it should be moving almost immediately.

wait(5)
local part = Instance.new("Part")
part.Name = "test"
part.Position = Vector3.new(0,5,0)
--part.AssemblyLinearVelocity = Vector3.new(0,100,0)
part.Parent = workspace
part:ApplyImpulse(Vector3.new(0,1000,0))

From what I understand, this is a networking issue. Because the above code runs on the server (as I assume happens most of the time). And when you eventually move the part to the workspace, that is when it is replicated to other clients. So when you call “ApplyImpulse”, that information comes later after the part has been created on the client, and thus the delay before the part starts moving.
That’s my guess at least.

Calling “ApplyImpulse” does not work if called before the initial parenting happens.

So I am hoping there is some simple solution to this.
I can provide a gif showing what I am witnessing as well, if none of you see what I am describing after running the above lua code on your computers.

3 Likes

You’re correct in that there’s a delay before physics applied on the server acts on an object and is replicated to the client, and it is due to network ownership

See if you can find a way to set the network ownership to a player in your script, although do note that by doing so you’ll be introducing a potential security risk since the player will be free to move the part as they please if they’re an exploiter so you’ll need to track its movement on the server

2 Likes

Thank you.

In the main project where I am noticing this, I am setting the network owner to “nil” so the owner is the server. Because I noticed issues with collision events giving part positions that where way off from where the part atually was when it collided.

But I could also try setting the network owner to the client that created the part via the interaction they performed to create it.

2 Likes

That would be a good method to use :grin::+1:

Personally I like to set the network owner to the player who initiated the physics interaction, for example the driver of a vehicle, then set the network ownership to auto if the object will stay present in the game instead of the object being destroyed afterwards

2 Likes

I change my test code to this:

wait(5)

local player = game.Players:WaitForChild("Andrew900460")

local part = Instance.new("Part")
part.Position = Vector3.new(0,5,0)
part.Parent = workspace
part:SetNetworkOwner(nil)
part:ApplyImpulse(Vector3.new(0,500,0))
task.wait()
part:SetNetworkOwner(player)

And it seemed to fix the issue, but it requires some strange sequence of network ownership changes in order to make it work, for some reason…

If I write the code like this:

wait(5)

local player = game.Players:WaitForChild("Andrew900460")

local part = Instance.new("Part")
part.Position = Vector3.new(0,5,0)
part.Parent = workspace
part:ApplyImpulse(Vector3.new(0,500,0))
part:SetNetworkOwner(player)

Where I only set the owner to the player. In this case, it doesn’t even apply the force, the part just falls to the ground.

So for some reason, I need to manually set the owner to the server, then apply the impulse, then I have to yield the script for 1 game tick (via wait), and after that, I can set the owner to the server.
Doing it that way seems to make the part not freeze in air any more.

But I find this to be a very strange way to get a proper looking result.
Like to me, this seems like a bug that aught to be addressed.
Yesterday, I also did tests where I found that on the client, in some situations, the newly created part would have a non-zero velocity; (0,95,0) for example. But it will still be stationary for some time. When maybe the part shoud’ve been moving in some fasion, even if the movement was just due to interpolation before the client was ready to start updating the position based on the server.

I’m probably gonna do some more tests here though.
My assumption is that this is a widely known issue, and most big games have a decent way to get around it, or there is an official solution for this.

3 Likes

Here is an alternative solution I tried:

This is a local script that would go into “ReplicatedFirst”.

wait(1)

local partsToAnimate = {}
local partsToRemove = {}

workspace.ChildAdded:Connect(function(child: Part)
	local vel = child.AssemblyLinearVelocity
	table.insert(partsToAnimate,{part=child,timer=30})
end)

game:GetService("RunService").RenderStepped:Connect(function(deltaTime: number)
	for k,v in ipairs(partsToAnimate) do
		v.part.Position = v.part.Position+v.part.AssemblyLinearVelocity*deltaTime
		v.part.AssemblyLinearVelocity = v.part.AssemblyLinearVelocity + (Vector3.new(0,-workspace.Gravity,0))*deltaTime
		v.timer = v.timer-1
		if v.timer == 0 then
			table.insert(partsToRemove,k)
		end
	end
	
	for k,v in ipairs(partsToRemove) do
		table.remove(partsToAnimate,v)
	end
	
	table.clear(partsToRemove)
end)

This obviously woudn’t work for all parts in the workspace.
This code is meant to address the issue for simple parts that are not part of an assembly.

And all it’s doing is crudely simulating the physics of the part on the client for a short period of time, until the client starts simulating things itself.

The only problem with this solution is that, after this script stops simulating the physics on the clinent, it doesn’t continue moving, but stops mid air like it originally did without this code.

So this leads me to think that this is some strange bug within the physics code of the game.
Because I can write a client-side script which properly simulates the objects movement. So the engine should be doing that on it’s own, but it just isn’t for some reason…

2 Likes

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