0
\$\begingroup\$

First post here. So I am a newbie to Unity and am willing to create a general character controller script to base my future characters. I understand a character's mechanics are pretty design (UX) dependent and I will need a few varients.


What I want

Momentum-wise accurate physical simulation (as much as game performance allows). Some examples:

  • If a flying canon-ball hits the player, it shall be crashed or flown away (some parameters would let us kill him in code hopefully) in accord with ball's momentum and player's mass.
  • If the player hits a stationary canon-ball the ball most-probably wouldn't move (due to friction), yet if they push enough it gains some torque and rolls-over. Rotational and kinetic energy would need equal energy provided.
  • Multiple player's could act upon a bunch of pieces just for fun.
  • Regular character capabilities such as stair/ladder climbing, walking, etc.

What I have read so far:

  • CharacterController needs to write code for desired physics, and apt when not so interactive characters (e.g. first person shooter) are at hand.
  • Rigidbody is good for non-agent dynamic items (e.g. falling boxes), and is hard to implement for agents (muscle powered humanoids, etc.), though possible.

What I ask

How can I implement such momentum-wise accurate physics (regarding collisions) in Unity engine?

\$\endgroup\$
1
  • \$\begingroup\$ I don't see how implementing accurate physics for CC would be any different than using rigidbody. Compared to re-implementing physics, molding rigidbody into an agent is certainly not hard. \$\endgroup\$ Apr 3, 2021 at 17:37

1 Answer 1

1
\$\begingroup\$

The way I like to solve this is to use a dynamic Rigidbody, and give my character control script a notion of "traction" - the maximum force they can exert against the ground to alter their movement.

When traction is high, we can control the movement very precisely, like using a CharacterContoller. Imagine the character is wearing sturdy cleats with a planted stance so they can resist attempts to push them around.

External influences can still be used to modify this traction where we want to: for instance, we can check the material of the collider under the controller and use it to lower the current traction if, say, we're standing on slippery ice.

Or if the character is hit, we can put them into a stumbling state where they have reduced traction for a period of time, or until they drop below a certain speed, allowing strong hits to send them sliding/flying like a regular dynamic object.

The heart of this is a helper method something like this:

void PushToward(Vector3 targetVelocity, float maxStartingForce, float maxStoppingForce) {

    Vector3 deltaV = targetVelocity - rigidbody.velocity;

    Vector3 force = rigidbody.mass * deltaV / Time.deltaTime;

    // TODO: You may want to remove the component of force perpendicular to the
    // terrain, so that we can only push ourselves parallel to the ground.

    float forceLimit = Vector3.Dot(deltaV, rigidbody.velocity) < 0f ?
                    maxStoppingForce : maxStartingForce;

    force = Vector3.ClampMagnitude(force, forceLimit);

    rigidbody.AddForce(force);
}

Here we pass the velocity our character "wants" to have based on the player's input, but modulate that want according to a limiting force value (you could also parametrize these as accelerations instead of forces, to take the mass out of the equation). That way our control script respects some physical limits of how much "torque" our character's engine has, how much grip they have on the ground, how hard they can push against obstacles/etc. In contrast to a CharacterContoller that will always go exactly to the destination position, stopping only for collisions.

Character control generally feels best if you have a small window of acceleration when starting to move, but a very hard brake when releasing the controls or changing direction. That's why I like to use separate limits for "starting" and "stopping" forces - the latter can be much higher to keep the controls feeling tight and responsive, without making the character look too jerky.

These two force parameters become our avenue for managing our character's traction. When standing on ice, or when the character is in a stumbling/ragdoll state, (which we can trigger based on relative velocity/impulse of a collision inside OnCollisionEnter), we can scale both these force limits down to a small multiple, so the character exerts less and less control over their movement. Maybe even 0 to send them skating like a hockey puck. Then we can bring that multiplier back up to 1 when they're on solid ground or when they regain their footing after a knock back.

This gives us a controllable blend between pure rigid body dynamics-driven behaviour, and the tight control of a character controller, and we can dial the behaviour anywhere along that spectrum as the situation demands.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the informative respond, and underlining that I need a set of knowledge prior to action. I can hopefully try your code and suggestions starting next week, and will edit and mark then. \$\endgroup\$
    – cbugra
    Apr 3, 2021 at 14:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .