Losing gravity

I’m moving some monsters around by applying a velocity to their rigidbody. This has worked out well for a while, but then I introduced slopes.
When my monsters walk off slopes, gravity takes its sweet time to impact them. They do fall, but very very slowly.
The best I can figure is that nearly every update I’m feeding them a manual velocity to have them walk in a specific direction, so I’m overriding the effect of gravity.
But if this is the case, then how do I get gravity to have its natural impact? If I just change the velocity I set to a force that I add then my monsters are going to have momentum and inertia when I just want them to move in a given direction and stop as needed.

But honestly this doesn’t sound right; I could have sworn that in the past I’ve had things still get impacted by gravity and other forces even though I’ve had scripts to move them in specific directions. So I don’t get it; why is gravity just now not working?

How do you expect anybody to answer this without seeing what you actually did in code? ^^

Pretty much. In the frames where you do, you overwrite the effect of gravity. If your monsters still fall slowly, that’s either due to the frames where you do not overwrite the velocity, or due to some other quirk of either your code or Unitys execution order.
It doesnt seem like you want to use physics at all. Currently you run all those physics… just to then ignore and overwrite the result without gaining anything from it. Arent you better off with a character controller then?

In 3D you have two approaches to choose from. Character controller offers perfect control, rigidbody offers perfect physics. The goal is usually somewhere inbetween, but unless you need an actual physics simulation, which is highly unlikely for characters, the actual goal is usually shifted far, far towards the perfect control side of things, plus some smoothing and stuff.

So without having seen your code or anything, if you want to stick with overwriting the velocity… why not just overwrite the part you actually want to change, ie leave the velocity.y what physics believes it should be?

2 Likes

I’ve never used a character controller before, and honestly I forgot it even existed. The last time I looked into that I got the impression that it was adding more overhead than I wanted, like it was trying to be a complete controller package. Reading some of the documentation though, “A CharacterController is not affected by forces and will only move when you call the Move function. It will then carry out the movement but be constrained by collisions.” holy crap why didn’t all the tutorials I started with back in the day use this? This sounds like exactly what I want.

I’ll have to calculate my own gravity manually, but if this means I can have characters not push each other around then it sounds like a more-than acceptable compromise.
I see there is even a “simpleMove” that already works for XZ planar movement and applies gravity.

I’m noticing that some of the tutorials I’m seeing are using the Character controller in tandem with the rigidbody. Maybe that’s the kind of stuff that has been making me thing I didn’t want to use the character controller before; using it in place of rigidbody seems more more desirable.

1 Like

Unity uses this:

https://docs.nvidia.com/gameworks/content/gameworkslibrary/physx/guide/Manual/CharacterControllers.html

I’ve started applying this to my monsters.
It looks like their movement is a little staccato since my quick modification is applying the movement on fixedUpdate instead of Update.
Still, I don’t really like to have something as critical as movement being applied on update, because then if something happens and the game drops a bunch of frames it can f*** over the movement by giving a sudden push. Is there any way to interpolate character controller movement? Or should I just bump up the Fixed Timestep to 60 fps and hope no performance junkies notice.

To clarify why that is: for collisions to work one of the two objects (or both) needs to have a rigidbody component. Rigidbody basically is the physics system. So unless i’m missing something, you will need one too. Since you do not use it for physics other than collisions, you then turn on the ‘isKinematic’ option.
One other reason for far more advanced projects would be ragdolling. If an enemy or the player is killed, in some games you want it to ragdoll and fly away or collapse. This too is achieved by re-enabling an existing rigidbody component, and then some.

Absolutely change that. Only physics belong in the fixed update. The reason being that Unity tries its best to call fixed update on a fixed timestep. Sounds nice, but can cause serious problems if you do not absolutely make sure that fixed update is as lightweight as possible. Now let’s say for simplicity sake that fixed update is called every 10ms in this example. If it takes 1 ms to complete, there is 9 ms for normal Update calls. If you have some heavy workload in your Update method, the game will slow down linearly. Unity will attempt to call fixed update every 10ms, but if an Update for example took 30ms, it would call fixed update several times to catch up the physics calculations.
Now what happens if your fixed update is not lightweight and instead itself contains a heavy workload? Let’s say your fixed update takes 9 ms. That means your update only has 1ms to run until Unity realizes fixed update has to be called again. So assuming that Update call took 10ms, Unity realises a physics cycle needs to be calculated… but that takes another 9ms, so another physics cycle needs to be calculated right away… and another… and another… and so on. The majority of time is suddenly spend on physics. The game will slow down exponentially. Imagine if your physics calculations took a full 10ms. No normal frames could be rendered anymore, ever. Unity is actually kinda smart about this and detects this case and renders a frame here and there… but i hope the example helps to understand why things like inputs, non-physics movement and just general calculations do not belong in fixed update.

I believe you are misunderstanding something. You should multiply all movement that happens with Time.deltaTime, which is basically the amount of seconds since the last frame. That way you have a constant movement per second, whether you have 10 FPS or 1000. It also does not matter if there is a sudden spike in framtime. Keep in mind: states between what you see do not actually exist. There is no “sudden push”, ever. Every single frame you do not apply fluid motion… you literally teleport every object to its new location, be that a small or large change at once. A game is not a fluid world that actually exists. It is a series of states with a visual representation that represent changes to a model in quick succession, to appear as if things actually moved. Unlike reallife, nothing exists inbetween some frame A and some frame B. Those states are literally all there is. That’s why any calculations we apply, even physics, is multiplied with the time that passed between A and B.
Not an expert, but physics are run on a fixed timestep since, among other things, otherwise it can be hard to detect collisions with varying frametimes. And even with that, for high velocities collisions can still be missed, which is why there is a collision detection mode that’s more computational expensive but checks for collisions “between” those two states, but i digress.
Anyways as far as your question is concerned: simply multiply your movement with Time.deltaTime.
https://docs.unity3d.com/ScriptReference/Time-deltaTime.html

