Rigidbody physics for a character

Up until now, I’ve been working with a pseudo-physics setup for my game. First I was using CharacterController for the players and CapsuleColliders for the enemies, but I ended up hitting a number of unbreakable walls using CharacterControllers when dealing with being blocked by moving objects and physics interactions. I ended up rewriting my characters to use CapsuleColliders and basically reverse engineered the CharacterController as best I could because I wanted the super-responsive movement of CharacterControllers. An important part of this involved setting rigidbody.velocity = Vector3.zero every frame to remove any imparted forces and moving the unit using rigidbody.AddForce(vector, ForceMode.VelocityChange) which eliminates any inertia/acceleration which I don’t want.

Now I’m hitting another wall with my set up. There are certain instances where I want an NPC to be able to block the player, but I don’t want the player to be able to push the NPC around. I found that when using ForceMode.VelocityChange, no matter the Mass setting or the friction setting of the NPC, the player can still push him around, albeit very slowly. The NPC can’t just be set to kinematic because he needs to be able to walk around (I COULD set the unit to Kinematic when he’s not walking, but that’s a last resort). This made me go back and rethink my whole setup, so I started experimenting with PhysicMaterials and friction to see if I should go for a more true physics approach. I found that using ForceMode.Acceleration in AddForce in the player’s movement made it so he wouldn’t push the NPC around as easily (but still does by a microscopic amount), but it also made it nearly impossible to come up with a good-feeling character movement setup. I tried a bunch of combinations of different movement vector magnitudes, friction settings on the environment and the units, and damping on the rigidbodies, but I could never get a responsive-feeling character movement without tons of inertia. (Huge move vectors made for responsive, quick acceleration, but even max frictions ended up like ice skating because they couldn’t stop the movement fast enough.) These experiements with physics make me wonder how you achieve a responsive, non-floaty character controller using rigidbodies without resorting to clearing the movement vector every frame.

1 Like

if you look back at the reference on ForceMode, you’ll see that VelocityChange ignores mass…

so, I would imagine that perhaps changing to an Impulse or direct Force mode might work well (a guess)?

You might consider using “constant” forces instead of Add forces, then when your input changes (left, right, none) you simply apply the appropriate constant force. You will probably need to tweek the physics material for your character though and also drag. I would believe that somewhere, depending on your space and design, you’ll find masses appropriate for the player character and NPC to prevent ‘pushing’… etc.

I did try Impulse and it had the same effect as ForceMode. I believe when it says that VelocityChange ignores mass, it means it doesn’t dampen the speed based on the mass of the moving collider. I don’t think it has any effect on other colliders it hits, except that the moving collider would be moving faster possibly with ForceMode if it has much mass.

As for constant forces, I assume you mean using MovePosition instead of AddForce. I was doing this before I went to AddForce because my testing showed MovePosition allowed “quantum tunneling”, even at moderate speeds, whereas AddForce did not. Or do you mean setting the velocity vector directly?

I was thinking constant force (Unity - Scripting API: Component.constantForce) if you wanted to maintain a particular amount versus an additive approach with AddForce, but either way, you will have some drift without a reasonable drag (depending on mass).

I see what you’re saying now regarding the ignores mass, but it ‘should’ allow relatively low amounts to move the ‘character’ around that way and if you were to use a fairly higher mass for the NPC it would prevent the pushing (would need to tweek friction combine, et al.)

I was just testing this a bit on my own controller and while I have a pretty high velocity on my character controller, it doesn’t push the other rigidbodies around… it has taken a lot of ‘play testing’ so far for me to get something that feels real, but yet reacts dynamic to my controls. However, I still have a bit of drift on the player when turning. I figured though this can be tweaked later with dynamic friction.

I do think though, that if you want to be able to change directions quickly you may need to simply set velocity to zero on the controller when a change in direction is detected (perhaps a simple Boolean operation). With constant force then applied, you will get a consistent ‘speed’ change this way (just a thought). This way, you aren’t changing velocity on every frame or fixedupdate… which would be bad I suppose :slight_smile:

Perhaps the barrier breaking affect you have is due to the collision resolver? Would “continuous dynamic” fix the penetration of the collider space?

oh, I just noticed the side effects of MovePosition and can understand why you are getting that barrier problem… well, like it says… it’s just like teleporting :slight_smile:

Oh, I see. I wasn’t aware of that component. You learn something new every day! :slight_smile: But it doesn’t look too useful for my purposes as it essentially does exactly what I’m doing already by adding forces every frame.

