How would you do it?
Albin Engström

I've written many different types of builds for my games, i would like you to describe how you would have done it, as i have no name for the subject i will describe my "builds", and you will probably realize what im talking about:

1. To put everything in main... no functions at all and drawing directly to the screen.
2. To put everything in main. no functions at all and using double buffering.
3. using functions without callbacks(or whatever it's called) with global variables, using either double of triplebuffering.
4. using functions without callbacks with global variables, using a logic loop of 1000/sec with double buffering.
5. using functions without callbacks with global variables, putting the graphic routines in a timer... using triplebuffering with a logic rate of 1000.
6. using functions without callbacks with variables put in global structures, using a timer for stacking a variable used to loop the logic, using triplebuffering.
7. global structures with variables and large functions without callbacks(like a continuation of the code, inline?) and small with callbacks. with a timer recording the delay between two frames in ms and uses the value for the logic loop, and an un looped logic ruotine. using double buffering with vsync or triple buffering.

I've done a lot more but the difference between them and these are so small so i didn't post them. ALL of these was failures, at first i thought number 7 was a little good and it ran so well, but the frames lagged more the more the cpu was used, and it did not look good at all when using draw_trans_sprite for fading(the cpu went 100%). also, i realized that if the cpu could not execute a logic loop in less than a millisecond on normal speed the program would screw up.

Before i struggle with the next one i'd like to listen some advices, because i really need some as you might have realized, the reason i like to have a logic rate of a 1000 is because it's convenient, the collision detection gets much better looking and i don't have to waste as much time as i would have with a logic rate synced with the frame rat. if you have any smart ideas and tricks on how to make an efficient yet good build, please tell me.

Onewing
Quote:

How would you do it?

With classes and style. 8-)

Kikaru

I don't get what you want to attempt. Here is what I do, though most people don't like it.

I put a mix of things in main. Mostly, if it seems too long, or is redundant, or needs arguments, or needs a return value, then it goes in a global function. I always use double buffering, and put all drawing in main. I use timed game loops, with the help of an interrupt handler from Allegro.
Oh, the part most people don't like is that I use all global variables. 8-)

Onewing
Quote:

Oh, the part most people don't like is that I use all global variables.

Using global variables is not a sin, but using all global variables could be a questionable religion in itself.

Arthur Kalliokoski

If a given module (such as main) grows beyond a screenful or two, it's easy to get confused. The little example programs in allegro/examples are pushing it, but they're "self contained" as examples. If your program gets really big, main() should be more like a table of contents, letting you see the big picture, and you'd look at the individual modules for more detail.

Same with globals, since every module can see them, it gets harder to think of unique names for them all in a big program, also they can slow down a program if the access patterns are always causing cache misses. Having static variables in your modules can do the same, but you eliminate the first problem. Locals in functions are on the stack, which is accessed pretty often (especially since a called function pushed the return value) but if you need to access some variable in several modules or they're huge arrays or something then that's out too.

Trezker

I'm very much satisfied with 100 logic updates per second. If collisions require more then I'll improve the handling in those situations but I wont do more frequent handling.

I rather not put anything in main except call the run function of the game.

I also don't want to go into more of my programming style. There's way too much of it.

ReyBrujo

Classes, inheritance and interfaces. Every class is small, doing very little things. I use composite to create bigger classes with smaller ones. And things like that :)

Audric

If you have performance problems, compile your game with profiling options, and analyze what takes time.

Doing more than 100 updates per second is probably wasteful, but there's probably something else as well.

Evert

Lots of functions with as few global variables as possible (I still have a few more than I should though). I do use a fair number of static variables in each source file, which is probably ok given that each of these source files are fairly specialised to a specific task.
Main is fairly minimal and mostly interprets commandline options and calls initialisation functions. When the game is done, it calls shutdown functions.
I use a re-usable game loop based on the one in Allegro's FAQ, with a fixed logic rate of 60Hz (I think, been a long while since I set it up). The screen update code is optionally double buffered, triple buffered or any other method. The game loop rests when no graphics need to be updated and the next logic cycle hasn't started yet (reducing CPU usage to a few percent).

Quote:

it did not look good at all when using draw_trans_sprite for fading(the cpu went 100%).

Make sure you don't use draw_trans_sprite() with video bitmaps, since reading from video bitmaps is slow.

Quote:

also, i realized that if the cpu could not execute a logic loop in less than a millisecond on normal speed the program would screw up.

Limit the number of frames that may be skipped.

Quote:

the reason i like to have a logic rate of a 1000 is because it's convenient,

Do not run your logic at 1000Hz; Allegro's timers can't run at that frequency reliably. Stick to 100Hz if you need an easy number.

Quote:

the collision detection gets much better looking

