I am using TweenService
in order to move my platform upwards.
However, on high speeds, the player clips through it and falls.
I have no idea how to avoid it or detect it. Any help is appreciated.
For the engine to include the platform in physics calculations, you’ll have to use something physics based.
- AlignPosition, VectorForce, and other mover constraints
- PrismaticConstraints and similar
- BodyMovers (deprecated)
- …
Here’s Okeanskiy’s example where he made an elevator using prismatic constraints (ROBLOX Easy Elevator with Prismatic Constraint - 2019 Scripting Tutorial (Floor/Lift System) - YouTube). It’s from 2019 but still very relevant.
My platform is also constantly moving downwards.
And I am not too sure if I can tween the constraints.
The constraints are not tweened, they’re physics based and tweens/direct CFraming are not.
If you set the appropriate actuator type (Motor, Servo), some additional settings - like Velocity, MotorMaxAcceleration, MotorMaxForce → motor; LinearResponsiveness, Speed, ServoMaxForce, TargetPosition → servo - are going to open.
The video above has a working example.
I didn’t like the idea of constraints, so I decided to make a script of my own.
Took a couple of hours but I think it is worth it and others might find this helpful.
In StarterPlayerScripts
→ StarterCharacterScripts
create a LocalScript
. Name it however you want.
Paste this code in:
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local char:Model = script.Parent
local player = Players.LocalPlayer
local rootPart:BasePart = char:WaitForChild("HumanoidRootPart")
if char:WaitForChild("Humanoid").RigType == Enum.HumanoidRigType.R15 then
legHeight = char:WaitForChild("LeftUpperLeg").Size.Y
legHeight += char:WaitForChild("LeftLowerLeg").Size.Y
legHeight += char:WaitForChild("LeftFoot").Size.Y
else
legHeight = char:WaitForChild("LeftLeg").Size.Y
end
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = {char}
params.IgnoreWater = true
--// these are for testing where the ray goes
--local originPart = Instance.new("Part")
--originPart.Transparency = 0.5
--originPart.CanCollide = false
--originPart.Anchored = true
--originPart.Color = Color3.new(1, 0, 0)
--originPart.Size = Vector3.new(1.5, 1.5, 1.5)
--originPart.Parent = char
--local directionPart = Instance.new("Part")
--directionPart.Transparency = 0.5
--directionPart.CanCollide = false
--directionPart.Anchored = true
--directionPart.Color = Color3.new(0, 1, 0)
--directionPart.Size = Vector3.new(1.5, 1.5, 1.5)
--directionPart.Parent = char
local lastResult:RaycastResult = nil
local oldPosition = nil
local relativePosition = nil
RunService.Heartbeat:Connect(function(dt)
local origin = rootPart.Position
--originPart.Position = origin
local destination = origin - (Vector3.new(0, legHeight + (rootPart.Size.Y / 2), 0))
--directionPart.Position = destination
local result = workspace:Raycast(origin, destination-origin, params)
if lastResult ~= nil and result == nil then
if lastResult.Instance:IsA("BasePart") then
if lastResult.Instance.Position ~= oldPosition then
char:PivotTo(
CFrame.new(
lastResult.Instance.Position + relativePosition
) *
CFrame.Angles(
math.rad(rootPart.Rotation.X),
math.rad(rootPart.Rotation.Y),
math.rad(rootPart.Rotation.Z)
)
)
end
end
elseif lastResult and result then
if lastResult.Instance:IsA("BasePart") and result.Instance:IsA("BasePart") then
if oldPosition ~= lastResult.Instance.Position and lastResult.Instance == result.Instance and relativePosition then
char:PivotTo(
CFrame.new(
lastResult.Instance.Position + relativePosition
) *
CFrame.Angles(
math.rad(rootPart.Rotation.X),
math.rad(rootPart.Rotation.Y),
math.rad(rootPart.Rotation.Z)
)
)
end
end
end
if result then
if result.Instance:IsA("BasePart") then
relativePosition = rootPart.Position - result.Instance.Position
end
end
lastResult = result
if result then
if result.Instance:IsA("BasePart") then
oldPosition = result.Instance.Position
end
else
oldPosition = nil
end
end)
Ta-da.
The script isn’t perfected, but it is enough for me.
How does it work?
i have zero clue. i was in trans while writing this
Basically, it makes a Raycast
to check what part the player is standing on.
If
the player doesn’t stand on anything, it checks if the player was previously standing on anything.
If
yes, then we will check if the part that the player was standing on moved.
If
yes, then we will snap the player back to it.
Elseif
the player is standing on something, it checks if the part moved or not.
If
yes, then snap back to the part.
Why LocalScript instead of ServerScript?
I used ServerScript
but it turned out to be jittery and didn’t allow for the player to leave the platform. LocalScript
does this just fine.
Thank you for your help @waves5217.
EDITED: Reworked the script.