Player won't move with model

In my game, I’ll be having trains drive through a station constantly but I also want the ability for the player to stick on the train if they end up there. Problem is, they won’t, the train moves but the player stays in the same spot.

I’ve tried searching around on Youtube and the Forum but I can’t simply find a solution to my problem. With Youtube it’s tutorials on moving platforms, with DevForum, it’s literally anything but my problem. I really can’t find a solution to my problem and I feel like once someone tells me, it’s going to be really obvious and easy, but I just can’t and I need help.

I’ve also attatched a video to further demonstrate my problem. I go on the train, it doesn’t take me.

1 Like
.Touched,

and connect it to an function to create an weld constraint to connect the plr to the train

If I’m going to honest, and it feels a bit embarrasing to say this, but I used ChatGPT to make my code and I don’t know how to do that.

ask chat gpt to make the code i described. Also, check out alvinblox, its how i learned how to script.

1 Like

I have and that’s the part it keeps messing up, can you make your statement more specific so I can put it in?

1 Like

Make some code, than when a part is touched, if it is a player that touched it, use an weld constraint to attach the player to the part.

use physics as opposed to cframe

1 Like

You can set the assembly velocity of the part to the difference in position and any parts touching it will move along with it. Roblox physics can be janky and unpredictable so I suggest tweens or manually setting the CFrame of the vehicle locally.

In my game, I have used this little CFrame math to make the player move on some moving anchored parts

image
Basically, this code gets the Offset CFrame of the character relative to the Part’s CFrame from the previous frame, and adds that offset back to the new CFrame of the part, using CFrame math

This is ran every frame, given the player has a HumanoidRootPart

As for other solutions provided on this thread, welds will work, but the player wont be able to move, using physics will work but I don’t like to rely on physics

3 Likes

Sorry but I’m not a scripter so I’ll probably be wrong but for the script you’ve given, should I put that in the model? And as a seperate script or in the script the moves the model? Because neither are working. :C

You should put it inside StarterCharacterScript, as a LocalScript

The script as a whole should look something like this

local RunService = game:GetService("RunService")

local LastTarget = nil

RunService.RenderStepped:Connect(function() 
	local Character = script.Parent
	if not Character then LastTarget = nil return end

	local Humanoid = Character:FindFirstChild("Humanoid")
	if not Humanoid then LastTarget = nil return end

	local HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart")
	if not HumanoidRootPart then LastTarget = nil return end

	local Height
	if Humanoid.RigType == Enum.HumanoidRigType.R6 then
		Height = HumanoidRootPart.Parent["Left Leg"].Size.Y + (0.5 * HumanoidRootPart.Size.Y) + Humanoid.HipHeight
	else
		Height = (0.5 * HumanoidRootPart.Size.Y) + Humanoid.HipHeight
	end

	local RaycastParam = RaycastParams.new()
	RaycastParam.FilterType = Enum.RaycastFilterType.Exclude
	RaycastParam.FilterDescendantsInstances = {Character}
	local RaycastResults = workspace:Raycast(HumanoidRootPart.Position,Vector3.new(0,-Height -6,0),RaycastParam)

	local Target = RaycastResults and RaycastResults.Instance
	if not Target then LastTarget = nil return end

	if LastTarget == Target then 
		local Offset = LastTarget.CFrame:Inverse() * HumanoidRootPart.CFrame
		HumanoidRootPart.CFrame = Target.CFrame * Offset
	end
	
	LastTarget = Target
end)

I haven’t tested this code though lel


If you want to learn scripting, I recommend starting with these tutorials on the roblox docs

It goes over basics that is often overlooked in other scripting tutorials, and it encourages the learner to code alongside the tutorial which is a great way to learn

It doesn’t go over everything though, but it will give you a good basic understanding of coding (which imo is the hardest part)
image

However, the saving data tutorial is good for a basic understanding of datastores, but the code is prone to data loss
The Player Tools tutorial isn’t really about scripting but more about setting up tools
The leaderstats tutorials is mainly for leaderstats, if you want to use them

I put it the code in the StarterCharacterScripts but it’s not working. Also, I know I don’t know much about coding, but I feel like they should just be an easy fix instead of all of this right. It’s just like a moving platform, just a model though.

