Page 1 of 1

Moving while characterController is floating

Posted: Sun Sep 30, 2012 1:05 am
by chebob69
First of all, I just wanted to double check the physics here (been a while since I did any). If my character is at the peak of a jump (so no vertical movement), the required impulse to counteract the gravitational force would be calculated as (9.81*mass)/60. That seems to give roughly the right effect but I just wanted to sure. (Is this dependant on the game running at 60fps?)

Secondly, while my character is floating in the air, what's the best way to apply horizontal movement (with the directional keys being used to move the character normally)? Have impulses applied while the character is floating or alter the amount the characterController responds to the direction keys whilst jumping (and can you remind me where that is found in SphereCharacterController?

Thanks

Re: Moving while characterController is floating

Posted: Sun Sep 30, 2012 3:01 am
by Norbo
If my character is at the peak of a jump (so no vertical movement), the required impulse to counteract the gravitational force would be calculated as (9.81*mass)/60. That seems to give roughly the right effect but I just wanted to sure. (Is this dependant on the game running at 60fps?)
The per-time step impulse applied by gravity is always gravitationalAcceleration * entityMass * timeStepDuration. To counteract it, apply an impulse of -gravitationalAcceleration * entityMass * timeStepDuration every time step. Note that 'time steps' are conceptually distinct from game updates. If Space.Update(dt) is used (the parameter being the elapsed time to try and simulate), the engine will take as many time steps of length Space.TimeStepSettings.TimeStepDuration as necessary to approach the accumulated time. Calling Space.Update() without a parameter performs a single time step.
Secondly, while my character is floating in the air, what's the best way to apply horizontal movement (with the directional keys being used to move the character normally)? Have impulses applied while the character is floating or alter the amount the characterController responds to the direction keys whilst jumping (and can you remind me where that is found in SphereCharacterController?
Change the characterController.HorizontalMotionConstraint.AirSpeed to the desired maximum speed, and then set the characterController.HorizontalMotionConstraint.MaximumAirForce to the desired horizontal force. If they are set to match the non-air Speed and MaximumForce properties, the character will feel just as responsive in the air as it does on the ground. If you increase the air responsiveness that much you may also want to increase the 'sliding' responsiveness too. (The 'sliding' property variants apply when the character has support, but not traction.)

Re: Moving while characterController is floating

Posted: Sun Sep 30, 2012 1:25 pm
by chebob69
Cool, works quite nicely. The only problem now being that while the movement is desirable while character if floating (it's for a jetpack in the game), it's a bit too much for the regular jump. Is there a good way of changing the value programmatically? I assume I could just add a method to the SphereCharacterController that handles it? (since the horizontal motion constraint is instantiated there)
Norbo wrote:The per-time step impulse applied by gravity is always gravitationalAcceleration * entityMass * timeStepDuration. To counteract it, apply an impulse of -gravitationalAcceleration * entityMass * timeStepDuration every time step. Note that 'time steps' are conceptually distinct from game updates. If Space.Update(dt) is used (the parameter being the elapsed time to try and simulate), the engine will take as many time steps of length Space.TimeStepSettings.TimeStepDuration as necessary to approach the accumulated time. Calling Space.Update() without a parameter performs a single time step.
Trying to figure out what all this means. Are you saying calling Space.Update() without a parameter will have the physics update at the same rate as the game? If so, I assume that would lead to the problem that the impulse required would change if, for example, a slower computer can only run the game at 50fps. All I need to know is how to keep the physics constant in such circumstances? Space.Update(1/60) ??

Re: Moving while characterController is floating

Posted: Sun Sep 30, 2012 5:24 pm
by Norbo
Is there a good way of changing the value programmatically? I assume I could just add a method to the SphereCharacterController that handles it? (since the horizontal motion constraint is instantiated there)
The AirSpeed and MaximumAirForce are publicly accessible properties can be changed whenever you want. You could set them to high numbers while jetpacking, and low numbers otherwise.
Are you saying calling Space.Update() without a parameter will have the physics update at the same rate as the game?
Not exactly. Space.Update() without parameters performs a single time step of length Space.TimeStepSettings.TimeStepDuration. If every single one of your game updates happens to be separated by exactly Space.TimeStepSettings.TimeStepDuration and calls Space.Update(), then the physics could be said to be running at the same rate.

So, if your game has IsFixedTimeStep set to true, then calling Space.Update() once per update would work. If the game just happened to always update at the same rate (e.g. due to vsync framerate coupling and guaranteed running environment conditions), it would work.

If you aren't using IsFixedTimeStep and the game can't update fast enough to reach the update rate goal but you're still using Space.Update(), the physics simulation will progress at a slower rate reflecting the slower update rate. Even if the time between updates varies, the time simulated by a Space.Update() call will not. It will always take a step of Space.TimeStepSettings.TimeStepDuration (which should not be changed on the fly to match unfixed game update time; that would introduce instability).
If so, I assume that would lead to the problem that the impulse required would change if, for example, a slower computer can only run the game at 50fps.
When using Space.Update() without a parameter, the only problem that will occur with a slower update rate is that the simulation progression will slow down. On the other hand, if you're using Space.Update(dt) with a parameter, it will try to perform as many time steps as necessary to keep up with the passed in accumulated time.

If physics are the bottleneck keeping the game from getting to the update goal, these internal time steps triggered by using Space.Update(dt) can cause a vicious cycle. It will try to perform 2 updates, but those two updates will take so long to compute that the next frame will need to compute 3 updates, and so on. There's a Space.TimeStepSettings.MaximumTimeStepsPerFrame property which defaults to 3 to prevent this from just progressively destroying performance, but it's not a complete solution- if it can't simulate the requested time, the simulation progression will slow down relative to real time expectations.
All I need to know is how to keep the physics constant in such circumstances? Space.Update(1/60) ??
If your game has IsFixedTimeStep set to true or otherwise guarantees that a game update is responsible for simulating a fixed chunk of time, use Space.Update().

If your game does not know how long a game update will last but you want a sufficient number of time steps to be used anyway, use Space.Update(dt) where dt is the span of time you wish to simulate. It can't just be a fixed number like '1/60' or else it won't match the update progression of your game. You can get the appropriate elapsed time from the update's GameTime structure in XNA (be sure to use seconds, not milliseconds!).

If your game cannot match the desired update rate due to performance limitations, you're stuck. You can either lag horribly in a vicious loop, or slow down the simulation, or optimize.

A side note: When using Space.Update(dt), there will be tiny fractions of a time step's worth of time left over. Those chunks weren't big enough to warrant a simulated time step yet, so they're kept around for the next frame to accumulate. However, because there are a varying number of time steps being performed per frame, you may end up with slightly jittery graphics if you directly access the position and orientation of objects. You can address this by using interpolated states as explained in demo and section 2.B of the updating asynchronously documentation. (Interpolated states don't require asynchronous updates to be useful; asynchronous updates are just a common use case.)