# Best practices for a rigidbody controller

In my test project, I want to create a rigidbody-based vehicle prefab for most of the actors in the game. In testing, I’m discovering that I don’t understand the best way to manage keeping the physics engine from throwing my vehicles all over the place.

Assume all vehicles are hovercraft. The primary surface on which vehicles must operate is a terrain. Here’s what I’m doing now:

Vehicle Object
----Body
--------repulsor (empty) for each of 4 corners
----Target

The Vehicle Object stays at the world origin (it’s just for organization). Initially, the Body and Target are placed in the desired location. The Repulsors cast rays down and use this data to apply force up, thus keeping the object aloft, and aligned to the surface below the vehicle. Body rotation is explicitly clamped within a certain tolerance to prevent the vehicle from spinning out of control and losing the hover functionality.

On X and Z, force is applied to make the rigidbody seek the Target position. When input is applied, the Target position is what the input controls, and force is added to the Body to try to reach it. Not doing this means the hover function can move the ship freely on X and Z, and does so until the ground beneath is flat enough for the drag to cancel out that motion.

I think I’m going down the wrong path here. The more controls I add, the more checks and balances I must add, and the whole thing is starting to seem less and less reliable. Can anyone suggest alternative methods for achieving the same result? I would appreciate having some second opinions.

Thanks…!

OK, so I dig the concept of a move target based drift. Though I think the concept could be tweaked a bit. Consider 1) casting a ray from the current position straight down to the planet’s surface. This gives you a distance and normal. (NOTE: this concept requires that gravity be turned off)

OK, first distance: your distance to the surface should be constant + a sine wave to make it look like it’s floating. If it is greater than that, then you need to apply downward force based on gravity. if it is less then you apply upward force based on the distance to the float spot. This would be a semi buoyancy script.

OK, the normal: This should be the tilt of the ship. So 1. Store the current rotation and y euler so you can re-use them. Set transform.up = the normal then set the y rotation to the last y rotation. Then do a Quaternion.Lerp(rotation, transform.rotation, 2.0 * Time.deltaTime). This will force a self correcting rotation. You could also then use the normal to add drift.

One of the cool “semi-physics” concepts that I was dealing with on a project similar was that any input or tweak would be applied to the physics through Lerps. This means that if you are flying along and you clip something it should turn a bit and/or stop but would react fairly normally. The usage of this revolves around Velocities, not Forces.

I really appreciate this detailed reply; you are now my favorite person of the day! In seeking more reliable, predictable, responsive behavior, I actually began programming a poor-man’s PID controller for both translations / rotations. Your idea of using pseudo-physics is very appealing versus the results I’ve been getting. I understood where you’re coming from on everything except this: How to let the sim dictate rotation while still maintaining explicit control.

Ideally, I could have some play on rotation when reacting to collisions with other bodies. Maybe my rotation clamp could be clamping X,Z angular velocity with a Lerp:
Minimal resistance when X,Z rotation matches surface normal, (can rock the boat)
Total resistance when angular velocity would cause the rotation to exceed a threshold. (can’t tip the boat over)
How does this sound?

Obviously X,Z rotation would be dependent on the normal of the surface below, and thus won’t be 0,0. What then, is the best way to enforce my Y rotation to be what I want while still allowing X,Z to be dictated by the surface normal? In other words, what’s the best way to script a TurnToFaceThisPoint() method without relying on or messing with X,Z, and while avoiding Gimbal Lock or using %360 and eulers everywhere?