Your model doesn’t move using the physics engine, instead, the position of your train is updated manually every frame (which is fine, it cannot derail or anything). If it used the physics engine, then no code would be needed. The code I provided isn’t that complex (well it definitely is for a beginner), but most of it is just getting the character and doing a raycast, to then update the CFrame of the character


I tested my code and well there was a small issue, so here is a working version

local RunService = game:GetService("RunService")

local LastTarget = nil
local LastCFrame = nil

RunService.RenderStepped:Connect(function() 
	local Character = script.Parent
	if not Character then LastTarget = nil return end

	local Humanoid = Character:FindFirstChild("Humanoid")
	if not Humanoid then LastTarget = nil return end

	local HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart")
	if not HumanoidRootPart then LastTarget = nil return end

	local Height
	if Humanoid.RigType == Enum.HumanoidRigType.R6 then
		Height = HumanoidRootPart.Parent["Left Leg"].Size.Y + (0.5 * HumanoidRootPart.Size.Y) + Humanoid.HipHeight
	else
		Height = (0.5 * HumanoidRootPart.Size.Y) + Humanoid.HipHeight
	end

	local RaycastParam = RaycastParams.new()
	RaycastParam.FilterType = Enum.RaycastFilterType.Exclude
	RaycastParam.FilterDescendantsInstances = {Character}
	local RaycastResults = workspace:Raycast(HumanoidRootPart.Position,Vector3.new(0,-Height -8,0),RaycastParam)

	local Target = RaycastResults and RaycastResults.Instance
	if not Target then LastTarget = nil return end

	if LastTarget == Target then 
		local Offset = LastCFrame:Inverse() * HumanoidRootPart.CFrame
		HumanoidRootPart.CFrame = Target.CFrame * Offset
	end

	LastTarget = Target
	LastCFrame = LastTarget.CFrame
end)

I suspected that because the model is being manually updated it would be buggy due to the fact that the changes between CFrames is extremely short (0.001) making it hard for the player to keep up or go along smoothly as well as the model moving by 1.5. I think if I fiddle around I could get something good but for now I won’t mark it as a solution.

I don’t quite understand (the model moves by 0.001 or by 1.5?), and even if the movement is very small every frame, that is not problematic

Does it work with the new code?

The model moves by 1.5 studs every 0.001.

The camera seems to not follow the character properly, which is a bit odd. Using RenderStepped should makes it run before the camera updates. Maybe BindToRenderStepped can lead to better results, it does seem to make things very smooth for me, while using RenderStepped seems to have small jitters

local RunService = game:GetService("RunService")

local LastTarget = nil
local LastCFrame = nil

RunService:BindToRenderStep("CharacterOnMovingParts",Enum.RenderPriority.Camera.Value - 100,function()
	local Character = script.Parent
	if not Character then LastTarget = nil return end

	local Humanoid = Character:FindFirstChild("Humanoid")
	if not Humanoid then LastTarget = nil return end

	local HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart")
	if not HumanoidRootPart then LastTarget = nil return end

	local Height
	if Humanoid.RigType == Enum.HumanoidRigType.R6 then
		Height = HumanoidRootPart.Parent["Left Leg"].Size.Y + (0.5 * HumanoidRootPart.Size.Y) + Humanoid.HipHeight
	else
		Height = (0.5 * HumanoidRootPart.Size.Y) + Humanoid.HipHeight
	end

	local RaycastParam = RaycastParams.new()
	RaycastParam.FilterType = Enum.RaycastFilterType.Exclude
	RaycastParam.FilterDescendantsInstances = {Character}
	local RaycastResults = workspace:Raycast(HumanoidRootPart.Position,Vector3.new(0,-Height -8,0),RaycastParam)

	local Target = RaycastResults and RaycastResults.Instance
	if not Target then LastTarget = nil return end

	if LastTarget == Target then 
		local Offset = LastCFrame:Inverse() * HumanoidRootPart.CFrame
		HumanoidRootPart.CFrame = Target.CFrame * Offset
	end

	LastTarget = Target
	LastCFrame = LastTarget.CFrame
end)

