Aligning my vehicle with the surface below

I am creating a hovering vehicle that primarily uses an AlignOrientation for the orientation of the vehicle. I have hovering, throttle, steering, and braking all figured out so far.

The vehicle steering follows the mouse and also adds some slight tilt to the left and right while steering.

local SteerDirection = -(2*Player:GetMouse().X/Player:GetMouse().ViewSizeX-1)
Alignment.CFrame = CFrame.new(Alignment.CFrame.Position) * CFrame.Angles(0,math.rad(Vehicle.Center.Orientation.Y+3*SteerDirection),0) * CFrame.Angles(SteerDirection*math.rad(10),0,0)
--[[ 
This code controls the orientation of the vehicle.
The Y value of the AlignOrientation is the direction the vehicle is facing, so this is not relative to the surface below.
]]--

What I’m trying to achieve:
The alignorientation (X and Z values) align with the surface below the vehicle. (think of the vehicle slanting while going up a ramp) I also want to conserve the tilt applied by steering left or right (X value) alongside the new orientation (slant while going up a ramp) I am trying to apply.

What actually happens:
The vehicle floats above the surface as if it were flat. This is because the X and Z values of the AlignOrientation remain unchanged because I cannot figure out how to get the values needed.

I have noticed that manually changing the X and Z values of the AlignOrientation in the explorer while testing can give me the orientation I desire. I believe that using raycast normal I can achieve the appropriate values to change the AlignOrientation X and Z values to match the surface below, however I am struggling to understand raycasting and cframes and how to get the numbers i’m looking for.

I made a Bicycle System before and Achieved something like this, it’s probably not the most efficient way but it works great for my Case

Basically you just set up 2 Attachment Points, One at the Back Edge of the Vehicle, and One at the Front Edge of the Vehicle

Then Repeatedly cast a Ray Downwards (Vector3.new(0,-Lengtn,0) or UpVector) and when the Raycasts hit Something, set the AlignOrientation CFrame to CFrame.new(BackRayHitPos, FrontRayHitPos)

1 Like

This causes my vehicle to spin in circles, but only when the vehicle isn’t moving. I honestly am just not too familiar with CFrame.
Here is my current code (within a runservice.heartbeat)

local Params = RaycastParams.new()
	Params.FilterDescendantsInstances = {Center,Vehicle.VehicleModel}
	Params.FilterType = Enum.RaycastFilterType.Blacklist
	local Result1 = workspace:Raycast(Front.WorldCFrame.Position, Vector3.new(0, -20, 0), Params)
	local Result2  = workspace:Raycast(Rear.WorldCFrame.Position, Vector3.new(0, -20, 0), Params)
	if Result1 and Result2 then
		Alignment.CFrame = CFrame.new(Alignment.CFrame.Position) * CFrame.new(Result2.Position, Result1.Position)
	end
	
	if Throttle.VectorVelocity.X < -1.5 then
		Alignment.CFrame = CFrame.new(Alignment.CFrame.Position) * CFrame.Angles(0,math.rad(Vehicle.Center.Orientation.Y+3*SteerDirection),0) * CFrame.Angles(SteerDirection*math.rad(10),0,0)
	else
		TweenService:Create(Alignment,TweenInfo.new(.25,Enum.EasingStyle.Linear),{CFrame = CFrame.new(Alignment.CFrame.Position) * CFrame.Angles(0,math.rad(Vehicle.Center.Orientation.Y),0)}):Play()
	end

I think this is the Issue, it overrides the raycast CFrame, here try this

local Params = RaycastParams.new()
	Params.FilterDescendantsInstances = {Center,Vehicle.VehicleModel}
	Params.FilterType = Enum.RaycastFilterType.Blacklist
	local Result1 = workspace:Raycast(Front.WorldCFrame.Position, Vector3.new(0, -20, 0), Params)
	local Result2  = workspace:Raycast(Rear.WorldCFrame.Position, Vector3.new(0, -20, 0), Params)
	if Result1 and Result2 then
		Alignment.CFrame = CFrame.new(Result2.Position, Result1.Position)
	end
	
	if Throttle.VectorVelocity.X < -1.5 then
		Alignment.CFrame = Alignment.CFrame * CFrame.Angles(0,math.rad(SteerDirection),0) * CFrame.Angles(SteerDirection*math.rad(10),0,0)
	else
		TweenService:Create(Alignment,TweenInfo.new(.25,Enum.EasingStyle.Linear),{CFrame = CFrame.new(Alignment.CFrame.Position) * CFrame.Angles(0,math.rad(Vehicle.Center.Orientation.Y),0)}):Play()
	end

It still spins in circles once it comes to a stop, I’m not sure what’s going on