I just discovered something… When I was testing immobilizing the NPC yesterday, I set Mass = 10 and friction on his collider to 1, 1, maximum combine yet I was still able to push him around VERY slowly with a mass 1 unit. But what I neglected to do was to enable gravity on the NPC, thereby making friction not take effect. I normally handle gravity myself in the NPC, but I have it so when they are not moving and are grounded, gravity does not apply downforce because I don’t want them slowly sliding down small slopes like they do without that (that’s another issue, I’ll mention at the end of the post). Because he was grounded, my script wasn’t applying gravity. Setting gravity on permanently using the rigidbody.useGravity made it so friction was taken into account and both the “pure physics” rb mass = 1 unit pushing against it and my original unit using ForceVelocity are unable to push it around. So it looks like I may be able to use my zero-inertia ForceVelocity controller afterall (as long as the NPC is not standing on a hill that would pull it down when gravity is on.)

So it seems Friction + gravity is absolutely required if you want an object to be 100% immobile therefore it cannot be free-floating… either that or it must be Kinematic. It makes sense physically, but for gigantic free-floating objects like, say, planets I don’t think the Mass setting goes high enough for that. :slight_smile: Or at least the docs say not to go above 10 anyway…

I tried again and eventually found a fairly responsive combination. For my purposes, friction shouldn’t be the factor determining movement speed because I want the units to be able to move around in the air as well as on the ground without massive speed changes due to friction or the lack thereof. Therefore, drag seems to be the key. A large drag combined with a massive force vector yields what is ALMOST as responsive inertialess movement. Drag = 21.2, Speed = 85 (force multiplier), StaticFriction = 0, FrictionCombine = minimum. However, the major flaw with this setup is now gravity’s effect is extremely small being dampened by all that drag. I suspect this would require manually calculating the gravity in the script and multiply the force vector enough to make it powerful enough to negate the drag.

Not sure whether its really a bad thing or not. Instant acceleration does have negative effects when doing things like stacking objects, and then the one below moves. But I think in a game with more actual physics interaction where say you had characters pushing balls and boxes around it might cause some problems. In my game, physics is really only used for keeping units from walking through each other, certain types of bullets, and of course the obvious movement throughout the environment. Apart from the pushing issue which turned out to be my mistake where friction was ignored, I haven’t found any other issues with nulling out velocity every frame and applying ForceMode every frame (which is essentially directly setting the velocity, which come to think of it may be cheaper to do…).

I did try all the modes but they didn’t help. In addition to switching to AddForce everywhere, one other thing I did end up doing was to up the physics update to 100fps. This was necessary to keep units from slightly “bouncing” back up when landing from a jump. (The collider moves somewhat into the ground before being corrected back up to proper surface level at 50fps.) Its a lot more processing, but I couldn’t find any way around it.

Yeah, but who doesn’t like teleportation? :slight_smile:

Thanks for helping me think this through!

Edit: Oh I mentioned a hill-sliding issue with RB colliders earlier. I posted it in another thread here: http://forum.unity3d.com/threads/35931-rigidbodies-slide-down-terrain?p=1395298&viewfull=1#post1395298 This was a real problem in my game where NPC’s that were just standing around would end up sliding down into water or off cliffs, which is why I implemented gravity myself and had it stop pulling down once the unit was grounded and not moving. But now I see that borks friction…

Having a huge friction to prevent the NPC from being pushed makes it so he can’t really walk around anymore. D’oh. It looks like I’d have to be dynamically changing friction depending on whether the unit is moving or not, in which case I might as well just make him kinematic when he stops moving and be done with it.

Relatively big mass differences (1 vs 10) aren’t enough to prevent pushing the object out of the way. Moderate frictions (0.4) are not enough either to preven the pusher from moving the blocker as long as it keeps pushing up against it continually even with such a big mass difference. Giant frictions make it impossible to move. Kinematic switching seems to be the only thing that makes sense.

not a problem, it’s actually got me thinking through some of my own short-comings for a character controller

you know, something I was thinking about earlier that could help here is to not use a capsule, but to create your own mesh collider… perhaps in a frustrum like shape, add an empty game object that is used to control your simulated ‘gravity’ force vector which always points perpendicular to the frustrums base.

I suppose you could actually do this with the capsule since you do want it to actually be able to move along an incline with necessary force, but not move otherwise. this would require you to create an additional empty game object to use as your ‘translation’ forces, but in reality is an angular moving object (does that make sense?)… and another perhaps to handle gravity.

