Archived

This topic is now archived and is closed to further replies.

Real Game Programmers

This topic is 5574 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have been programming games for halft a year or so now, and programming for all of my life. But thats not important here. The important thing is that when I start code a game, I always think "this game has to behave EXACTLY the same even if I run it on the slowest possible computer". This gives me enourmous problems that I don''t like, like Collision Response. If the computer is slow as hell, will the outcome be EXACTLY the same if something collides? Then I have to trace the collision to it''s EXACT (pixelwise) point in time. This is a lot of work. Extremely more than just getting the pixelperfecet collision detection to work, which is quite easy. Another problem is the Acceleration/friction one. But this is certainly a skill issue. Ofcourse we are talking about a gameengine that measures milliseconds since last frame, and updates all objects using this value. Now the question is, If I run a state of the art game on an extremely slow computer - will the outcome be EXACTLY the same? How the *insert french word* do they do that with the collision detection, fysics, and everything else for that matter. I actually whish I coded for a gaming console when I get stuck in questions like this. That would actually solve the issue all by itself. Thanks for the help to a gameprogramming newbie. zilch_

Share this post


Link to post
Share on other sites
They don''t run state of the art games on slow PCs... hence system requirements.

But you''ll have to use timers in order to get the same response times from PCs of different speeds.

Share this post


Link to post
Share on other sites
I''m by no means a professional, but i believe you need to pick a target system and code for that, or for something slightly slower, but don''t get crazy thinking your game needs to run on an ibm p/s2. Code for your target audience.

- Free Your Mind -

Share this post


Link to post
Share on other sites
Zyroth,
I''m totally aware of that.

The question was not about how to do that. I wrote...

"Ofcourse we are talking about a gameengine that measures milliseconds since last frame, and updates all objects using this value."

... which meant that I did this. And I assume all other state of the art engines do that too.

The question was whether they actually behave EXACTLY the same if they are running on a 800 mhz computer, or a 1800 mhz computer. If a spaceshit collides with an AI spaceship in decent2 (or something), would the outcome be EXACTLY the same on an 800 mhz computer (assuming it''s hosting the AI too ) that it would on an 1800 mhz computer? I mean that the resulting x,y coordinate after the ship has stopped whould be EXACTLY the same. That means it actually trances back to the exact point of location.

When I think about it, this whould actually be a lot simplier in 3d than in 2d, as you have the triangles colliding, and their corresponding coordinates. But in a 2d game, all you have is pixels representing the ship.

thanks!

zilch_

Share this post


Link to post
Share on other sites
No, I don''t beleive the results would be EXACTLY the same, due to the simple fact that your timer isn''t infinitely accurate (you can only time to within milliseconds, or whatevers, right?). Also, calculations on variables used in deciding things such as collision response etc. aren''t infinitely accurate, you only have a certain number of decimal places. These tiny differences can add up. From a players point of view, someone playing at 10 FPS can never hope to reproduce the same gameplay as someone playing at 100 FPS, because the frequency at with their inputs are read are different (the fast computer has more accurate inputs, producing different outputs). However, with good design and good physics, you can make sure they are VERY NEARLY the same results on most systems. The physics involved can be very complicated, a bit beyond me at the moment, as I discoved the handling in my car physics demo was wildly different on different computers I got the acceleration and braking speeds correct on slow and fast computers, but I still haven''t sorted the steering.

Share this post


Link to post
Share on other sites
Interesting,
I know what you are going through mate

Not in my wildest dreams I would think that the steering whould be harder to fix than the physics though.

And ofcourse,
the input sampling would differ,
but assuming the game is input-less, and the object start with an initial velocity and direction.

Assuming a difference in 10 fps and 100 fps, it would still be possible to make it 100% accurate. It would be in a gameloop (this is just to show you what i mean) that does all movement, physics and other things in a loop incrementing by 1 millisecond each iteration. Ofcourse no game does this. But this would still make it EXACTLY the same even on ALL computers.

This would catch all collisions at the same spot too.

zilch_

Share this post


Link to post
Share on other sites
zilch_ , I''m not sure I quite understand how to get 100% accuracy.

Take this example, a car crashes into a wall. However, because the game runs in frames, on a fast computer the collision is detected when the car is 0.01 metres through the wall, but on the slow computer, because the time steps between frames are larger, the collision is detected when the car is 0.1 metres through the wall. Now, we could use some funky maths in order to work back and solve the exact moment the car just touched the wall, but because our equation will have different inputs on different computers, inputs which have been ROUNDED, the outcomes surely would be slightly different.

In the example of acceleration verses steering, maybe it isn''t any harder, it''s just harder for me because I understand certain areas of physics better than others. What I do know is that every variable must be in terms of time, such as metres per second for the cars speed. I still haven''t got all the variables for calculating skids in a "per second" format, that''s my problem.

Share this post


Link to post
Share on other sites
Aha, it just clicked into my head what you were meaning. Yes, that would produce exactly the same results on each computer, but the action would unfold at different speeds! Like what sometimes happens when you play old DOS or QBASIC games on your fast computer nowadays. This might look bad, and even if you ignored that, you couldn''t use this for multiplayer games, or games where your score was based on time, or games which required a fast reaction in order to win. However, it may be very good for physics simulations in real world applications, where accuracy is more important.

