Making your character move relative to the part it's standing on for parts being moved with CFrame and TweenService?

I initially assumed anchored parts on the client being moved using CFrame and TweenService would work with Moving Platforms although it appears they don’t:

https://i.gyazo.com/12c6f5cbc402a4e74e0d64d7efdac5a1.mp4

What’s the best way to fix this without switching to alternative methods such as body movers or constraints?

3 Likes

I don’t think you can use tweens for this sort of thing, because Tweening doesn’t consider physics, if you use things like bodygyro or body position, it’ll take physics into consideration and it’ll start working.

you can also tween the properties of BodyPosition & BodyGyro if you really need the tween service.

IIRC @EgoMoose’s character controller can do this!

Try digging through it!

A great post that actually helps with this issue is this:

@ForeverHD I wouldn’t use a custom character controller, then you would have to learn a new character controller system.

and It also only takes 2-4 lines of code, you don’t need raycasting or any special math either.
you just have to remember that tweening object CFrames will bypass any physics, BUT if you tween body position or gyro’s then its the opposite.

TweenService:Create(BodyGyro, TweenInfo.new(1), {CFrame = CFrame.new(0,0,0})

TweenService:Create(BodyPosition, TweenInfo.new(1), {Position = Vector3.new(0,0,0})


1 Like

That’s an old module.

I suggest using the Wall Stick Controller in this post:

It does just a bout everything better.

8 Likes

Thanks all for the replies. For anyone reading in the future, here’s some simplified code based on EgoMoose’s WallStick to achieve the effect:

-- LOCAL
local runService = game:GetService("RunService")
local players = game:GetService("Players")
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local hrp = character:WaitForChild("HumanoidRootPart")
local gap = 0.1
local offsetY = -hrp.Size.Y * 1.5
local previousPart
local previousMovingPartCFrame


-- STICK
runService.Heartbeat:Connect(function(step)
	if humanoid.Health <= 0 then
		return
	end
	local origin = hrp.Position + Vector3.new(0, offsetY+gap, 0)
	local lookDirection = origin + Vector3.new(0, -1, 0)
	local ray = Ray.new(origin, (lookDirection - origin).unit * gap*2)
	local movingPart, standingPos = workspace:FindPartOnRay(ray, character)
	if movingPart and previousMovingPartCFrame and movingPart == previousPart then
		local offset = previousMovingPartCFrame:toObjectSpace(hrp.CFrame)
		hrp.CFrame = movingPart.CFrame:toWorldSpace(offset)
	end
	previousPart = movingPart
	previousMovingPartCFrame = movingPart and movingPart.CFrame
end)
15 Likes

this code isn’t working for me, should this be in local script or server script?

It quite specifically says – LOCAL at the top as well as using LocalPlayer so it has to be a localscript no?

Why do i am not being sticked when i am a bit laggy ?

I may be extremely late(4 months late to be exact) but some people such as myself might stumble upon this thread and find this reply helpful. Try putting this into a local script in startercharacter, it isn’t perfect but I made it entirely local and updated the raycast to workspace:raycast due to the raycast inside the other script being deprecated.

-- LOCAL
local runService = game:GetService("RunService")
local players = game:GetService("Players")
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local hrp = character:WaitForChild("HumanoidRootPart")
local gap = 0.1
local offsetY = -hrp.Size.Y * 1.5
local previousPart
local previousMovingPartCFrame
local movingPart

local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
raycastParams.FilterDescendantsInstances = {character}

-- STICK
runService.RenderStepped:Connect(function(step)
	if humanoid.Health <= 0 then
		return
	end
	local origin = hrp.Position + Vector3.new(0, offsetY+gap, 0)
	local lookDirection = origin + Vector3.new(0, -1, 0)

	local ray = workspace:Raycast(origin, ((lookDirection - origin).unit * gap*2), raycastParams)
	if ray then
		movingPart = ray.Instance
	end

	if movingPart and previousMovingPartCFrame and movingPart == previousPart then
		local offset = previousMovingPartCFrame:toObjectSpace(hrp.CFrame)
		hrp.CFrame = movingPart.CFrame:toWorldSpace(offset)
	end
	previousPart = movingPart
	previousMovingPartCFrame = movingPart and movingPart.CFrame
end)
1 Like