what I have found best for me, is to separate concerns related to the character controller… using empty game objects for rotational forces, and another for translation… it helped me to focus a bit, needless to say I did not make it very far in complex math :slight_smile:

come to think of it… I think I recall reading something on Gamasutra not that long ago that dealt with this and the solution used was to a perpendicular force to the ground plane (or to it’s normals). I’m not so sure though how that could be done.

[edit]

here was the article:

I know it’s for 2D, but was one of those ‘got me thinking’ articles…

Ahh, interesting idea. I hadn’t thought of that, but I’m actually already doing something similar for my sliding code. I have certain slopes I don’t want the player to climb so when the controller detects one of these slopes I apply a force parallel with the surface to push the character down the slope. I also do something similar when running up/down a hill to prevent skipping. A raycast (or several) determine the angle of the hill and change the character’s movement vector to point down the hill (or up) so the unit doesn’t skip downhill or speed up going down hill (or slow down going uphill) as would normally happen with a direct forward force. Changing gravity to point perpendicularly to the contacting ground polygons when grounded shouldn’t be difficult, though I have found that nothing’s perfectly accurate when dealing with ground detection because you have to consider many points below the unit and make judgement calls how to treat it (that and the fact that there are some bugs in the surface normal detection in Unity). Finding what works good enough through play testing seems to be key.

Not following all of it completely, but I would question whether a mesh collider would be smooth enough for deflection when pushing against a surface, like when a capsule pushes against a not-flat wall or something. I imagine you’d have a lot of issues getting stuck against things and end up having to write your own deflection code (which I did before and it turned out not as good as the PhysX implementation).

this was the thought (basically cutting off the spherical top/bottom)

1396753--72235--$capsule.jpg

and here’s someone showing how the surface normal detection was working with the built in capsule collider and box collider… recommendation was using a custom mesh collider…

[edit]
link: How can i detect the normal of the collider the Character Controller is touching. - Questions & Answers - Unity Discussions

I have not done this myself, but will be definitely looking into it when the time calls for it. I’m only using a simple sphere collider for now (flying game), but when I get to character and ground level animation/collisions… I think this is the way to go.

Interesting idea. Unfortunately, Unity has a 255 polygon limit for convex hulls as mentioned here. Therefore, the best I could do was this to get under 255. Looks a little rough to me but we’ll see…

1397388--72310--$CutCapsule.png

I’ll do a little testing and see how it works. Another thing I worry is that the MeshCollider will likely be a lot slower than a CapsuleCollider. This may be ok for players, but I’m guessing it will be a deal-breaker for enemies. Again, only testing will tell.

I see… I think that explains my surface normal issues as well, which means the only reliable way to do it is with several raycasts, which still ends up being just an approximation.

So far did a little testing and the first things I noticed:

  1. CutCapsule has more “friction” against other objects like backgrounds and other CapsuleColliders. Pushing against things does deflect, but it feels like it wants to stick to things rather than slide off. Probably from the flat tesselated edges. Feels the same with smoothSphereCollisions enabled.

  2. Climbing small objects is obviously more difficult because of the flat bottom. Probably will need some step-up code to pop onto small rises like CharacterController does.

  3. On a slope, as you can see from this pic, the contacting faces are always going to be on the rounded part of the capsule anyway. The result of this is the same as a CapsuleCollider. When gravity is on, even at 100% friction, the cut capsule slides downhill. (This assumes locked rotations as you probably don’t want your character facing the normal of the hill all the time.)

I’m late to the conversation, but I didn’t see any mention of “Late Update.” Have you tried just capturing the position once, then setting the position in every LateUpdate() whenever you want the NPC to “stand his ground”? The cached position can be updated when the NPC chooses to move. This will override any and all adjustments to the transform done in earlier physics calculations.

Thanks for joining in! The more minds the better! :slight_smile:

I tested your idea and it did work. It negated almost all imparted movement when pushing a unit up against the NPC, though you could still detect tiny variations in the position watching the Transform fields in the inspector. Even though the transform numbers changed when the NPC was receiving a force, it wasn’t enough to notice his position move and when the force stopped he would be pushed back to his original position. All of this is imperceptibly small, so its not an issue. (I suspect it may have something to do with the fact that LateUpdate runs at the end of every frame, but not necessarily at the end of every FixedUpdate frame [I’m assuming] so there may be a frame or two where the physics movement gets applied before LateUpdate is able to undo it…)