No I’m not misunderstanding, I’m speaking from experience.
Many years ago I was working with UDK on a machine that was just a little above the minimum requirements. Sometimes the system would just pause for a little bit and I’d drop a bunch of frames.
The problem is that then all the deltaTime calculations would make a huge push because suddenly deltaTime was a lot bigger. What really bothered me was that this frequently happened while I was jumping (it was a platformer) and I would hang in the air for a fraction of a second and then suddenly hit the ground with extra force as if I was in the air longer, and then I’d take damage from the fall even though it was from a safe height.
My game would randomly hurt the player because my hardware was under-powered.

Computers drop frames, this is just a fact of life. But too frequently small developers don’t see the impact this has on under-powered machines. The fundamental problem with deltatime is that it can cause sudden pushes and suddenly jumps because some other software running int he background had to run some calculations.

I get your point. But something like that should only ever happen due to either a horribly implemented feature, or simply because of exactly the physics problems i wrote about above.
If the hardware hung up for a fraction of a second doing something else, then the game would completely hang up as well. Once it returns to calculating the game, nothing out of the ordinary should happen. Again, the game world does not exist outside of calculations. So if the game literally hangs up and resumes and something out of the ordinary happens, then one of two things would be true that i can think about. One of which being a badly implemented feature. For example, if the fall damage is based on the time spend in the air and not the actual velocity, and this time is not accumulated but checked when leaving and returning to the ground. This would cause the fall to be considered higher than it actually was. In no way is something like this related to deltaTime, it’s simply a badly implemented feature.
The other scenario i can think of is that the game did not hang and instead only the visuals froze. This could, for example, happen due to exactly what i wrote above, ie the physics cycle needing to catch up. Especially on worse computers, since everything takes longer, physics in relation take up more time. However, in Unity as far as i know this should not lead to unexpected behavior, like dying from a small fall, unless coupled with some other problem. The physics would just do its thing. So unless some critical step in the fall damage calculation depended on the part of the game that runs the visual representation, it should not come to this. Of course i cant say anything about how arbitrary game examples may be implemented, or how other engines handle these things.

Either way, deltaTime should not cause such problems. Especially since gravity would still be done by the physics engine, and youd only move on the XZ plane in Update. The only thing that could happen on low-FPS computers is that you check inputs in Update (as you should be) and thus, due to having lower FPS, they may have their input active for longer than they intended. This is however a one-frame difference at best, so unless we talk about hanging up for a bigger part of a second then this is a non-issue. And the only fix for this would be to put inputs into fixed update as well (as you absolutely should not) - all of which simply adds to the problem since now even more time is spend on physics.

It needs to run in update, or you need to perform your own interpolation. It’s not part of the simulation so it in fact, doesn’t require Fixed Update.

The only (small) issue you might encounter is moving colliders will still only move during FixedUpdate, but I doubt this will bother you.

If you want to do it in FixedUpdate, simply apply your own interpolation, and separate the Character Controller from the rendered visuals. The visuals then perform the interpolation. This is what Unity does for rigidbody interpolation.

1 Like

I have a character controller with a plane and some boxes. Collisions seem to work fine.

The “slow falling” is because gravity is not allowed to accumulate, causing it to fall at a constant speed rather than accelerate as it should.

Slowdown IRL is due to air drag and friction. In Unity this is done with the “drag” property on the rigidbody, and applying physics materials with friction on your colliders. They may or may not be enough for your purpose, in all likelihood not though.

I have to make some assumptions since you have not revealed your code. I will assume your enemy movement direction only occurs on the X and Z axis, and you are simply multiplying the movement direction by your desired speed. Then you apply the movement vector to your rigidbody velocity. If this is indeed the case, all you need to do to preserve the effect of gravity, is to cache the rigidbody.velocity.y, and reapply it to your movement vector before applying it to the rigidbody.velocity

float cacheY = rb.velocity.y;
Vector3 movementVect = yourTravelDirection * yourTravelSpeed;
movement.y = cacheY;
rb.velocity = movementVect;

If you step away from manipulating velocity and instead use AddForce, you will have to check the X and Z velocities, to see if they currently exceed your desired max speed, before applying your AddForce.

Vector3 checkSpeed = rb.velocity
checkSpeed.y = 0;
If(checkSpeed.magnitude < yourMaxSpeed){
    rb.AddForce(yourMovementForce);
}

The disadvantage of this method, is the inability to turn on a dime, and dependent on using the Physics system to stop. Any other method to stop will most likely involve manipulating velocity directly anyway, so you might aswell move by manipulating velocity directly at that point.

With either method, the effect of gravity will be preserved, but you still might not move on the slope well if your movement is too fast. I’ve answered this before conceptually, so I’ll link it here first, just in case you encounter this problem.
https://discussions.unity.com/t/781837/4

Slopes - rotate the current movement vector each frame, so gravity is along the slope normal and the velocity is aligned by the slope too.

This fixes bunny hopping, speed issues, sliding, pretty much everything, but it will depend on what you want.