[SOLVED] rigidbody character standing on moving objects

like many misguided fools before me, i am trying to make a character that can stand on moving objects without sliding off (why isn't this a default behaviour or a toggle in the physics settings? surely thousands of users need this), specifically i am trying to implement a self-contained system that requires no parenting, as this would be incompatible with rigidbody movement (not to mention how much it messes up scale).

in my current setup, i can determine how much velocity the player should inherit from whatever object it is standing on (including rotational velocity) and can apply that velocity to the character's position. however, this seems to mess up the character's rigidbody velocity, and causes them to move in an inconsistent and stuttery way (even when the object they are standing on is not moving at all).

my code looks like this:

private void ApplyInheritedVelocity () {
  if (grounded) { //if we're grounded (we only want to apply inherited velocity if there is something to generate it);
    currentContactTransform = groundContact.collider.transform; //set our current contact transform to be whatever we are standing on;
    if (currentContactTransform == lastContactTransform) { //if the current contact transform is the same as last frame (which means we have remained in contact with it);
      inheritedVelocity = (currentContactTransform.TransformPoint (localContactPoint) - globalContactPoint); //find the difference between our current and previous contact points in world space, this is how far the object should have carried us in that time;
      transform.position += inheritedVelocity; //add inherited velocity to character position;
    localContactPoint = currentContactTransform.InverseTransformPoint (groundContact.point); //create new local contact point;
    globalContactPoint = groundContact.point; //and new global contact point;
  } else { //if we're not grounded;
    currentContactTransform = null; //then our ground contact is null;
  lastContactTransform = currentContactTransform; //and store the current contact transform in our last contact variable, even if that contact is null;

i have tried using rigidbody.MovePosition, transform.Translate, rigidbody.AddForce, setting the rigidbody's velocity directly, joining the two objects with a fixed joint, and (of course) parenting. none of these solutions has worked.

is this really such an impossible problem?

It is not impossible but tricky.

For instance, timing plays a crucial role here. This ApplyInheritedVelocity should be running in FixedUpdate to begin with, or more precisely, it should run within the physics simulation itself - which I believe you cannot do in Unity. The problem being that physics determined that the objects standing on a moving, slightly tilted platform must have force applied to slowly start sliding in one direction. So it applies that force, and calculates the new position of the rigidbody on the platform.

Now you have two problems: you not only have to counter the effect of all forces that were applied solely by standing on the tilted platform, you also have to move the object back to its previous position at the same time since it has already been moved.

This may work to some degree by applying these changes right after FixedUpdate ran - which means you’d have to hook into the PlayerLoop because there is no “LateFixedUpdate”. As a quick-fix solution, you could set a bool in FixedUpdate, and check for that in Update and reset the bool to only run this correction code after physics simulation ran.

Properly calculating the inverse force will still be tricky, since you’d have to know about how the physics engine works internally, how it generates its forces, which constant values it uses and which dynamic values are being factored in, and so on.

In the end, practically all games solve this using kinematic physics only, so that the object doesn’t move by the physics simulation but only forces you apply to it.

i actually have implemented a late and early fixed update system into this particular project. i have a class which is responsible for handling the physics simulation and which invokes events immediately before and after the simulation to allow for code injection at appropriate times.
i think my problem may have been misinterpreted. i am not trying to stop my player from literally sliding off the object (either because the surface is angled or the physics material is too slick), but rather i am trying to ensure that my player is carried by whatever it is they are standing on, without using parenting, and regardless of the properties of the carrier (whether or not they are moved by physics or animation (both procedural and explicit)).

i have made some progress after reading the Animation.animatePhysics docs, which says that “An animated platform can apply velocity and friction to rigid bodies sitting on top of it. In order to use this, animatePhysics must be enabled and animated object must be a kinematic rigid body.”
testing this has yielded positive results: rigidbodies can indeed be carried (rotated, lifted, and translated) by an animated kinematic body, so long as the friction between the two objects is high enough, and the gravity is sufficient to keep the object stuck to the platform as it descends.
this is a good start, however, in my particular case, i am using a custom character controller which never makes direct contact with the surface it is standing on, and thus no “real” friction is ever applied (much like a character controller component, but using a rigidbody at its core).

so i guess my adjusted question is: can i force the object i am standing on to apply its friction to an arbitrary object (the player)? or program the application of friction in a way that mimics the behaviour exhibited by the animated kinematic rigidbody?

Cool, I didn’t know about that! :slight_smile:

Cannot really help with the questions but makes me wonder, why doesn’t your character controller make contact with the surface it is on?
Does it work with the built-in CharacterController? If so, you should try and make your character controller work the same way.

i was originally using the CharacterController component but i needed to be able to rotate my character and that component doesn’t support rotation (thanks Nvidia!), so i switched to a custom rigidbody controller which, in order to support behaviours like climbing stairs and standing on steep slopes, uses casts (a spherecast, a raycast, and a rigidbody sweep) to determine what it is standing on and pushes the rigidbody up (like a big spring) based on how close it is to the ground. it’s a cute system but it creates some peculiar problems like this one.

i’m going to try to fake contact friction by using the GetPointVelocity function on whatever the character is standing on and applying it to my character as a force (not sure if a particular forcemode is the correct one but we’ll see).

Unity has recently bought the Kinematic Character Controller and hired the dev, or was it the other way around? :slight_smile:

Anyway, you find them on the store for free now and they are the best character controllers you can get, a version of this also supports DOTS/ECS. One is called Rival, can‘t remember the other one. If you don‘t mind switching tech, but i think it will be worth it.

yeah i’ve used the kinematic controller before, but for some reason (i don’t remember anymore) it wasn’t what i wanted, but i might look into it again if things have changed since i last tried it.

this very nearly works but not quite. i think i’m going to open a new question seeing as the original has been answered with the kinematic MovePosition documentation.