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!
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?
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.
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.
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.
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.
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?
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!
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!