Share this post


Link to post
Share on other sites
OK!
I have to explain what I mean, as what you describe is the (my, and probably many others) initial problem.

What you say, about the car crashing, assumes, basically, that the collision detection is run once for each frame, therefore not actually exactly at the same point in time (Realtive to the start of the application).

However, what I say, is that if your gameloop does everything that is inside a basic gameengine (movement, psysics AND collision detection) once for each millisecond; the outcome would be the same.

Ofcourse, there will still be different amount of milliseconds passed since last fram on different computers, but if the gameloop is changed in this way, the outcome is always the same.

This is however not practical in reality. But it is possible.

What I mean in more detail, is instead of having:

gameloop {
ms = millisecondsSinceLastFrame();
updateAllObjects(ms);
CheckAndHandleCollision();
// Whatever you want
render();
}

you have:

gameloop {
ms = millisecondsSinceLastFrame();
for ( each millisecond ) {
updateAllObjects(1); // one millisecond
CheckAndHandleCollision();
// Whatever you want
}
render();
}

That WOULD solve the problem. In an INappropriate manner however.

zilch_



[edited by - zilch_ on September 9, 2002 9:37:28 PM]

Share this post


Link to post
Share on other sites
If results are not 100% accurately reproducible on different framerates, how on earth could replay functionality work, if movement is not sampled, but instead input (which according to game programming gems is the way to go) ?

They must be?

zilch_

Share this post


Link to post
Share on other sites
I see what you mean now, I thought you meant this:

gameloop {
DontBotherMeasuringMilliseconds();
updateAllObjectsIrrespectiveToTime(1);
CheckAndHandleCollision();
// Whatever you want
render();
}

Which would always produce the same results, but appear to run at different speeds. The reason that your suggestion does not work perfectly is in this part:

quote:

ms = millisecondsSinceLastFrame();



because what if 4.5 milliseconds (or any other non-integer number) have passed? Then you cannot do this:

quote:

for ( each millisecond ) {}



Do you see what I am getting at? Your function to measure time passed can never be perfectly accurate.

Share this post


Link to post
Share on other sites
Replays usually work in 2 different ways. The problem is similar to networked games.

A bad way, which I think is used in the original Grand Theft Auto, and in Driver 1 and 2 for Playsation (not sure about the PC version), is to simply record all the inputs. Then play the game again, except take your inputs from the saved file instead of the keyboard etc. The problem is that one mistake, for example, 1 keypress is omitted, and the whole reply messes up. This actually happens on my copies of these games!

A better way to do replays is like this (excuse VB code, I think in VB, I still find C++ hard):


Sub GameLoop()
Do
UpdateObjects
Render
RecordObjectPositionsAndCurrentTime
Loop Until GameOver
End Sub

Sub ReplayLoop
Do
GetCurrentTime
FindRecordWhereTheTimeMatchesMostClosely
UpdateObjectsFromThisRecord
Render
Loop Until ReplayOver
End Sub


This would LOOK very similar in the replay to the actual game. And in replays, that's all that matters!

[edited by - bazee on September 9, 2002 9:57:48 PM]

Share this post


Link to post
Share on other sites
Thanks for your involvement!

Yes, I see where you''re getting at.

First of all, it wouldn''t return 4.5. The last .5 would stay in the "buffer" and be return at next call. Lets take SDL_GetTicks() as and example, which return milliseconds since the start of the application (some might argue this is a bad example since it is very unaccurate, but take it as an example). It would return SOMEVALUE+4. HOWEVER, it might be that it SHOULD be SOMEVALUE+4.5, BUT, I think this is irrelevant since this would be taken care of the next frame instead. The user wont notice any difference if the gameengine works with milliseconds OR nanoseconds.

I''m talking about the state of the game engine when it has WORKED at x milliseconds. It doesnt matter if the gameengine measures seconds or millisecond.

You must mean that when a user stopps the game at 41.12412 milliseconds according to his clock, he wants the scene to look the same on all game. Then you are right, and we are talking about different things. Or you must mean that some time is always discarded, if you measure the time since last frame. I don''t know if this is true. Then you might be right.

Thanks for the discussion, I''m getting smarter every minute

zilch_

Share this post


Link to post
Share on other sites
No, I really mean that the game outcomes could be different. Here''s a classic example. You''re playing your favourite shooting game. You take a shot at an enemy. The enemy begins to dive out of the way. On the fast computer, the bullet only just misses the enemy. In fact the shot was so close, that if the enemy was 0.5 milliseconds slower, he would have died. Now on your slow computer - the enemy really does die! The whole outcome of the game could be different, just due to some small inaccuracies in timing.

Share this post


Link to post
Share on other sites
Look for frame-rate independant movement in the archive (when it''s up again) or on Google. It is possible (and desirable) to have exactly the same outcome on different machines.

Cédric

Share this post


Link to post
Share on other sites
Yes, you''re right.

