Make part move with other part

I have an obby game with parts that move from side to side and the player controls a ball as their character. These parts are moved using TweenService.

I want the ball to move with the part and I have been able to implement this behavior with the following code running on the client:

---> services
local RunService = game:GetService("RunService")
local CollectionService = game:GetService("CollectionService")

---> variables
local lastCframe

---> functions
local function runCheck()
	local playerBall = workspace:WaitForChild("PlayerBalls"):FindFirstChild(`Ball_{Players.LocalPlayer.UserId}`)
	if not playerBall then return end
	
	-- cast a ray to check if the player is touching a part
	local ray = Ray.new(playerBall.CFrame.Position, Vector3.new(0, -10, 0))
	local hit = workspace:FindPartOnRay(ray, playerBall)
	
	-- check if the part the player ball is touching is a moving part
	if hit and (CollectionService:HasTag(hit, "movingPart") or CollectionService:HasTag(hit.Parent, "movingPart")) then
		if hit.Parent:FindFirstChild("Configuration") then
			local moveDir = hit.Parent.Configuration:GetAttribute("MoveDirection") 
			
			-- we only want to track the part when it is moving side to side (left or right)
			if moveDir == "Left" or moveDir == "Right" then
				if not lastCframe then
					lastCframe = hit.CFrame
				end
				local rel = hit.CFrame * lastCframe:Inverse()
				
				lastCframe = hit.CFrame
				playerBall.CFrame = rel * playerBall.CFrame
			end
		end
	else
		lastCframe = nil -- player is no longer on the platform
	end
end

---> main
RunService.Heartbeat:Connect(runCheck)

This is based off the following post solution: Jailbreak train platform system? - #35 by Kord_K

The one problem I am experiencing is that when a player is on a moving platform like the one above, when they first jump off they are teleported forward a bit and it doesn’t look smooth at all. An example of this occurring can be seen below:

I’m hopeful that anyone else who has created similar systems where characters move with parts could help me with this issue - I’m a bit of a noob with physics stuff.

Thanks in advance :slightly_smiling_face:

Try using this instead:

local RunService = game:GetService("RunService")
local CollectionService = game:GetService("CollectionService")

local lastCFrame = nil
local playerBall = workspace:WaitForChild("PlayerBalls"):WaitForChild("Ball_" .. game.Players.LocalPlayer.UserId) -- Assuming it exists

local function movePlayerBallWithPart(part)
    if part.Parent and part.Parent:FindFirstChild("Configuration") then
        local moveDir = part.Parent.Configuration:GetAttribute("MoveDirection")
        
        if moveDir == "Left" or moveDir == "Right" then
            local currentCFrame = part.CFrame
            
            if lastCFrame then
                local relativeCFrame = currentCFrame:ToObjectSpace(lastCFrame)
                playerBall.CFrame = relativeCFrame * playerBall.CFrame
            end
            
            lastCFrame = currentCFrame
        end
    end
end

RunService.Heartbeat:Connect(function()
    local ray = Ray.new(playerBall.Position, Vector3.new(0, -10, 0))
    local hit, _ = workspace:FindPartOnRay(ray, playerBall)
    
    if hit then
        if CollectionService:HasTag(hit, "movingPart") or CollectionService:HasTag(hit.Parent, "movingPart") then
            movePlayerBallWithPart(hit)
        else
            lastCFrame = nil
        end
    else
        lastCFrame = nil
    end
end)

The same teleporting issue still occurs when using this script.