Anyway, I also tested the kinematic switching I mentioned above, and it showed the NPC to be rock solid – zero changes to the Transform in the inspector when receiving external forces (as expected). I’m not sure how much overhead is involved in switching the isKinematic mode, but I’m going to guess that its less than repositioning the rigidbody every frame in LateUpdate because you only have to switch kinematic mode once when the NPC goes into stand ground mode and once when he goes out.

Regardless, both methods are better than trying to use massive frictions to keep the unit in place, which requires changes to the material’s friction when the unit wants to move anyway.

the only issue I can imagine with switching kinematic is you’ll also need to switch to a manual transmission :smile: when I suppose takes you full circle… if you’re going to make a manual movement system for the character, why not just go with it entirely :frowning:

thanks for taking the time to test the modified capsule… I can see now that it would not make a difference unless the surfaces where in parallel, so creating a system to handle that would be pointless I suppose.

I still think though it would be easier to put in an empty game object that only deals with gravitational force which always points inversely to the surface contact normal. You could implement this on any collider type.

you’ld have to figure out a way to handle multiple contacts though, and if the character is capable of flying too,… hmmm.

I think I would have a switch that would be “if grounded then point inversely to surface contact normal” otherwise point towards my (planet ?) center of mass? I dunno, just thinking out loud now.

I’m coming to the same conclusion as well. The thing is, I don’t see a way around it. Somewhere there’s going to have to be a “manual transmission” switching even if using pure physics because it seems to be simply impossible to make an object 100% immobile against small physics forces without gravity + 100% friction, and even then slopes throw a monkey wrench into that plan. So on the one hand, you have gravity + 100% friction, switching the gravity direction based on the slope, but then you have to remove the friction once the unit wants to move (mode switch). On the other hand, you have the kinematic switching. It just feels simpler to me to switch the kinematic mode rather than switching friction and the gravity vector.

(EDIT: One thing just dawned on me… The sleep velocity could be critical for the sliding and tiny movement stuff… Mine’s at 0.15, which seems high enough that it should stop small creep, unless gravity wakes the rb up. Even at 100 it still slides down. More testing shows that no amount of sleep velocity even with modified min penetration for penalty will stop this creep. The only thing that does is manually calling Sleep on the rb, but then you have to do it only when grounded or you’re going to have problems with falling off ledges and when a unit reaches the peak of his jump, etc. when the move vector is tiny.)

Ultimately, I posted this question in the first place to try to understand using physics for a character controller better, and at this point, all I can gather is that it requires a lot of manual overriding of physics to achieve what could be thought of as a fairly common character controller for a game (FPS, third person, etc). Just the issue of gravity slope sliding alone is big enough that I’d assume a manual workaround is pretty much required in all cases. In which case, my “pseudo physics” setup I’ve been using doesn’t seem all that unorthodox afterall. (I’ve been turning off gravity when grounded to deal with that, but I think directional gravity is better if you’re going to use PhysicMaterial frictions in your game.)

I do like the idea of surface-normal gravity a lot. I’ll have to test if that’s enough to eliminate accidental slope slide, but I think it may be. I can also imagine scenarios where you may get a little jitter or even possibly uphill sliding depending on your surface normal detection system at the points of contact… using raycasts gives a far more accurate normal than the Collider does, but you have the issue of many points of contact, not all of which are going to be on the same polygon on a mesh collider floor. I’ve dealt with this before with my steep slope slide code, but it’s never exact. And yes, switching the gravity direction whether the unit is grounded or not would be required as well.

Oh, and as for using an empty game object, there’s not really any need to. Just raycast from several points in your capsule’s base to (and slightly beyond) the points of contact the collision gives you. Probably directly above the contact points would work the best, as long as you’re only testing against points below the center of the bottom sphere. Of course, this would be different for other collider types, but you’d have to deal with their own contact points and determine how to define a “foot” level individually anyway.

If I were to think how the human body works against gravity on an incline, I could see where we naturally oppose the force by altering our center of mass forward and/or lowering it. I would correlate it to a pendulum like effect which at some point (dependent upon the angle of incline) the correction would no longer have enough affect to prevent the body from sliding downward.

If the body was to remain verticle (vector3.up), the combined force of gravity with its center of mass would essentially cause the body to move down on the incline (which is exactly what we’re experiencing).

so, if we detected a change in the angle between the center of mass and the surface normal… we may be able to find the counter force required keep the RB from sliding regardless of friction.

actually, after thinking a little more… the corrective force may be the inverse of the angle between surface normal and gravity force.

woke up and had to read this: Inclined plane - Wikipedia

I think the answer is in the “Derivation of mechanical advantage for uphill motion”