As for how you move the train, it doesn’t actually move 1.5 studs every 0.001 seconds. The smallest amount of time task.wait() can wait is one frame, or 0.0166 seconds, if the client is running at 60fps. A wait time of 0.001 seconds would require a fps of 1000, and if the train was actually moving 1.5 studs every 0,001 seconds, it would move 1500 studs every second, which it clearly isn’t. This also presents another issue with moving an object by a fixed distance every frame, the speed changes with the fps. Here is how you can fix this issue

local RunService = game:GetService("RunService")

local Speed = 90 -- 90 studs per second, which should be about the same speed you have currently

local StartPosition = Vector3.new(-512,0,0)
local StartTime = os.clock()

-- RunService.Hearbeat is used to make this function run every frame
RunService.Heartbeat:Connect(function() 
	local TimeDifference = os.clock() - StartTime -- How many seconds have passed since the start
	
	Part.Position = StartPosition + Speed*TimeDifference -- 90 studs/s * 0.5s = 45 studs, etc ...
end)

If you want the train to repeat this path many times, you can do something like this

local RunService = game:GetService("RunService")

local StartPosition = Vector3.new(-512,0,0)
local EndPosition = Vector3.new(512,0,0)
local Duration = 20 -- How much time it takes for the train to go from StartPosition to EndPosition
local WaitTime = 10 -- How much time there is between passing trains

RunService.Heartbeat:Connect(function() 
	local TotalDuration = Duration+WaitTime
	local t = os.clock() - math.floor(os.clock()/TotalDuration)*TotalDuration 
	-- t goes from 0 to 30 seconds, repeatedly
	-- math.floor() floors the number (1.33 -> 1, 1.75 -> 1, 64.2 -> 64) 
	-- By doing os.clock()/TotalDuration, what is does is basically this
	-- 70 - math.floor(70/30)*30
	-- 70 - math.floor(2,33)*30
	-- 70 - 2*30
	-- 70 - 60
	-- 10 seconds
	-- the number returned by os.clock() is very big, much bigger than 70, but the same principle applies

	local alpha = math.min(t/Duration,1) -- Since duration is 20, and t can go to 30, t/Duration can be higher than 1
	-- However, the math.min prevents alpha from going above 1 (math.min returns the smaller of the two given numbers)
	-- This means that the train will be stuck at alpha 1 (100%), for 10 seconds

	Part.Position = StartPosition:Lerp(EndPosition, alpha) -- :Lerp() lerps the vector from StartPosition to EndPosition, using alpha, alpha of 0.25 means the lerped vector will be 25% of the way between Start and End, 0.5 is halfway, and 1 is all the way to End
end)

You can do pretty much do the same thing using TweenService, but much simpler (without all the math), but I didn’t feel like introducing TweenService (as if this was simpler… um I wrote this, I don’t feel like erasing it)

Don’t feel intimidated by this code, it is important to not skip steps when learning to code, or learning doesn’t really work

Look man, I know you put a lot of effort into your posts but you’re adding too much stuff, for what I feel like should be something simple. You added a wait time between trains which I don’t why, you made code for the train repeating which I already had and you added some math for some reason too. I don’t even know where to put all this code. You acknowledge me as a beginner but then don’t act as though I am one and I simply do not understand so much of this. I hope this does not come across as aggressive but I just really need something simple.

1 Like

Yeah… I get it

If you want to make scripts inside your game, you’ll likely have to learn scripting, have ChatGpt do the scripts for you (which doesn’t work very well for more complex stuff), or you’ll have to hire a scripter. There isn’t really a “simple” solution, well, other than making the train move using the physics engine. And I assume there will be other aspects of your game that will require some scripting

The other simple solution (for the train) would be using TweenService, but that still isn’t something you’d find simple probably. When learning to script, you really want to start with the fundamentals

Scripting (for a game) is the combination of many concepts you have to learn separately, ideally

Let me know what you are thinking right now about this

If you have any simple solutions, which you might’ve already posted, I’m all for it, but I need a step by step process, of where I need to put things and maybe an explanation for each code. I also want to apologise by bothering you so very much, so thank you for helping.

1 Like