Skip to main content
GameDev.net gamedev.net
🔒 Locked

Physics and Timing problem

Started by skazzaks Mar 12, 2007 at 10:58 AM 4 replies 600+ views
Original Post
skazzaks
skazzaks
Hello all! I am trying to build a simple 2D side scrolling game using C# and the (semi) new Microsoft XNA framework, but have run into a problem. Firstly, I have an image on the screen that I want to "jump." When it jumps, I assign an upward acceleration for the instant, and then in the next frame, I assign no upward acceleration, but just let gravity kick in, and he correctly begins to go upward more slowly, and then downward toward the earth. For the most part, the framerate is constant, so everything is smooth. When the framerate is not constant, however, I experience a problem. Across the board, I multiply all "time oriented values" (acceleration, velocity) by the amount of time it took to display this frame, so that framerate is not an issue. For example, if a sprite is moving to the right at 4pixels/frame and it takes 3 frames to display, the game will auto-correct itself and go 12 pixels. If it takes 1 frame of time, it will only move 4. I understand this to be a common approach. This system breaks down when I assign the instantaneous acceleration to the "jump", however. Since multiplying by time will not give the correct predictive result (the system doesn't know that the acceleration should stop for the next frame..how could it?). So what ends up happening is that if the game lags right when I am jumping, my character jumps too high (it assumes I want to apply that acceleration for multiple frames). Is there anything I can do about this? Thanks!
haphazardlynamed
haphazardlynamed
Rather than plug the (highly variable) time value into your physics equations.
On each update, check how much time has passed since the last update. Then divide by say...16ms. Then have a small physics loop that steps through your position equations multiple times as needed, each one using a time of only 16ms...
(hence, the jump acceleration would only apply for that first 16ms phsyics step. not All of them within the frame update)

Having a Fixed timestep (time interval) should make the physics calculations consistent...




Once that works, you'll probably notice a slight jarring motion on occasion due to the redraw rate not being a perfect interval of the physics rate...
to solve that issue, we calculate the physics one step ahead of the frame time, then interpolate between past and future physics states to match the frame timing...
Gagyi
Gagyi
This is why most things use fixed timestep. No time-multiplication needed (thus, easier implementation).

Fixing the timestep:
(the _ things are "space")

while nexttimestep_position+=velocity;
_velocity+=acceleration;
_if jump then velocity+=jumpforce;
_nexttimestep+=10;
end loop

Yup, this is easy. And 100FPS, wich is pretty fast. If you use this, you wont have problems when you try to make some multiplayer games.
[EDIT: haphazardlynamed, you were only faster, because I had to go to pee when i was wrting :P)
-----------------------------------"After you finish the first 90% of a project, you have to finish the other 90%." - Michael Abrashstickman.hu <=my game (please tell me your opinion about it)
skazzaks
skazzaks
Thanks for the quick replies.

I wanted to support variable frame rates in case I made the game networked...I figured if different machines couldn't support the same framerate I would need to calculate the difference.

Also, I like your idea about calling the physics logic multiple times, but I can't think of how to implement it given my current configuration. Every time the game loop is called, I first check for input and then run the physics logic. If I hit the physics section and then detect that I need to run the logic multiple times because of a slowdown, I have no way of updating the accelerations of the player, etc.

For example:
I hit up and set the player's upward acceleration. I get to the physics logic and see that it took 64ms, so I will need to run it 4 times. The first time it sets the acceleration correctly. The second time, how does it know that it should be zero? There hasn't been another check for input, so it still thinks there should be upward acceleration.

Again, thanks for your help.
haphazardlynamed
haphazardlynamed
Quote:
Original post by skazzaks
I get to the physics logic and see that it took 64ms, so I will need to run it 4 times. The first time it sets the acceleration correctly. The second time, how does it know that it should be zero? There hasn't been another check for input, so it still thinks there should be upward acceleration.


I use a messagequeue to handle inputs.(using SDL, but you should be able to do a similar strategy ifnot)
Basically any user inputs at Any Time get saved to a list, thus anything that the user did between now and the last update is available for me to retrieve when I do the physics.(retrieveing them removes them from the list, so each action applies once)

This kind of thing can vary depending on the type of action of course, for example I've got a spaceship game, and the rocket engine remains On for succesive physics updates so long as the user has not let go of the key.

Whereas for for your jumping example, you could have a check that says the character cannot jump if his feet are not on the ground, thus the first physloop would get him moving up, and even if he has not let go of the jump key (or if you have not updated the input checks) the second physloop would see he is not on the ground and not apply a jumping acceleration...
Agony
Agony
When you do your physics logic, you'll have to know whether this is a first pass, or a catch-up pass. On a first pass, you'll pay attention to all input like normal. On a catch-up pass, you'll ignore any input that is an instant action, but continue to normally handle any input that is a continuous action. Jumping, for example, is an instant action; holding the jump key down shouldn't change the way you jump. Thrusting in a space-sim, however, would be a continuous action, and should be applied normally overall all the physics sub-steps.

Although you might eventually need to adjust this so that instant actions turn into partially continuous actions, by introducing a cool-down. For example, firing a machine gun is an instant action, in the sense that when you hit the key, it should fire one bullet, and not a "beam of metal". However, holding down the key should produce a different result than just tapping it, and that is because if you hold the key down long enough for another bullet to be fired, it should automatically fire that bullet as well.

One way you might handle this, along with your jump problem, is to use a state to represent your object that performs the action. In all physics steps, try to apply the jump to the object. But don't apply the acceleration directly; instead check the state of the object. If it is jumping, then do nothing. If it is not jumping, apply the acceleration, and set its state to jumping.

If you implement double jumping, then you'll also need to remember the start time of the jump as part of the state. Like before, if the object is not jumping, then apply acceleration, set the state to jumping(1), and record the jump time. If it is already on its first jump, then see if it's been long enough since it started its jump to initiate a double jump. If not, then ignore the input. If so, then apply the new acceleration, change the state to jumping(2), and record the jump time just in case you need it later.

This way, every single physics pass operates exactly the same, but what accelerations get applied all depends on the state of your objects.
"We should have a great fewer disputes in the world if words were taken for what they are, the signs of our ideas nly, and not for things themselves." - John Locke o

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.