I am having problems effectively utilizing Allegro's GUI dialog menu bar. Right now I am working on a simple solitaire card game and I put up a simple menu that has a Start Game item. Clicking on the Start Game menu item runs a callback function that starts up the game code.
The problem is that I don't know any tricks to keep the menu "active" while the game is being played. For example once my game code starts up, the menu no longer draws itself since the callback function I supply hasn't yet returned back to the do_dialog() system (when the game is running). I finally figured out that I could keep the menu drawn on the screen by running the object_message() function with a redraw message, but that doesn't allow the menu to be clicked on still. How can I keep the menu somewhat active and still run the game code? Are there any good tricks to use?
I was thinking it would be possible to monitor the X-Y coords of the mouse in the game code and if they approach the top of the screen (where the menu is) I could active the menu. I am guessing there is any easier way that I haven't figured out yet.
The recommended solution:
1. Your play_game() function just sets a flag and returns immediately.
2. The actual game is a d_game_proc() kind of thing that is part of the menu dialog and checks the value of the above flag to see whether a game is supposed to be played or not.
Or you could use update_dialog() instead of do_dialog(), check the allegro manual for more information, because it's not quite as simple as that.
2. The actual game is a d_game_proc() kind of thing that is part of the menu dialog and checks the value of the above flag to see whether a game is supposed to be played or not.
This is actually a good idea, if you want to have a responsive GUI using Allegro's routines and not have to worry about managing all the other widgets. Just make the MSG_IDLE handler do the logic loop (after checking that it's time to), then return D_REDRAWME. Then set your MSG_DRAW handler to draw and display your game section. You can even make your menus send custom messages to your game dialog to make it change states in real-time. Tracking MSG_CHAR messages should be done in place of keypressed/readkey, and you can use the key[] array like normal. You'd want to return D_WANTFOCUS for MSG_LOSTFOCUS and MSG_WANTFOCUS events.
Just make sure to disable using KEY_ESC to quit the dialog (unless that's what you want). And don't use a d_yield_proc. If you want to rest, do it in your game loop after checking that you don't need to run logic yet.
Of course, you probably don't want to do anything for MSG_START/MSG_END messages. IIRC, there's a problem with MSG_START that it gets called multiple times, so for initialization/cleanup you'd want to do it right before/after do_dialog.
An example of this kind of setup would be:
1 | volatile unsigned int timer; |
2 | void update_timer() |
3 | { |
4 | timer++; |
5 | } |
6 | END_OF_FUNCTION(update_timer); |
7 | |
8 | int d_game_proc(int msg, DIALOG *d, int c) |
9 | { |
10 | switch(msg) |
11 | { |
12 | case MSG_DRAW: |
13 | // Careful. This will be called before the first logic run, |
14 | // so make sure it won't die |
15 | draw_scene(buffer); |
16 | blit(buffer, screen, ...); |
17 | return D_O_K; |
18 | |
19 | case MSG_IDLE: |
20 | if(timer == 0) |
21 | { |
22 | // Ahead of schedule. rest a bit to ease CPU usage |
23 | // (not needed, but nice to do), then return control |
24 | rest(1); |
25 | return D_O_K; |
26 | } |
27 | // Do all waiting logic |
28 | while(timer > 0) { |
29 | do_logic(); |
30 | timer--; |
31 | } |
32 | // Ready to draw |
33 | return D_REDRAWME; |
34 | |
35 | case MSG_CHAR: |
36 | // We got a keypress. 'c' (third parameter) is the same format as |
37 | // returned by readkey() |
38 | if(c>>8 == KEY_ESC) |
39 | return D_CLOSE; |
40 | |
41 | // So other widgets don't get what was intended for us |
42 | return D_USED_CHAR; |
43 | |
44 | case MSG_WANTFOCUS: |
45 | case MSG_LOSTFOCUS: |
46 | // Try to keep focus |
47 | return D_WANTFOCUS; |
48 | } |
49 | } |
50 | |
51 | DIALOG game_dialog[] = { |
52 | // Should be at the top |
53 | { d_game_proc, ... }, |
54 | ... |
55 | }; |
56 | |
57 | int main() |
58 | { |
59 | ... |
60 | |
61 | init_game(); |
62 | timer = 0; |
63 | do_dialog(game_dialog, 0); |
64 | deinit_game(); |
65 | |
66 | return 0; |
67 | } |
Thanks for the help people. I implemented a game_proc function and it works pretty well. I also realized that my clear_to_color() function was drawing over the menu bar, which I hadn't thought about before. I made it so my clear to color doesn't overwrite the menu bar anymore, which is also a big help.