Unanchored Building Slowly Shifting Over Pause and Resume Cycles

I want to be able to pause the physics in Roblox without any minute changes occurring. I am creating a physics-based casual puzzle game, where you fire a projectiles to knock over a building, and want to create a Pausing System. However, stress testing by cycling pause and resume showed unwanted results.

The issue is when trying to do the Pausing by anchoring all the parts, and then unanchoring all the parts on resume, the parts end up moving slightly and this adds up overtime leading to undesirable outcomes.

Video is sped up by 4x

Here is the code used for the Pausing and Resuming as well as the Stress Test code

function LevelController:Pause()
	if self.LevelFastCast.Simulation == nil then return end
	print("Pause")
	
	local PausedBaseParts = {}
	for i,Instance in self.LevelRoot.Structures:GetChildren() do 
		if Instance:IsA("Model") then 
			table.insert(PausedBaseParts, Instance.PrimaryPart)
		elseif Instance:IsA("BasePart") then
			table.insert(PausedBaseParts, Instance)
		end
	end
	for i,Mob in self.LevelRoot.Mobs:GetChildren() do 
		if Mob:IsA("Model") then 
			table.insert(PausedBaseParts, Mob.PrimaryPart)
		end
	end
	for i,Cast in self.LevelFastCast.Simulation.StateInfo.Casts do
		table.insert(PausedBaseParts, Cast.RayInfo.ServerBulletObject)
	end
	
	task.spawn(function() 
		task.delay(0,function() 
			self.LevelFastCast.Simulation:Pause() 
		end) 
	end)
	
	task.spawn(function()
		self.LevelInfo.PausedBaseParts = {}
		for _,BasePart in PausedBaseParts do 
			task.delay(0,function()
				print("Anchored Part")
				BasePart.Anchored = true
				table.insert(self.LevelInfo.PausedBaseParts, BasePart)
			end)
		end
	end)
	
	task.spawn(function()
		for i,Cast in self.LevelFastCast.Simulation.StateInfo.Casts do
			task.delay(0,function()
				Cast.RayInfo.ServerBulletObject.CFrame = Cast.UserData.BulletSkin.CFrame
			end)
		end 
	end)
	
end

function LevelController:Resume()
	if self.LevelFastCast.Simulation == nil then return end
	if GuiService.MenuIsOpen or self.PlayerInfo.GUI.LevelMenu.Visible or PI.WindowFocusState == "Released" then return end
	print("Resume")
	
	task.delay(0,function() self.LevelFastCast.Simulation:Start() end)
	
	for _,BasePart in self.LevelInfo.PausedBaseParts do
		task.delay(0,function()
			print("Unanchored Part")
			BasePart.Anchored = false
		end)
	end
end


-- STRESS TEST BASIC CODE -- 
while on do 
	self:Pause()
	wait(0.2)
	self:Resume()
	wait(0.2)
end

I have tried saving the data for the BasePart on Pause, its CFrame and AssemblyLinearVelocity, and on Resume copying that data over immediately, after a very small delay, and after RunService Waits, but all led to the same results.

I believe ideally Roblox needs to add more control over the physics engine to allow for more creativity with said engine. I have some knowledge with Physics Engines as FastCast itself is one, albeit very basic. Simple things like slowing down physics time and being able to completely stop it would be ideal and allow for some very cool projects to be made. Even better would be deterministic physics, allowing for things like replay systems.

This is most likely due to the accumulation of IEEE-754 floating point & other approximation inaccuracies inside the physics simulation; every time you resume it, the assembly becomes subject to gravity again and absorbs some force inaccuracy. I doubt there’s a clean solution to this because of how intrinsic the problem is to the engine.

2 Likes