game programming patterns game loop from the book by robert nystrom

16
Game Programming Patterns Game Loop From the book by Robert Nystrom http://gameprogrammingpatterns.com

Upload: leticia-darke

Post on 14-Dec-2015

220 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Game Programming Patterns Game Loop From the book by Robert Nystrom

Game Programming PatternsGame Loop

From the book byRobert Nystrom

http://gameprogrammingpatterns.com

Page 2: Game Programming Patterns Game Loop From the book by Robert Nystrom

A simple main loop for an interactive program:

while (true) { char* command = readCommand(); // read text from keyboard handleCommand(command); }

Page 3: Game Programming Patterns Game Loop From the book by Robert Nystrom

A modern event-driven program such as your word processor is similar:

while (true) { Event* event = waitForEvent(); dispatchEvent(event); }

Events could be key presses, mouse clicks, system shutdown, window minimization, timer firing, or many other notifications.

Page 4: Game Programming Patterns Game Loop From the book by Robert Nystrom

A game keeps moving even when the user isn’t providing input. This is the first, key part of a real game loop: it processes user input, but doesn’t wait for it.

while (true) { processInput(); // doesn’t wait update(); // advances game simulation one step render(); // draws a frame on the screen}

We want this to run at a fixed number of frames per second, no matter how many objects exist, no matter how complex the physics, and no matter what fast the CPU is.

We don’t want the game to run too fast or too slow.

Page 5: Game Programming Patterns Game Loop From the book by Robert Nystrom

A simple fix: wait. If we want 60 FPS, then we have 16 milliseconds per frame.

while (true) { double start = getCurrentTime(); processInput(); update(); render(); sleep(start + MS_PER_FRAME - getCurrentTime()); }

Page 6: Game Programming Patterns Game Loop From the book by Robert Nystrom

A simple fix: wait. If we want 60 FPS, then we have 16 milliseconds per frame.

while (true) { double start = getCurrentTime(); processInput(); update(); render(); sleep(start + MS_PER_FRAME - getCurrentTime()); }

Sleep() makes sure the game doesn’t run too fast. But it doesn’t help if the game runs too slowly.

Page 7: Game Programming Patterns Game Loop From the book by Robert Nystrom

Let’s try something a bit more sophisticated. The problem we have basically boils down to:

1. Each update advances game time by a certain amount.2. It takes a certain amount of real time to process that.

If step two takes longer than step one, the game slows down.

But if we can advance the game by more than 16ms of game time in a single step, then we can update the game less frequently and still keep up.

Page 8: Game Programming Patterns Game Loop From the book by Robert Nystrom

Choose a time step to advance based on how much real time passed since the last frame.

double lastTime = getCurrentTime(); while (true) { double current = getCurrentTime(); double elapsed = current - lastTime; processInput(); update(elapsed); // here is the magic render(); lastTime = current; }

Say you’ve got a bullet shooting across the screen. With a fixed time step, in each frame, you’ll move it according to its velocity. With a variable time step, you scale that velocity by the elapsed time.

Page 9: Game Programming Patterns Game Loop From the book by Robert Nystrom

Looks good:

• The game plays at a consistent rate on different hardware.• Players with faster machines are rewarded with smoother gameplay.

But, alas, there’s a serious problem lurking ahead: we’ve made the game non-deterministic and unstable.

Consider a two-player networked game, where one computer runs at 100 FPS and one runs at 50 FPS. A bullet travels across each screen for one second, at 100 meters (in game space) per second.

Computer one: 100 meters/second * (100 * .01 seconds) = 100.00000007Computer two: 100 meters/second * (50 * .02 seconds) = 100.00000004

Floating point rounding error!

Also, many physics engines don’t handle changing time steps.

Page 10: Game Programming Patterns Game Loop From the book by Robert Nystrom

Better idea: fixed time steps and flexibility as to when we render:

double previous = getCurrentTime(); double lag = 0.0; while (true) { double current = getCurrentTime(); double elapsed = current - previous; previous = current; lag += elapsed; processInput(); while (lag >= MS_PER_UPDATE) // not MS_PER_FRAME { update(); // our old friend fixed update lag -= MS_PER_UPDATE; } render(); }

Page 11: Game Programming Patterns Game Loop From the book by Robert Nystrom

One issue is left, “residual lag”. Update happens at a fixed interval, but rendering is less frequent than updating, and not as steady. Potentially, motion looks jagged or stuttery.

Conveniently, we actually know exactly how far between update frames we are when we render: it’s stored in lag. We bail out of the update loop when it’s less than the update time step, not when it’s zero. That leftover amount? That’s how far into the next frame we are. When we go to render, we’ll pass that in:

render(lag / MS_PER_UPDATE);

Page 12: Game Programming Patterns Game Loop From the book by Robert Nystrom

Some additional thoughts.

Who owns the game loop – the engine/platform or the game programmer?

Is power consumption important? In particular, with mobile devices you might sacrifice some frame rate and “sleep” between frames.

There are some trade-offs between more complex coding and greater adaptability to a range of CPU speeds.

Page 13: Game Programming Patterns Game Loop From the book by Robert Nystrom

Unity’sMonoEngine:

Page 14: Game Programming Patterns Game Loop From the book by Robert Nystrom

What about SDL?

In Windows, the entry point is WinMain(), not main().

But didn’t you write a main() in your SDL programs??!!

#include <iostream> #include <SDL.h>

int main(int argc, char **argv){ if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl; return 1; } SDL_Quit();

return 0; }

Page 15: Game Programming Patterns Game Loop From the book by Robert Nystrom

From C:\...\SDL\src\main\windows\SDL_windows_main.c

/* This is where execution begins [windowed apps] */int WINAPIWinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw){ char **argv; int argc; char *cmdline;

/* Grab the command line */ TCHAR *text = GetCommandLine(); cmdline = SDL_strdup(text); if (cmdline == NULL) { return OutOfMemory(); }

/* Parse it into argv and argc */ argc = ParseCommandLine(cmdline, NULL); ParseCommandLine(cmdline, argv);

/* Run the main program */ console_main(argc, argv);

SDL_stack_free(argv); SDL_free(cmdline);

return 0;}

Page 16: Game Programming Patterns Game Loop From the book by Robert Nystrom

Also from C:\...\SDL\src\main\windows\SDL_windows_main.c

/* This is where execution begins [console apps] */intconsole_main(int argc, char *argv[]){ int status;

SDL_SetMainReady();

/* Run the application main() code */ status = SDL_main(argc, argv);

/* Exit cleanly, calling atexit() functions */ exit(status);

/* Hush little compiler, don't you cry... */ return 0;}

And in SDL_main.h (which is included by SDL.h)

#define main SDL_main

extern C_LINKAGE int SDL_main(int argc, char *argv[]);