Floating point values accumulated over time could be different depending on how often they are calculated, because, just like you say, they don''t have infinite precission.

This problem is still solved by using the one-millisecond-at-a-time gameloop. Or you still think this is wrong?

Thanks

zilch_









Share this post


Link to post
Share on other sites
cedricl,
the frame-rate-independant movement artickles is not dealing with the collision- and physics problems related to it, when I last read through them. That''s what I need help with I think.

zilch_

Share this post


Link to post
Share on other sites
I'm no expert, but I still stick by my original opinion. I may be wrong. I know what frame rate independant movement is, and I agree it works 99.99% of the time you play a game that uses it.

Here's another example. One computer runs at 2 FPS and one computer runs at 3 FPS (these numbers aren't realistic, just easy to work with as an example). Lets say you are 1 metre away from a cliff edge, and you decide to walk foward at a speed of 1 metre per second for exactly 1 second, and then stop. Using frame rate independant movement, at 2 FPS lets see what happens...

0 + (1/2) = 0.5
0.5 + (1/2) = 1.0

Oh dear you fell off the cliff edge!

Now, at 3 FPS what happens?

0 + (1/3) = 0.3333333
0.3333333 + (1/3) = 0.6666666
0.6666666 + (1/3) = 0.9999999

You have not fallen off the cliff!

There has been a different outcome, even though we are using frame rate independant physics, due to a difference in FPS. And it's just down to simple rounding errors.

[edited by - bazee on September 9, 2002 10:57:40 PM]

[edited by - bazee on September 9, 2002 10:59:11 PM]

Share this post


Link to post
Share on other sites
hate to burst your bubble, but


#include <iostream>
#include <stdlib.h>
#include <conio.h>

using namespace std;

int main(){
float x = 0;
x += 1.0f/3.0f;
cout << x << "\t";

x += 1.0f/3.0f;
cout << x << "\t";

x += 1.0f/3.0f;
cout << x << "\t";

system("pause");
return 0;
}


the output of this is:
0.333333 0.666667 1

So apparently, either the computer''s smarter than that, or GCC is.

Anyway, I''m guessing you could probably track the collision back in time to when it occurred after you recognize that it *has* happened. Use the old-fashioned way you learned in physics. Something like x = v*t

I haven''t worked it out in my head, but I imagine there''s not really any reason to have collision behavior to be framerate dependent. I''m not sure about the other things you guys have been talking about.

Share this post


Link to post
Share on other sites
I''m sure there are other examples that WOULD have the values accumulate to something that is not _perfect_. I still think the example shows what one of the problems are.

Now the difference was so small that the computer still considered it to be 1.

I''d like to know how you''d write the update method of an object that takes milliseconds passed sice last frame, and calculates it''s new position and velocity counting for it''s current velocity, it''s current acceleration, and the surface''s current friction.

Please?

Object::update(int elapsedTime);

float velocity;
float acceleration;
float friction;

zilch_

Share this post


Link to post
Share on other sites
Just to make sure what you're talking about:

If you use time samples,

ms = msSinceLastFrame()
for_each(ms)
UpdateObjects();
DrawObjects();

then the rounding errors will of course be the same on all computers, because you're always working with the same step size.

There's the typical frontal car-collide problem: If there are two cars, exactly 10 meters appart, driving towards each other, the collision point will vary depending on which object will be moved first, and which the time scale:


5 meters 5 meters
-----------> <-----------

0 ms _*>__________ _________<*_

1 ms _________*>__ _________<*_ (update object a)
_________*>__ __<*________ (update object b)

2 ms _____________ _*><*_______ (update object a)


If you you ran this on a fast computer with delta time calculations (position += velocity * deltatime), the cars would be moved in small steps and collide near the center

For a slow computer, each car would move larger steps per frame and the collision could occur somewhere else because car A was moved and ran into car B before car B could perform its movement/collision detection.


Solutions are (have been mentioned already):
- TimeFrame model. (for_each(ms) { Update(); })
You *will* have errors, but they will be the same on all computers. Rounding errors also aren't a problem since they will be the same on all computers. Afaik, Quake uses this model.

- DeltaTime model. (position += velocity * deltatime)
You have to carefully trace back each detected collision's point-of-impact. Floating-point numbers become a real problem, so fixed-point is often used. Afaik, Aliens vs Predator (1) uses this model.

- Frame-by-frame (position += 1)
Good for consoles and other fixed-hardware applications.


-Markus-


[edited by - Cygon on September 10, 2002 6:48:51 AM]

Share this post


Link to post
Share on other sites
I''m sure that framerate-independant movement can fix your problems. The idea is to always run the physics loop for the same time step. So let''s say your time step is 0.02 seconds. If the time between your last drawn frame and the next is, say 0.07 seconds, you would run the physics three times for 0.02 seconds, without drawing anything between the calls.

You should also ''accumulate'' the remaining time (0.07 - 3 * 0.02 = 0.01), so if at the next frame, the time difference is again 0.07, you would call the physics 4 times ((0.07 + 0.01) / 4)

Cédric

Share this post


Link to post
Share on other sites