game loop

Started by
6 comments, last by knife 14 years, 1 month ago
i just started and trying to make ping pong (2d) using allegro, i have just wrote movement function for the ball and called it until escape key is pressed. my code is badly written because it take some time to exit as it remains in the loop for drawing. void ball::movement() { point temp = getposition();//stores current position of ball while(temp.x < 620 && right)//just movement along x axis { temp.x++; clear_to_color(screen, makecol(0, 0, 0));//clearing screen textprintf(screen, font, temp.x, temp.y, makecol(170, 185, 255),"%dx%d", SCREEN_W, SCREEN_H);//printing dummy meg if(temp.x == 620) { right = false;//right is a flag (bool type) left = true;//left is a flag (bool type) } } while(temp.x > 20 && left) { temp.x--; //putpixel(screen, temp.x, temp.y, color); clear_to_color(screen, makecol(0, 0, 0)); textprintf(screen, font, temp.x, temp.y, makecol(170, 185, 255),"%dx%d", SCREEN_W, SCREEN_H); if(temp.x == 20) { right = true; left = false; } } setposition(temp); } http://pastebin.com/Eij1a0rn here is where i am calling it from main while(!key[KEY_ESC]) { obj1.movement(); } any suggestion how to write my game loop.
Advertisement
Your problem is (partly) that you aren't seperating the logic of your program.

You have a function called 'ball::movement()', so what does it do? Well, it draws the ball... See how that doesn't make sense? A function that moves the ball, shouldn't draw the ball, and a function that draws the ball, shouldn't move it.

Your game loop should do these things: 1) get the player input, 2) update the objects based off time, and 3) draw the objects. (Other programs, depending on their goals, might do other things as well, like read packets sent over the net)

You ought to seperate different aspects of your program from each other.

My typical game loops look like this:
while(!quit){    //Get and respond to player input...        //Update all game objects based off of time... (each object knows how to update itself)        //Draw each game object... (each object knows how to draw itself)}
As established, ball:movement isn't a good function name, but some games DO simplify their game loops to
    while notQuit        thing.update()
or more likely:
    while notQuit        for each thing in things            thing.update()


The idea of having update move, draw, and do everything on its own doesn't make sense to me. I separate these things into smaller functions that get run in batches, myself. Besides that, it's a design that doesn't work eventually because objects will depend on each other's states and not every object will be updated until the end of the frame. In other words, if you have A and B, when A checks collision with B, it will be looking at B's previous-frame state, but if then B checks collision with A, it's looking at A's present-frame state! See how that may cause problems?

But your question was how to write the game loop! I find your question ambiguous. I do not understand your problem.
Regardless of whether you run your logic directly in the main() function, or in a function called by main, you are still seperating the different parts of the logic from each other, and not trying to do them it all in one function, which was the point I was trying to make. [smile]

I see your point about A and B checking different frames of the collision - I hadn't thought of that, and indeed that might cause problems for the OP (although for pong, I doubt it'd be much of an issue). Luckily, my entities don't know about each other anyway, so can't check each other's state. At the state my game is currently, they don't interact at all, but the plan is to have a single class that controls their interaction with each other at a higher level - and naturally, it wouldn't do so in the middle of the entities updating - it'd either do so before or after they all update (most likely before).
Quote:Original post by Splinter of Chaos
As established, ball:movement isn't a good function name, but some games DO simplify their game loops to
    while notQuit        thing.update()
or more likely:
    while notQuit        for each thing in things            thing.update()


The idea of having update move, draw, and do everything on its own doesn't make sense to me. I separate these things into smaller functions that get run in batches, myself. Besides that, it's a design that doesn't work eventually because objects will depend on each other's states and not every object will be updated until the end of the frame. In other words, if you have A and B, when A checks collision with B, it will be looking at B's previous-frame state, but if then B checks collision with A, it's looking at A's present-frame state! See how that may cause problems?

But your question was how to write the game loop! I find your question ambiguous. I do not understand your problem.


