Player falling sliding off moving platform

Hello Devforum! I have been making moving platforms using tween service but I have a problem where the player doesn’t move with the platform. I have researched this issue and found the topic: Moving platform for players using TweenService?. The only problem after reading this topic is that I couldn’t really understand what was happening. I read the topics provided, but was still very confused on what to do. The solution also did not make sense to me. Do I have to create a body gyro and body position in my platform and then tween them? How do I tween them with my code?

My script:

local tweenservice = game:GetService("TweenService")

for i, object in pairs(game.Workspace:GetChildren()) do
	if object:IsA("Folder") then
		if object:FindFirstChild("IsTower") then
			local tower = object
			if tower:FindFirstChild("MovingPlatforms") then --got folder with platforms
				local movingplatforms = tower.MovingPlatforms:GetChildren() --gets all moving platforms
				for i, moveplatform in pairs(movingplatforms) do
					coroutine.wrap(function()
						while true do
--Tweening code
							local tweeninfo = TweenInfo.new(moveplatform.Time.Value)
							local goal = {}
							goal.CFrame = moveplatform.Finish.CFrame
							local tween = tweenservice:Create(moveplatform.SpaceshipMove.PrimaryPart, tweeninfo, goal)
							tween:Play()
							wait(5)
							local tweeninfo = TweenInfo.new(moveplatform.Time.Value)
							local goal = {}
							goal.CFrame = moveplatform.Start.CFrame
							local tween = tweenservice:Create(moveplatform.SpaceshipMove.PrimaryPart, tweeninfo, goal)
							tween:Play()
							wait(5)
						end
					end)()
				end
			end
		end
	end
end

If I could get an explanation on how to do this in the future, I would really appreciate it! :smiley:

Hello there. So, from what I can understand, you are moving the primary part itself using CFrame? If so, then that is the issue.

When moving parts via CFrame, they are not counted as “Physics Objects” per say, so they will not move the player along with themselves. An easy way to fix that is to use a BodyPosition attribute (along with a BodyGyro so it does not spin around) and then change the Position of the BodyPosition using TweenService.

Example

Here is how the explorer looks like:
image

Here is the script that I used:

-- Services --

local TweenService = game:GetService("TweenService")

-- Variables --

local Start = workspace.Start -- Anchored brick at the start location
local End = workspace.End -- Anchored brick at the end location

local BodyPos = script.Parent -- BodyPosition force

local TweenInfo_ = TweenInfo.new(3, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut)

-- Scripting --

while true do
	local Completed = false
	
	local Tween = TweenService:Create(BodyPos, TweenInfo_, {Position = End.Position})
	Tween:Play()
	Tween.Completed:connect(function()
		Completed = true
	end)
	
	repeat wait() until Completed
	
	wait(5)
	
	Completed = false

	local Tween2 = TweenService:Create(BodyPos, TweenInfo_, {Position = Start.Position})
	Tween2:Play()
	Tween2.Completed:connect(function()
		Completed = true
	end)

	repeat wait() until Completed
	
	wait(5)
end

And here is how it looks in execution:
https://gyazo.com/4baea7a8e90a950e991f28e63a34ec26

Of course, you could optimize this more. I highly suggest you move the platforms locally as it will prevent lag and reduce the amount of people falling off at high speeds due to NetworkReplication.

Alternatively, you could another method which is not physics based but ensures people don’t fall from platform. You can find details about this one here.

I hope this helped you understand your problem better and even solved it. If you have any questions, feel free to ask.

4 Likes

Thank you for your response! I think I understand a bit more. I tried implementing most of ur script into my script and tweaked it to fit my needs, but it isn’t working as planned. There are no errors and it prints the print statement I put at the beginning of the loop and after the tween plays. Here is my current script. I am not sure what I did wrong.

local tweenservice = game:GetService("TweenService")

for i, object in pairs(game.Workspace:GetChildren()) do
	if object:IsA("Folder") then
		if object:FindFirstChild("IsTower") then
			local tower = object
			if tower:FindFirstChild("MovingPlatforms") then
				local movingplatforms = tower.MovingPlatforms:GetChildren()
				for i, moveplatform in pairs(movingplatforms) do
					coroutine.wrap(function()
						local start = moveplatform:WaitForChild("Start") --start
						local finish = moveplatform:WaitForChild("Finish") --finish
						local seconds = moveplatform:WaitForChild("Time") --time for waiting value
						local bodypos = moveplatform:WaitForChild("SpaceshipMove").Move.BodyPosition --getting the body pos from the move part
						local tweeninfo = TweenInfo.new(3, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut) --tweeninfo identical to yours
						while true do --start of loop
							print("ye") --print statement (prints by the way)
							local completed = false
							local tween = tweenservice:Create(bodypos, tweeninfo, {position = finish.Position})
							tween:Play() --plays tween but doesnt
							print("Played") --prints played though
							tween.Completed:connect(function()
								completed = true
							end)
							repeat wait() until completed
							wait(seconds.Value)
							completed = false
							local tween2 = tweenservice:Create(bodypos, tweeninfo, {position = start.Position})
							tween2:Play()
							tween2.Completed:Connect(function()
								completed = true
							end)
							repeat wait() until completed
							wait(seconds.Value)
						end
					end)()
				end
			end
		end
	end
end

Is there something wrong?

An error that I did notice was that the “p” in position was NOT capitalized, which will just cause an error. After testing it as well, I did confirm that this causes issues:

image

If I am correct, you just need to change the position to Position in {position = start.Position} and {position = finish.Position} and it should work as intended.