Collision detection should not depend on your logic rate (I see how it could, but it shouldn't).

Quote:

and i don't have to waste as much time as i would have with a logic rate synced with the frame rat.

What do you mean here?

Albin Engström

"Audric: Doing more than 100 updates per second is probably wasteful / Evert: Stick to 100Hz if you need an easy number." got it, but would you say no to multiply it with 10 and use it with a logic loop? :P.

"Evert: The game loop rests when no graphics need to be updated and the next logic cycle hasn't started yet (reducing CPU usage to a few percent)." Great tip!! gave me a lot of good ideas :).

"Evert: Make sure you don't use draw_trans_sprite() with video bitmaps, since reading from video bitmaps is slow." drawing a video bitmap or to a video bitmap? i'm (was) drawing to a videobitmap.

"Evert: Collision detection should not depend on your logic rate (I see how it could, but it shouldn't)." what should it depend on? i can't see any easy solutions that would satisfy me :(.

"Evert: What do you mean here?" I meant that i don't have to waste as much time on figuring out how to convert everything from 1000ll to 100ll with the same effect.

gnolam

Gah. Use [quotes} like normal people. :P

Quote:

got it, but would you say no to multiply it with 10 and use it with a logic loop? :P

I would. You don't need a 1000 Hz update frequency.

Quote:

drawing a video bitmap or to a video bitmap? i'm (was) drawing to a videobitmap.

Think about it: to simulate transparency, you take the pixels from both the bitmap you're drawing from and the one you're drawing to and blend them together. So if reading from video bitmaps is slow, that means..?

Evert
Quote:

drawing a video bitmap or to a video bitmap?

Check the manual on vram->vram blits; you should only do it if what you're trying tio do can be accelerated in hardware (Allegro's translucent blits can not be).

Quote:

what should it depend on?

Old and new positions of the colliders, maybe the two or three previous positions as well if you need estimates for the velocity and the acceleration.

Albin Engström

don't know how to use quotes ^^, looked in the help file, but i don't want to test it on a "serious" conversation.

"gnolam: Think about it: to simulate transparency, you take the pixels from both the bitmap you're drawing from and the one you're drawing to and blend them together. So if reading from video bitmaps is slow, that means..?"

haha, i guess the answer was that simple, but i'd have to ask, you never know what may happen in this strange world of allegro and c++ if you don't know the truth..

"Old and new positions of the colliders, maybe the two or three previous positions as well if you need estimates for the velocity and the acceleration." sounds good, but i can't help to think that it would be much harder to inplent.

my other questions still remains to answer... and "I would. You don't need a 1000 Hz update frequency." doesn't qualify as an answer :P

thanks!

Evert
Quote:

looked in the help file, but i don't want to test it on a "serious" conversation.

You can edit your posts, you know?

Quote:

i can't help to think that it would be much harder to inplent.

Depends on your implementation, I suppose. Without seeing an implmentation I can't comment on that (you don't have to post code; I don't have time to look at it in detail anyway).

LennyLen
Quote:

You can edit your posts, you know?

Or use the preview feature.

Albin Engström

"You can edit your posts, you know?"
yes i know, i do that all the time :).

"you don't have to post code"
I don't have any code to post anyway :).

gnolam

And so you choose not to better yourself because..?

Michael Jensen
Quote:

I don't have any code to post anyway .

ummm, what?

Have you been programming on paper again?

Albin Engström

"gnolam: And so you choose not to better yourself because..?"
Because i don't know if it's the better thing to do..

"Michael Jensen: Have you been programming on paper again? [thedailywtf.com]"
^^' no, not really,(nice link by the way), what i meant was that i don't have anything to show that would be worth posting, it would be a waste of time. :).

LennyLen
Quote:

Gah. Use [quotes} like normal people.

Just a reminder.

BAF

Use quotes FFS!

Albin Engström

:'(

BAF said:

Use quotes FFS!

HA! in your face..

ImLeftFooted

Go to the mockup page and read the section entitled 'Quotes'. Very nice feature :).

edit: Wow that is the definition of beaten :P

Goalie Ca

If a tree falls down an no one is around does it make a sound?

In other news does foot->kick(ass) or does ass->getKicked(foot)?

I haven't quite figured that one out.

Richard Phipps

Everyone has a different opinion on the correct way to program, and the style you should use. While some methods are going to be better than other, I think personally the most important thing is finishing a project rather than how it is written.

Albin Engström

Richard Phipps: well said.. but even if you finish it, you want it to turn out good right? :P. at least that's what i want.. but then again, if i focus too much on the best way of writing it will never be finished, as you said. and i'm with you on that one, because i've got some personal experiences regarding that :-X.

FMC
1main(){
2 init();
3 run();
4 end();
5}
6 
7init(){
8 //start allegro, load global data, etc...
9 }
10 
11run(){
12 myGameClass Game;
13 
14 Game.prepare(); //load non global data, prepare everything to play
15 
16 while(going){
17 Game.getInput();
18 Game.update();
19 Game.draw();
20 }
21 
22 Game.end();
23 }
24 
25end(){
26 //unload all globals
27 }

This is my basic layout :)

Thomas Harte
Quote:

