Unanchored parts bounce as they go up and down a lift?

Hi there, I have a question I’m hoping someone with a bit more of building with physics background can help me answer.

I have lifts in my game that go up and down much like an elevator. These lifts are powered through bodymovers so to my understanding this is a question about Roblox physics, not scripting.

When I put a block on these lifts they go up perfectly, but when they go down, they bounce around and sometimes fall off the lift.

I was wondering if others have run into this problem before and if so how did they fix it?

I will note that this problem also occurs to humanoid standing on the platform, although to a lesser extent.

Any help or suggestions would be much appreciated!

3 Likes

Feedback

When they go up, they don’t move because the part is being pushed up by the moving ground. However, when the lift goes down, the part things that it is falling. I’m sure you know this already. Also, what do you need those unachored parts for?

Yes I’m aware.

I figured though that as long as the lift going down is not accelerating faster than gravity then the green block wouldn’t bounce (it’d be pressed against the surface) just like you’d expect in real life. I’m wondering if there are any physical part settings (which I tried without success) or techniques I should be using to get this behaviour?

As for the purpose of the unanchored part it’s for a puzzle game, but I’m not sure if that really matters in the overall context of this problem? A player, other parts, etc. these could all be potentially on a lift in future levels I design.

Have you tried changing the density of the object? Or maybe just add a weld constraint every time the part is on the platform.


What if you added a body mover to the part as well?

I like your logic but with the “not accelerating faster than gravity” doesn’t work because when the lift falls, it is like it is moving a certain distance of studs. The blocks for a moment thinks that it has stopped, then the lift is moving again. Since things don’t move directly and sometimes there’s there’s pauses, as you have stated, it happens with humanoids, which shows that the lift is actually moving in small intervals.

Or, though this is usually with much bigger and larger objects, when the part hits the floor (that in this case is moving), it is actually bouncing. For example, if you were to place a giant unachored ball in the air on baseplate and press play, when the ball falls, the impact actually causes your avatar to jump. This could suggest that this is the same process happening in reverse, the floor is impacting the part causing it to bounce.

Or maybe it is a bit of both,

1 Like

I don’t know what you are using right now but this might help you in making the right selection, there are a few ways to do this so i suggest trying some other bodymover types to see what works best.

Article: Documentation - Roblox Creator Hub

If all else fails you could increase the gravity of anything that touches your lift through a touched event.

I have tried changing the density and did not get really any better results.

My main concern with implementing a weld or a bodymover that applies greater force is that I’d like the objects to still be pushable and whatnot by players.

Wait. I got an idea. Do you know how some flags work that are made of parts? Maybe you could do something similar. Though it might need some scripting. Maybe you do anchor the part to the floor but when the player touches it, it moves depending on the player’s input direction. Something like the puzzles in Loomian Lagacy. However, it does limit movement and some degree of freedom.

This reminds me of ping pong balls.

If you drop a ping pong ball from a certain non-zero height above a platform moving downwards with some damping, you will see similar characteristics to what you are observing. The faster the platform moves, the more aggressive the bounces are. The higher the ball is initially above the platform, the more aggressive the bounces are. On the way up it doesn’t matter since it quickly gets forced up - gravity only works one way.

The idea is that your system is behaving as if it has some initial starting height. It’s possible that the Roblox physics engine is only getting that the platform moved a frame later than when it actually moved. When are you updating the moving platform?

1 Like

Alright, so I did find a solution but it’s most definitely rooted in scripting.

I created a class that lets me define certain objects as “PhysicsObjects”. These objects do a raycast every heartbeat step and CFrame’s the part so it maintains the same offset it had from last frame. This has the added benefit of working on both humanoids and regular parts.

I will post the code I used, but I don’t really have time to explain it too much:

local RUNSERVICE = game:GetService("RunService")

-- Class

local PhysicsObject = {}
PhysicsObject.__index = PhysicsObject

local ActiveObjects = {}

-- Public Constructors

function PhysicsObject.new(part, height)
	local self = setmetatable({}, PhysicsObject)
	
	ActiveObjects[self] = true
	
	self.Part = part
	self.Height = height
	self.Ignores = {part}
	
	self.LastPart = nil
	self.LastPartCFrame = nil
	
	return self
end

function PhysicsObject.FromPart(part)
	return PhysicsObject.new(part, (part.Size/2).Magnitude)
end

function PhysicsObject.FromHumanoid(humanoid)
	local hrp = humanoid.RootPart
	local isR15 = (humanoid.RigType == Enum.HumanoidRigType.R15)
	local hipHeight = isR15 and humanoid.HipHeight or 2
	local phys = PhysicsObject.new(hrp, hrp.Size.y/2 + hipHeight + 1)
	phys.Ignores = {humanoid.Parent}
	return phys
end

-- Public Methods

function PhysicsObject:GetActive()
	return ActiveObjects[self]
end

function PhysicsObject:SetActive(bool)
	ActiveObjects[self] = not not bool
end

function PhysicsObject:AddIgnore(ignore)
	table.insert(self.Ignores, ignore)
end

function PhysicsObject:Destroy()
	ActiveObjects[self] = nil
end

function PhysicsObject:OnHeartbeatStep(dt)
	local ray = Ray.new(self.Part.Position, Vector3.new(0, -self.Height, 0))
	local hit, pos, normal = workspace:FindPartOnRayWithIgnoreList(ray, self.Ignores)

	local lastPart = self.LastPart
	if (hit and lastPart and lastPart == hit) then
		local offset = self.LastPartCFrame:ToObjectSpace(self.Part.CFrame)
		self.Part.CFrame = hit.CFrame:ToWorldSpace(offset)
	end
	
	self.LastPart = hit
	self.LastPartCFrame = hit and hit.CFrame
end

--

RUNSERVICE.Heartbeat:Connect(function(dt)
	for physObject, value in next, ActiveObjects do
		if (value and physObject.Part:IsDescendantOf(workspace)) then
			physObject:OnHeartbeatStep(dt)
		end
	end
end)

--

return PhysicsObject

Thanks for the help everyone! :+1:

I will mark this as a solution for now, but if someone gives me something a bit less overkill I’ll be happy to switch over to that!

15 Likes

You could just weld the part to it when it’s moving and break the welds when it stops.

1 Like

I did think of that, but it comes with problems of its own. :grin:

1 Like

Ah, good point. I wish the physics could be so much simpler sometimes.

1 Like

Network owner isn’t shared. Guessing the character radius is being reset or never set in the first place, which causes this. :stuck_out_tongue:

2 Likes