How do I make body gyro oriented to the ground

I am making a horse using body gyro, but now it just stays the same on the floor and on the slope. I am trying to manipulate it Angles using RaycastResult.Normal, but I don’t know where to go next.

image
image

Here is the code i use to detect Surface Normal

		local ray = Ray.new(driverSeat.Position, Vector3.new(0, -20, 0))
		local target, position, surfaceNormal = workspace:FindPartOnRay(ray)
		
		bodyGyro.CFrame = -- what should I do with surface Normal
		

==ALTERNATIVE SOLUTION==

4 Likes

horse

‘lookvector’ would be the general direction the horse is facing.
the ‘red’ vector is the lookvector crossed with the normal vector.
the ‘yellow’ vector is the normal vector crossed with the ‘red’ vector, it should point in the same X-Z direction as ‘lookvector’ while being aligned with the ground.

So you want your bodygyro to be a CFrame that points along the yellow vector.

local ray = Ray.new(driverSeat.Position, Vector3.new(0, -20, 0))
local target, position, surfaceNormal = workspace:FindPartOnRay(ray)

local p1 = driverSeat.CFrame.LookVector:Cross(surfaceNormal)
local p2 = surfaceNormal:Cross(p1)

bodyGyro.CFrame = CFrame.new(Vector3.new(0, 0, 0), p2)

Also the old ray casting method is apparently being deprecated; Roblox wants us to use workspace:Raycast now.

2 Likes

ok, so now I also have steering, how can I make steering and this work together. and thank you, you solve one of my problems

		bodyGyro.CFrame = bodyGyro.CFrame * CFrame.Angles(0,math.rad(steer),0) -- steering function
		bodyGyro.CFrame = CFrame.new(HRP.Position, p2)  --ur function

I would apply the Angles calculation after calculating the orientation relative to the ground, then you would only need to update the bodygyro once instead of twice:

bodyGyro.CFrame = CFrame.new(HRP.Position, p2) * CFrame.Angles(0, math.rad(steer), 0)
2 Likes

I tried this, you can’t steer after using this, but I am figuring something out

I mark the answer as a solution because it did help me out, it just bug after bug

Alright.

Also I found a case in my code where it might not align with the ground if you are sideways on a slope.
You would want to construct a cframe whose lookVector is pointing along the yellow, and whose upVector is pointing along the surface normal:

local p1 = driverSeat.CFrame.LookVector:Cross(surfaceNormal)

--fromMatrix calculates the new lookvector for us so all we need is the rightVector and upVector
bodyGyro.CFrame = CFrame.fromMatrix(Vector3.new(0, 0, 0), p1, surfaceNormal)
4 Likes

Now that work :D, thank you so so much, final code

bodyGyro.CFrame = CFrame.fromMatrix(HRP.Position, p1, surfaceNormal) * CFrame.Angles(0, math.rad(steer), 0)
2 Likes

TestRig.rbxl (145.0 KB)
(Hit Play, not run Or hit F5 to demo)

An alternate and much better way (in my opinion) is to raycast down at 3 points around the horse and then define a plane which all three points lie on.
Orient the horse so that it is level with the plane.
Each leg should now roughly appear to be standing on each of the positions directly below it.
The result is a much smoother transition.

The demo above also has physics code for handling a max slope angle which I thought was nice to include. The legs also move a bit more freely to allow for more smoothness and less jumpiness.
Enjoy.

6 Likes

One thing I wanted to add for those who see this when searching same problem,
the reason the above is better than acquiring the surface normal is because:

Imagine a flat plane and a ramp.
Surface normal method abruptly changes orientation when moving from flat plane to ramp (and can make it jumpy / glitchy).

Whereas

Method above changes orientation smoothly. I.e. if your animal puts half its body on the ramp and half on the flat plane, it will orient sort-of halfway between them placing the legs appropiately. The freely moving legs also help with smoother transitions.

As an example, The Wild West uses something similar to 3-point plane method.

5 Likes