Trying to align the player to one axis of a part

Hi i’m trying to create rail grinding for my game and i’m currently stuck on trying to align the player to the part when touching it

is there any way i can try achieving this?

2 Likes

I made a script that changes the CFrame of the HumanoidRootPart and then welds the character to the rail part. After that it calls a move function that moves the character on the rail by changing the C0 of the weld. It changes the direction that the character faces and moves to when the player turns their camera enough.It uses Humanoid.Walkspeed for the movement speed.It uses raycasting to check if the character is still on the rail. If it isn’t it detaches it by destroying the weld and doing some other things. It also does this is the character dies.

I’m not sure what is the exact behavior you want, so you might need to modify this. If you only wanted a way to attach the character to the track, you don’t need the move function, just detach it somewhere else in the code. This script only works properly if the Size.Z of the part is its largest size value and Size.X and Size.Y are the small values. This should work even if the part is rotated. It may look weird if it’s been rotated too much, though. I have noticed that setting Humanoid.Platformstand to true doesn’t work when the character hits the part while jumping and even if I tried to change it in a Stepped loop after that, it didn’t work. However, it works if you are walking when you touch the part.

local RunService = game:GetService("RunService")

local COOLDOWN = 1
local RAIL_ANIMATION = nil

local trackPart = -- reference to the track part here.

local cantBeWelded = {}
local railAnimTracks = {}

local function detachCharacter(char, hum)
	trackPart[char.Name]:Destroy()
	hum.AutoRotate = true
	hum.PlatformStand = false
	railAnimTracks[char.Humanoid] = nil
	if COOLDOWN > 0 then
		wait(COOLDOWN)
	end
	cantBeWelded[char] = false
end

local function moveChar(char, hum, hrp) -- this function takes care of moving and deataching the player
	if RAIL_ANIMATION then
		local railAnimTrack = railAnimTracks[hum]
		if not railAnimTrack then
			railAnimTrack = hum:LoadAnimation(RAIL_ANIMATION)
			railAnimTracks[hum] = railAnimTrack
		end
		railAnimTrack:Play()
	end
	local weld = trackPart[char.Name]
	local raycastParams = RaycastParams.new()
	raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
	raycastParams.FilterDescendantsInstances = {char}
	raycastParams.IgnoreWater = true
	
	local _, delta = nil, 0
	while char.Parent and hum.Health > 0 do
		-- move the character
		if hum.MoveDirection ~= Vector3.new() then
            -- check if the direction should be changed
			if hrp.CFrame:ToObjectSpace(hrp.CFrame+hum.MoveDirection).Z > 0 then
				weld.C0 *= CFrame.Angles(0, math.pi, 0)
			end
			weld.C0 *= CFrame.new(0, 0, -hum.WalkSpeed*delta)
		end
		-- check that the character is still on the track
		local rayDirection = trackPart.CFrame*Vector3.new(0, 0, (trackPart.CFrame:Inverse()*hrp.CFrame).Z)-hrp.Position
		local raycastResults = workspace:Raycast(hrp.Position, rayDirection, raycastParams)
		if not raycastResults or raycastResults.Instance ~= trackPart then
			detachCharacter(char, hum)
			return
		end
		_, delta = RunService.Stepped:Wait()
	end
    -- the code will only reach this if statement if the humanoid has dies or the character was removed 
	if trackPart:FindFirstChild(char.Name) then
		detachCharacter(char, hum)
	end
end

local function onTrackTouched(hit)
	local hitParent = hit.Parent
	if cantBeWelded[hitParent] then
		return
	end
	local hum, hrp = hitParent:FindFirstChild("Humanoid"), hitParent:FindFirstChild("HumanoidRootPart")
	if hum and hrp then
		cantBeWelded[hitParent] = true
		hum.AutoRotate = false
		hum.PlatformStand = true
		-- position and rotate the character correctly
		local trackPartCf = trackPart.CFrame
		local relCF = trackPartCf:ToObjectSpace(hrp.CFrame)
		local newHrpCf = trackPartCf*CFrame.new(0, hum.HipHeight+hrp.Size.Y/2-trackPart.Size.Y/2, relCF.Z)
		if hrp.CFrame:ToObjectSpace(hrp.CFrame+hum.MoveDirection).Z > 0 then
			newHrpCf *= CFrame.Angles(0, math.pi, 0)
		end
		hrp.CFrame = newHrpCf
		
		-- create a weld that prevents the character form being moved normally
		local weld = Instance.new("Weld")
		weld.Name = hitParent.Name -- character's name
		weld.Part0 = trackPart
		weld.Part1 = hrp
		weld.C0 = trackPart.CFrame:ToObjectSpace(hrp.CFrame)
		weld.C1 = CFrame.new()
		weld.Parent = trackPart
		
		-- start moving the character
		moveChar(hitParent, hum, hrp)
	end 
end

trackPart.Touched:Connect(onTrackTouched)
3 Likes

Exactly what i was looking for. Thank you so much!

1 Like