Tips for a rigidbody-based first-person system.

There are some threads on the subject, but they don’t seem to give me a good place to begin, as I see potential problems off the bat. For example, this doesn’t look like it would let you control your movement if you were on a fast-moving platform:

if(rigidbody.velocity.magnitude < maxSpeed  grounded == true)

If you’ve gotten a rigidbody-based movement scheme working, that takes this into consideration, I’d appreciate any code or concepts you could share.

I think I’ve got a nice start on movement, but rotation is jerky. Do you think I’ll need to actually work with torque, or is there a way to set rotation directly and have it look right? As it is, I’m not updating the rotation in FixedUpdate(); I’ll try that next, after I get some sleep. Here’s a donation of some code, if that will inspire you at all. :roll:

386324–13297–$moveavatar_126.cs (1.44 KB)

From what I’ve used it for so far, Unity (or perhaps PhysX) models a completely pre-Einstein, somewhat pre-Newton, and to a degree pre-Galileo universe (especially if you use Drag too heavily), or at least the APIs encourage such modeling. All velocities are in the frame of reference defined by static colliders and Physics.gravity, but nothing says you can’t record the grounded object and calculate a velocity limit relative to it.

The are plenty of gotchas though, like if you accelerate your character, his feet will effectively drag along the platform, applying friction to the platform, moving it Forward, whereas Newton assures us it should receive a force backwards (from his feet kicking it backwards). Again, you’re free to model that opposite force (in theory, whenever you apply a force, you should be applying opposite forces that sum to it).

Fortunately, game players accept, and even expect Gametonian Physics, not reality. I dare say that players would be confused if when on a rotating platform it was faster to move outwards than inwards, even though their experiences as a child on a playground merry-go-round should tell them they’re lucky to even be standing. So a physical character sounds great, just be prepared for the consequences!

There is not really an elegant way to get velocity relative to a platform, but you can use the OnCollisionStay function to detect if the rigidbody object is standing on one. Then, you can calculate the relative velocity by subtracting the platform’s velocity from the player’s.

The easiest way to apply a torque that makes the rigidbody rotate to a target orientation is to use a configurable joint on the object. Set the joint to slerp drive mode and then set a bit of position spring and damper on the slerp drive. Then, you can change the target rotation quaternion to specify which direction you want the rigidbody to point. You may need to tweak the damper value to be sure the joint doesn’t oscillate briefly as it reaches the target position.

The real problem with rigidbody-based movement seems to be grounding.

The trick (I think) is to use a little bit of fuzzy logic to decide when you’re grounded, rather than simply check for intersections.

I’ve tried simply firing a ray downwards a limited distance (“if my feet are within X of the ground, I’m grounded”) which works pretty well. (Note that I’m working with my faux gravity system right now, where you can easily get airborne simply by running fast in a straight line :slight_smile: )

Torque, Force, etc. all work pretty nicely once you’ve got groundedness sorted out.

Looking at normals in OnCollisionStay should suffice.

Unfortunately, it seems to me the current collision events (or their handlers) OnCollisionStay, OnCollisionEnter and OnCollisionExit are insufficient, even for detecting accurately if you are grounded or not. I’m new to Unity, but I write the following with the understanding I’ve gained after various tests and by reading the documentation (ambiguous in many parts).

For example, if you have a character with rigidbody standing on a static box collider (the ground), you would maybe expect the OnCollisionStay to only be called after the character has been moved by the physics update according to its current velocity. However, this is NOT the case (at least in Unity 2.6.1f3 which I’m using). The OnCollisionStay is called also if in the beginning of the physics update a “collision” is detected, and if so, then that handler is NOT called again, if a collision happens after the move. The event OnCollisionExit works similarly (it’s like the negation of the OnCollisionStay but it is not raised if a collision between the same colliders were not detected last time), so if you were colliding the ground before the physics update, the collision events cannot tell you if you are colliding it after the physics update.

In another words, you get to know about collision exits with a lag of one fixed update/physics update. Also, if you are out of a collision for only 1 physics frame, there seems to be no way to detect that with the collision handlers (also onCollisionEnter is useless here).

So when implementing the FixedUpdate, if you are really still grounded and jump by only updating the y-velocity, not y-position, a simple implementation using onCollisionStay will regard you as grounded also at the beginning of the next FixedUpdate, so you will have full ground control and maybe possibility to jump again. If you double jump and you add a constant to the y-velocity to implement the jumping, you will jump with double the y-velocity increase you intended. You could force you to be always regarded as airborne after a jump, but the delay remains when you exit a collision without jumping (e.g. run off a platform).

Another confusing thing is that when you are in a collision handler and reading the transform.position, it seems the character with the rigidbody has always finished the physics update. In another words, the handling of the collision events are delayed until the physics update has finished.
That’s why comparing the y-coordinate of contact points with the transform.position.y (plus some constant) does NOT work (as fast implementation) when trying to find out if you are colliding a collider you can stand on. Instead, you are forced to use the normals.

I understand that current collision events fit well in some cases where you directly change the Transform.position in the FixedUpdate function. However, In my opinion, the collision event interface needs to be improved so that Unity users can easily create even higher quality game physics.