I wrote two while loops before, which was causing my cpu cycles spent in there and when i pressed ESC sometime it exits or sometime not because cpu was busy in that while iteration. Now i have separated movement function using if structures (which actually updates ball's new position values) and other is draw function which reads those updated values and prints to the screen and is independent.

you can check it here now http://pastebin.com/Cn2VEskX
I agree that separating them is a very good idea, but simple games do not need it. OP could always implement a high-level game engine using this article as a guide, but it's likely unnecessary.

Even for a pong clone, if the ball updates its position and checks for collisions with the paddles before they are updated, the collision will be recognized a frame late, if it doesn't stop intersecting the paddle next frame. However, an easy fix to this is to make sure the paddles are updated before the ball. Therefore, for a pong clone, having each object update() without separating the procedure into simpler steps is not problematic.

So, while it makes logical sense to separate the functions, it's not needed, and the OP can fallow our advice, but doesn't need to.

EDIT: OP ninja'd me, so...

Your problem is that you're telling your computer to run these functions as fast as possible. Your CPU maxes out because you put no limit on this. I'm not sure what the best way to solve that is, nor do i know a tutorial that's a good reference for this, so i'll just keep silent.
When you type 'while(!key[KEY_ESC])', 'key[KEY_ESC]' only checks if the escape key is currently pressed. This means, if the game is busy moving or drawing or whatever, and you hit the escape key, but let go of it before the program loops and reaches 'while(!key[KEY_ESC])' again, then by the time it does reach it, the key will no longer be held down, and the game won't shut down.

It's not checking whether the escape key was pressed, it only checks if it is currently pressed. So, instead, we need to check if it was ever pressed during the game (not just currently). To do this, we use an event queue, where we recieve each event one by one, in order. I'm not too familiar with Allegro, but looking at the documentation, we can do it like this: (Note: Not having allegro on my computer, I can't test this)

void HandleEvents(){	//Keep looping while events are in the event queue.	while(keypressed())	{		//Get the event from the event queue		int keyEvent = readkey();				int scancode = 0;		//Get the key from that event		scancode = (keyEvent >> 8);				//Handle that key press.		switch(scancode)		{			case KEY_SPACE:			{				//Spacebar was pressed!			} break;			case KEY_ESC:			{				//Escape was pressed!			} break;			//Other key presses.			default: break; //Do nothing.		}			}	}

(Since 'readkey()' calls 'pollkeyboard()' internally, if you are calling 'pollkeyboard()' anywhere in your main loop, you can now remove it)

So your main loop could look like this: (Or however else you want to lay out your main() function! Just so long as you exit when 'quit' (or a similar variable) is true)
while(!quit){	HandleEvents();		//update based on time...		//draw...}

And in the 'HandleEvents()' function, you could make 'KEY_ESC' set 'quit' to 'true'.

case KEY_ESC:{	//Escape was pressed!	quit = true;} break;


Allegro also has some forums where you might be able to find people more familiar with the API: Allegro forums

Here's a tutorial that might help you: Making pong in Allegro

Also, since you'll probably want to know this sooner or later:
Faq: How can I make my game run at the same speed on any computer?
Quote:Original post by Servant of the Lord
When you type 'while(!key[KEY_ESC])', 'key[KEY_ESC]' only checks if the escape key is currently pressed. This means, if the game is busy moving or drawing or whatever, and you hit the escape key, but let go of it before the program loops and reaches 'while(!key[KEY_ESC])' again, then by the time it does reach it, the key will no longer be held down, and the game won't shut down.

It's not checking whether the escape key was pressed, it only checks if it is currently pressed. So, instead, we need to check if it was ever pressed during the game (not just currently). To do this, we use an event queue, where we recieve each event one by one, in order. I'm not too familiar with Allegro, but looking at the documentation, we can do it like this: (Note: Not having allegro on my computer, I can't test this)

*** Source Snippet Removed ***
(Since 'readkey()' calls 'pollkeyboard()' internally, if you are calling 'pollkeyboard()' anywhere in your main loop, you can now remove it)

So your main loop could look like this: (Or however else you want to lay out your main() function! Just so long as you exit when 'quit' (or a similar variable) is true)
*** Source Snippet Removed ***
And in the 'HandleEvents()' function, you could make 'KEY_ESC' set 'quit' to 'true'.

*** Source Snippet Removed ***

Allegro also has some forums where you might be able to find people more familiar with the API: Allegro forums

Here's a tutorial that might help you: Making pong in Allegro

Also, since you'll probably want to know this sooner or later:
Faq: How can I make my game run at the same speed on any computer?


I have followed something similar to your suggestion. Though i have separated both position update function and drawing one, (calling drawing function at last) but this have solved my problem and with reasonable cpu usage. FAQ page was very helpful.

This topic is closed to new replies.

Advertisement