If the title makes no sense let me explain. I have a moving platform that moves sideways, up and down. It works fine, however as I could not figure out hot to make it move the way I wanted it to with velocities I had to make it do so with CFrames. The issue with that is that unless I weld the player to the platform, the platform would just move without them. And so I had to weld them, but doing so locks the player in place. I want to somehow keep platform movement the way it currently is while also allowing the player to move while on the platform.
local Target = script.Parent.Target
local Touching = script.Parent.Touching
local UpPart = game.Workspace.UpPart
local DownPart = game.Workspace.DownPart
local UpButton = script.Parent.Buttons.Up.ClickDetector
local DownButton = script.Parent.Buttons.Down.ClickDetector
local masterIndex = 0
UpButton.MouseClick:Connect(function()
Target.Value = "Up"
end)
DownButton.MouseClick:Connect(function()
Target.Value = "Down"
end)
local createdWelds = {}
function cleanWelds()
for i, weld in pairs(createdWelds) do
i.Parent.Humanoid.PlatformStand = false
weld:Destroy()
end
end
function movePlatform()
cleanWelds()
local touchingPlayers = workspace:GetPartsInPart(Touching)
for i, potentialPlayer in pairs(touchingPlayers) do
if potentialPlayer.Name ~= "HumanoidRootPart" then continue end
local HRP = potentialPlayer
HRP.Parent.Humanoid.PlatformStand = true
local newWeld = Instance.new("WeldConstraint", HRP)
newWeld.Part0 = script.Parent.Platform
newWeld.Part1 = HRP
createdWelds[HRP] = newWeld
end
masterIndex += 1
local indexSave = masterIndex
local increment = (Target.Value == "Up" and 0.2 or -0.2)
local targetPart = (Target.Value == "Up" and UpPart or DownPart)
repeat
local formulatedCF = script.Parent.PrimaryPart.CFrame + script.Parent.PrimaryPart.CFrame.LookVector * increment
task.wait(0.01)
script.Parent:PivotTo(formulatedCF)
until (targetPart.Position - script.Parent.PrimaryPart.Position).Magnitude <= 0.1 or indexSave ~= masterIndex
if indexSave == masterIndex then
cleanWelds()
end
end
Target:GetPropertyChangedSignal("Value"):Connect(movePlatform)
You would have to raycast in the direction that your character is actually standing on the platform while it is moving. Then replace the platform’s old CFrame with the platform’s new CFrame and change the CFrame of the humanoid root part as the platform changes direction. The main reason why the humanoid root part’s CFrame is relatively invertible opposed to the platform is because you will be stationary, whereas the platform would still be moving at some extent. So, to prevent this your humanoid root part’s cframe would change with the moving platform’s cframe.
local rs = game:GetService("RunService")
local players = game:GetService("Players")
local lastPlatformCFrame = nil
players.PlayerAdded:Connect(function(player)
local character = player.Character or player.CharacterAdded:Wait()
local hrp = character:FindFirstChild("HumanoidRootPart")
rs.RenderStepped:Connect(function()
local rayparams = RaycastParams.new()
rayparams.FilterDescendantsInstances = {character}
rayparams.FilterType = Enum.RaycastFilterType.Exclude
--not sure but either of these two would work
--local raycast = workspace:Raycast(rootPart.CFrame, rootPart.CFrame:PointToWorldSpace(Vector3.new(0,0,-50)), rayparams)
--local raycast = workspace:Raycast(rootPart.CFrame, rootPart.CFrame:VectorToWorldSpace(Vector3.new(0,0,-50)), rayparams)
if raycast and raycast.Instance.Name == "Platform" then --platform name?
local platformCFrame = raycast.Instance.CFrame
if lastPlatformCFrame then
local cf = platformCFrame * lastPlatformCFrame:Inverse()
hrp.CFrame = cf * hrp.CFrame
end
lastPlatformCFrame = platformCFrame
else
lastPlatformCFrame = nil
end
end)
end)
Unless you are looking for linearVelocity or vectorForce, tweening/lerping can also constantly change the CFrame values of a platform would work as well.
local Target = script.Parent.Target
local Touching = script.Parent.Touching
local UpPart = game.Workspace.UpPart
local DownPart = game.Workspace.DownPart
local UpButton = script.Parent.Buttons.Up.ClickDetector
local DownButton = script.Parent.Buttons.Down.ClickDetector
local masterIndex = 0
UpButton.MouseClick:Connect(function()
Target.Value = "Up"
end)
DownButton.MouseClick:Connect(function()
Target.Value = "Down"
end)
local createdWelds = {}
function cleanWelds()
for i, weld in pairs(createdWelds) do
i.Parent.Humanoid.PlatformStand = false
weld:Destroy()
end
end
function movePlatform()
cleanWelds()
local touchingPlayers = workspace:GetPartsInPart(Touching)
for i, potentialPlayer in pairs(touchingPlayers) do
if potentialPlayer.Name ~= "HumanoidRootPart" then continue end
local HRP = potentialPlayer
--HRP.Parent.Humanoid.PlatformStand = true
local newWeld = Instance.new("WeldConstraint", HRP)
--newWeld.Part0 = script.Parent.Platform
--newWeld.Part1 = HRP
createdWelds[HRP] = newWeld
end
masterIndex += 1
local indexSave = masterIndex
local increment = (Target.Value == "Up" and 0.2 or -0.2)
local targetPart = (Target.Value == "Up" and UpPart or DownPart)
repeat
local formulatedCF = script.Parent.PrimaryPart.CFrame + script.Parent.PrimaryPart.CFrame.LookVector * increment
for i, root in pairs(createdWelds) do
i.CFrame = i.CFrame + script.Parent.PrimaryPart.CFrame.LookVector * increment
end
task.wait(0.01)
script.Parent:PivotTo(formulatedCF)
until (targetPart.Position - script.Parent.PrimaryPart.Position).Magnitude <= 0.1 or indexSave ~= masterIndex
if indexSave == masterIndex then
cleanWelds()
end
end
Target:GetPropertyChangedSignal("Value"):Connect(movePlatform)
Tried that, the player does move with the platform now however as the loop that moves it is so quick the player is just rotates around wildly and isn’t able to actually move anywhere on the platform
That was probably because I never used welds to keep the player stuck to the platform and every render changed the player’s CFrame while the platform below the root part was being raycasted (mistakenly made the character rotate at unpredictable speeds). It was designed to be a whole separate script without the use of constraints.
Assuming that you want to keep the majority of your code, perhaps tweening the part’s CFrame works too, just multiply the CFrame of the humanoid root part by its inverse after tweening a part’s CFrame from one place to another.
I also have a reply of my own that does basically the same thing (although it applies to any object. Should probably exclude unanchored ones though)
The basic idea is get by how much the object (on which the player is standing) moved since the previous frame, and offset the character’s position by it. It can be done with vector math, or with CFrame math (which will apply rotation as well)
This is also what @Jayigon’s solution does, but specific to your code and the platform (although I can’t say if it is bug free)
What a coincidence, I was about to send this exact link just before you replied. I definitely never came up with the idea of the hrp.CFrame = rel * CFrame:Inverse() and all the credit goes to this post regarding the jailbreak train system.
I am assuming that you prevent the usage of welds, so that players may move freely or jumping around the platform. I do not know how to create a script that allows enough momentum when jumping on a moving object, but this post may provide more information:
I did what what suggested in the jailbreak thread and it works perfectly.
Local script in starterCharacterScripts:
local plr = game.Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local root = char.HumanoidRootPart
local RaycastParam = RaycastParams.new()
RaycastParam.FilterType = Enum.RaycastFilterType.Exclude
RaycastParam.FilterDescendantsInstances = {char}
local platform = game.Workspace.MovingPlatform.Platform
local RS = game:GetService("RunService")
local lastCFrame = nil
function update()
local rayResult = workspace:Raycast(root.Position, Vector3.new(0,-50,0), RaycastParam)
if rayResult.Instance.Name == "Platform" then
if lastCFrame == nil then
lastCFrame = rayResult.Instance.CFrame
end
local rel = rayResult.Instance.CFrame * lastCFrame:inverse()
lastCFrame = rayResult.Instance.CFrame
root.CFrame = rel * root.CFrame
end
end
game["Run Service"]:BindToRenderStep("Update", 1, update)