This looks like the problem line, specifically:
CFrame.new(Vector3.new(),normal)
This two-argument CFrame constructor can cause very different orientations based on small changes in input, which is most likely what is causing your random 180 turns. This is because the constructor only supplies information to create the LookVector
of the CFrame, so internally a RightVector
and UpVector
must be chosen and this can be fairly unpredictable/unstable. There’s an explanation which may help you here.
The best way to solve your problem, assuming I’ve diagnosed it correctly, is to use the full 12-argument CFrame constructor - you can find information on it here.
Leaving aside the extra orientation of your MeshPart you mentioned, you need to calculate the LookVector, RightVector, and UpVector of the CFrame you want to supply to the BodyGyro (Position doesn’t matter for the BodyGyro).
- Your LookVector relates to your camera LookVector (judging from your code)
- Your UpVector is the computed surface normal
- Your RightVector is the vector which is orthogonal (at a right angle) to both the LookVector and the UpVector - you can use the Cross product to calculate this.
Your code might look something like this:
local lookVector = camera.CFrame.LookVector
local upVector = sharedFunctions:GetSurfaceNormal()
local rightVector = lookVector:Cross(upVector)
local gyroCFrame = CFrame.new(
0, 0, 0
rightVector.x, upVector.x, -lookVector.x, -- constructor actually takes backVector (-lookVector)
rightVector.y, upVector.y, -lookVector.y,
rightVector.z, upVector.z, -lookVector.z
)
bike.Chassis.BodyGyro.CFrame = gyroCFrame
You will need to account for “the MeshPart’s weird orientation” by adding the * CFrame.Angles(…) after the longer constructor code.