(Disregard the above as this is an issue when using the part’s position, not the BodyPosition property)

If you could provide more information and more details on what the issue is (so tell me if the issue is that it is not moving, or if the player is not moving along with the platform, etc) and what the output is (such as “ye”, “Played”, anything else that you might put there, or nothing), then I can understand better what is causing the problem and possibly help you fix it.

Oops! I am sorry about that. So yes, the platform is not moving at all, but the print statements at the beginning of the loop are indicating that the tween is being played, which it is not. I looked at all the moving platforms in my game and none of them were moving although the print statements printed 4 times, the number of platforms in my game.

Are you sure that the platform isn’t anchored? If it is, then it’s not going to be moving at all. It is a physics object, therefore it needs to be unanchored (and everything welded / attached to it as well) for it to work.

The platform itself is anchored, but when I do unanchor it, it will fall.

Sorry for the late response had some things to do

Creating a platform that moves with the player’s Character can be achieved in different ways; however, it appears that utilizing raycasting allows for much more flexibility under certain circumstances & is good enough for games such as Jailbreak and The Wild West to make use of it.


Background Info

When I tried to create the same kind of moving platform, the topic that you referenced in the OP is one that I read through as well but I faced similar challenges with trying to make sense of it, too.

However, I later came across a topic that tyridge77 and badcc had responded to in order to answer questions about how they achieved such effects in the games they’ve implemented trains into.

During that topic, someone provided an example of how it could be done based on the input of badcc and tyridge77, and I worked off of one of the examples until I came across an issue that was resolved with the help of another user (which is outlined in the following topic):


Resources

I would suggest reading through the topic that badcc & tyridge provided insight into in addition to the topic I created about solving the issue that was encountered in case it’s able to provide enough information that makes sense.

In summary, the platforms can be Tweened on their own and raycasting can be utilized to determine how far the player’s Character has moved since the last frame in order to update their position and keep them on the platform. While I haven’t had too much experience with raycasting prior to this, I can elaborate/explain in more detail, if needed.


Here’s a test place that demonstrates this:

Raycasting Test Place (Fixed Version!).rbxl (27.5 KB)

(For ease of access/without needing to open the place file, the following codeblock handles the raycasting which would go into a LocalScript in StarterCharacterScripts)

Click here to see the code
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local player = Players.LocalPlayer


local lastObjectRaycasted
local lastObjectCFrame


local Function
local Function2


local Whitelist = {workspace.MovableItems.MovingParts}



Function = RunService.Heartbeat:Connect(function()
	
	local Character = player.Character or player.CharacterAdded:Wait()
	local Humanoid = Character.Humanoid
	local HumanoidRootPart = Character.HumanoidRootPart
	
	
	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = Whitelist
	raycastParams.FilterType = Enum.RaycastFilterType.Whitelist
	
	
	local raycastParams2 = RaycastParams.new()
	raycastParams2.FilterDescendantsInstances = {lastObjectRaycasted}
	raycastParams2.FilterType = Enum.RaycastFilterType.Whitelist
	
	
	local downVector = HumanoidRootPart.CFrame.UpVector * -13
	local moveDirection = Humanoid.MoveDirection * 2.5
	local angle = downVector - Vector3.new(moveDirection.X, 0, moveDirection.Z)
	
	local RaycastResult = workspace:Raycast(HumanoidRootPart.CFrame.Position, angle, raycastParams)
	local lastObjectRaycastedRaycastResult = workspace:Raycast(HumanoidRootPart.CFrame.Position, angle, raycastParams2)
	
	
	local updatedInfo
	
	if lastObjectRaycasted and lastObjectRaycastedRaycastResult then
		updatedInfo = lastObjectRaycastedRaycastResult
		
	else
		updatedInfo = RaycastResult
		lastObjectRaycasted = nil
	end
	
	
	if updatedInfo then
		
		
		local distance = (HumanoidRootPart.CFrame.Position - updatedInfo.Position).Magnitude
		local visualizer = Instance.new("Part")
		visualizer.Anchored = true
		visualizer.Transparency = 0.5
		visualizer.BrickColor = BrickColor.new("New Yeller")
		visualizer.CanCollide = false
		visualizer.Size = Vector3.new(0.1, 0.1, distance)
		visualizer.CFrame = CFrame.lookAt(HumanoidRootPart.CFrame.Position, updatedInfo.Position) * CFrame.new(0, 0, -distance/2)
		visualizer.Parent = workspace
		
		
		local raycastInstance = updatedInfo.Instance
		
		if not lastObjectCFrame then
			lastObjectCFrame = raycastInstance.CFrame
		end
		
		
		local currentCFrame
		
		if lastObjectRaycasted and raycastInstance ~= lastObjectRaycasted then
			currentCFrame = lastObjectRaycasted.CFrame
		else
			currentCFrame = raycastInstance.CFrame
		end
		
		
		local relativeDistance = currentCFrame * lastObjectCFrame:Inverse()
		HumanoidRootPart.CFrame = relativeDistance * HumanoidRootPart.CFrame
		
		lastObjectRaycasted = raycastInstance
		lastObjectCFrame = raycastInstance.CFrame
		
	else
		lastObjectCFrame = nil
	end
	
	
	if not Function2 then
		Function2 = player.Character.Humanoid.Died:Connect(function()
			Function:Disconnect()
			Function2:Disconnect()
		end)
	end
	
end)

More info about Raycasting can be found on the following pages:

Raycasting Article

Raycast Documentation

RaycastParams Documentation

5 Likes