Everyone has a different opinion on the correct way to program, and the style you should use. While some methods are going to be better than other, I think personally the most important thing is finishing a project rather than how it is written.

I think it would be a bit artificial to separate the concepts of structure and whether or not you finish. I know that isn't what you're doing, but it's worth commenting on all the same. A good structure should have the following goals:

  • maximise the amount of code you can reuse, to increase your probability of one day finishing something

  • and so, push the code specific to this particular game as far away as possible from the code you'll want to reuse or rewrite

Personally I use an event based game framework with an explicitly maintained screen stack. To explain:

1main()
2{
3 get address of main game controller
4 query short name of game from controller
5 use short name to figure out filename of game preferences file
6 load display and sound preferences from preferences file
7 hand FILE * pointer to game controller to read rest of game data
8 setup display and sound based on loaded preferences
9 
10 query address of first game screen from controller, push to stack. Note that the game controller is a C++ class derived from a simple base that can act as a screen and a controller and by default just passes itself - i.e. no need to worry about screens and stacks if just trying something simple
11 
12 while(!time to quit)
13 {
14 if(anything has happened that may affect display, e.g. resized window, switching in or out of full screen mode, gamma change)
15 {
16 act on whatever happened, send message to controller and current screen saying what happened
17 }
18 if(os has requested quit) set flag to quit
19 if(user pressed escape)
20 {
21 if(screen stack has more than one thing on it) post commands to clear stack to command queue;
22 else set flat to quit
23 }
24 
25 send draw request to controller, then current screen
26 vsync, sleeping here if CPU time is spare
27 work out time between now and last frame
28 work out number of logic updates that makes
29 request that number of logic updates from game controller and screen
30 
31 while(stack commands remain in queue)
32 {
33 switch(stack command)
34 {
35 case ascend: remove top item from screen stack, resync stack pointer to new bottom
36 case descend: go one down the screen stack with the stack pointer
37 case swap: remove the screen at the current pointer, move everything after it up one, resync stack pointer if it is now outside of the stack
38 }
39 }
40 }
41 
42 reopen prefs file, resave preferences, pass to game controller to save whatever it wants
43 send exit messages
44 cleanup
45}

As you can probably guess, the individual game screens can post stack control messages which are themselves queued.

It looks "complicated", but it's all very logical and works quite well.

Audric
Thomas Harte said:

(..)push the code specific to this particular game as far away as possible from the code you'll want to reuse or rewrite

Hmm, I can't agree there, because it's not easy to determine what you'll need to reuse, and what you won't ever :(

Personally, I'm still learning. So, some existing pieces of code (written 1 or 6 years ago) evolve from optimized (read: unreadable, case-specific) hacks to more generic ones. Some experiments are dead-ends too: I roll back when what I do was actually a bad idea for the game at hand.
The changes are progressive also, so at any time I can't clearly classify each piece of code into the categories "perfect" or "ugly".

The stack is a nice way of doing things, though.

ImLeftFooted

I like that layout. The only thing I'd change are the names of the stack commands.

Thomas Harte
Quote:

The only thing I'd change are the names of the stack commands.

They're probably not called exactly that (I'm away from my development machine), but ascend and descend are definitely the names I've picked for those two functions. The third one ("swap") isn't as useful as the other two, but tends to be used for stuff like game over. My stack generally starts like this:

  • title screen

Then for play goes:

  • title screen

  • level dispatcher

Every time the level dispatcher gets an entry message it checks for the gameover condition and if it isn't set then it increments the level number pushes to more screens to the stack:

  • title screen

  • level dispatcher

  • level introduction screen

  • actual code for running a level

and does a descend. The level introduction screen does a quick level intro then a swap operation so you're left with:

  • title screen

  • level dispatcher

  • actual code for running a level

The actual level code ascends either when the player completes the level or hits what should be game over.

If the level dispatcher senses game over then it pushes a game over screen to the stack and does a swap.

Each screen is a separate source file, which makes it easy to keep code organised. Very simple ones, like the level intro, only run to a hundred lines or so as they don't really do much more than write something like "entering level 1" on screen and maybe rotate it or whatever.

There's probably some more caveats to my current favourite form that I've forgotten to mention, but I'm sure everybody gets the heavily laboured point by now. In particular I have other bits and pieces throw in for retaining textures and TTF fonts across mode changes, etc, but nothing that fundamentally affects the structure.

Quote:

Hmm, I can't agree there, because it's not easy to determine what you'll need to reuse, and what you won't ever

It is a fuzzy line, but on the other hand there are things that I think you can say you would definitely reuse, such as frame rate compensation, correct CPU sleep, etc.

Trezker

All ways are good except for the bad ones. And in programming, there are lots of bad ways.
You will only reach a good practise through experience and good guidance.
I've been through a lot of bad practise.

BAF
Quote:

HA! in your face..

Quotes, FTW!

Albin Engström

;D and 8-) and :o and :P, thanks guys.. i'm ready to rumble!

Thread #589452. Printed from Allegro.cc