I'm working with Open Layer on an RPG. So, I want to integrate a GUI into my game but I don't exactly know how to do that.
Are there libraries that I could use or do I have to code everything by myself? Is it possible to use the GUI functions of Allegro?
I was thinking the exact same thing. I want to create a simple GUI for a game im making. Just a basic menu, start button, maybe some options and a quit button. But I dont know how to do it!
So im hoping someone will reply to this thread!
I've had the same problem, but I solved it by using something similar to collision detection in a game. If you want any type of button, you will know the size of it say 64 wide x 32 deep. You also know where you're going to display it on the screen say 100,100. You can track where the x and y is of the mouse pointer on screen (you have to install the mouse first) and you can also check for the mouse button being clicked.
So using the numbers above, the top left co-ords of the button on the screen are 100,100 and the bottom right co-ords of the button on screen are 163,131 (screen x: 100 + button width 64 - 1 [cos the button starts at 100 not 101] , screen y: 100 + button height 32 - 1 [for same reason]).
So if the mouse buttom is clicked and mouse x>=100 and mouse x<=163 and mouse y>=100 and mouse y<=131 then the button on screen has been clicked and you can use that info to do what you want.
If you want more than one button on screen at once, just keep a track of what the button co-ords are to initiate the correct function.

If you want a full code example let me know
A code example would be nice. Anyway sounds pretty simple. Now... But when youre thinking how to do its a diffrent story! Ill try this! Thanks!
I'm using guichan as a UI library together with OpenLayer, works fine, if you manage to setup all libraries you need. That means allegro, allegrogl, lpng (optional) and lzip (used only for lpng).
Hi, as promised here is my full code listing for my GUI. It's very basic and there may be other ways to do it better, but it worked for me 
| 1 | #include <allegro.h> |
| 2 | |
| 3 | #define RED makecol(255,0,0) |
| 4 | #define GREEN makecol(0,255,0) |
| 5 | #define BLUE makecol(0,0,255) |
| 6 | #define WHITE makecol(255,255,255) |
| 7 | #define BLACK makecol(0,0,0) |
| 8 | |
| 9 | //number of buttons on GUI interface |
| 10 | #define BUTTONS 2 |
| 11 | |
| 12 | //function prototypes |
| 13 | void create_buttons(void); |
| 14 | int check_click(int mousex,int mousey); |
| 15 | |
| 16 | //set up an array of button bitmaps - use a loop to display them |
| 17 | BITMAP *buttons[BUTTONS]; |
| 18 | |
| 19 | //set up an array for x,y cor-ords of each button on screen |
| 20 | //can loop through them when mouse button is clicked to see |
| 21 | //which button or not is clicked |
| 22 | int but_xy[BUTTONS*2]; |
| 23 | |
| 24 | //variables to keep track of mouse info |
| 25 | int mousex,mousey,mousebut; |
| 26 | |
| 27 | int main() |
| 28 | { |
| 29 | allegro_init(); |
| 30 | set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); |
| 31 | text_mode(-1); |
| 32 | install_keyboard(); |
| 33 | install_mouse(); |
| 34 | install_timer(); |
| 35 | show_mouse(screen); |
| 36 | |
| 37 | int x,but; |
| 38 | |
| 39 | create_buttons(); |
| 40 | |
| 41 | //loop to display buttons on screen at proper co-ords |
| 42 | for(x=0;x<BUTTONS;x++) |
| 43 | { |
| 44 | blit(buttons[x],screen,0,0,but_xy[x*2],but_xy[x*2+1],buttons[x]->w,buttons[x]->h); |
| 45 | } |
| 46 | |
| 47 | while(! key[KEY_ESC]) |
| 48 | { |
| 49 | textprintf(screen,font,1,1,WHITE,"%s","Press ESC KEY to Exit"); |
| 50 | //keeping track of mouse info |
| 51 | mousex=mouse_x; |
| 52 | mousey=mouse_y; |
| 53 | mousebut=(mouse_b&1); // this only checks left mouse button |
| 54 | |
| 55 | //if left mouse button is clicked the mouse x,y co-ords are checked against |
| 56 | //button co-ords on screen held in array |
| 57 | if(mousebut==1) |
| 58 | { |
| 59 | but=check_click(mousex,mousey); |
| 60 | rectfill(screen,1,11,500,21,BLACK); |
| 61 | //the button number clicked on will be returned and can be used in the switch statement |
| 62 | //to do the required thing it is designed to do in your game |
| 63 | switch(but) |
| 64 | { |
| 65 | case 0: |
| 66 | textprintf(screen,font,1,11,RED,"Result of last mouse click: %s","Play Button Clicked"); |
| 67 | break; |
| 68 | case 1: |
| 69 | textprintf(screen,font,1,11,BLUE,"Result of last mouse click: %s","Quit Button Clicked"); |
| 70 | break; |
| 71 | default: |
| 72 | textprintf(screen,font,1,11,WHITE,"Result of last mouse click: %s","No Button Clicked"); |
| 73 | break; |
| 74 | } |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | allegro_exit(); |
| 79 | return 0; |
| 80 | } |
| 81 | END_OF_MAIN(); |
| 82 | |
| 83 | |
| 84 | //creating bitmaps in memory, you can load your own nice looking buttons instead |
| 85 | void create_buttons(void) |
| 86 | { |
| 87 | int x; |
| 88 | |
| 89 | //set up all x,y co-ords of all buttons to display on screen here |
| 90 | |
| 91 | //x,y co-ord of button 0 |
| 92 | but_xy[0]=100; |
| 93 | but_xy[1]=100; |
| 94 | |
| 95 | //x,y co-ord of button 1 |
| 96 | but_xy[2]=150; |
| 97 | but_xy[3]=200; |
| 98 | |
| 99 | //creating bitmaps in memory here, you can load them instead |
| 100 | buttons[0]=create_bitmap(64,32); |
| 101 | clear_to_color(buttons[0],RED); |
| 102 | buttons[1]=create_bitmap(40,40); |
| 103 | clear_to_color(buttons[1],BLUE); |
| 104 | textprintf(buttons[0],font,14,12,WHITE,"%s","PLAY"); |
| 105 | textprintf(buttons[1],font,5,17,WHITE,"%s","QUIT"); |
| 106 | } |
| 107 | |
| 108 | //checking if mouse pointer is over a button on screen when clicked |
| 109 | int check_click(int mousex,int mousey) |
| 110 | { |
| 111 | int x; |
| 112 | int x1,y1,x2,y2; |
| 113 | int b=-1; // this is used to record which button number is clicked - if none returns -1 |
| 114 | |
| 115 | //looping through all buttons on screen and checking if mouse pointer is inside button |
| 116 | for(x=0;x<BUTTONS;x++) |
| 117 | { |
| 118 | x1=but_xy[x*2]; //top left corner of button on screen - x |
| 119 | y1=but_xy[x*2+1]; // top left corner of button on screen - y |
| 120 | x2=x1+buttons[x]->w-1; // bottom right corner of button on screen - x |
| 121 | y2=y1+buttons[x]->h-1; // bottom right corner of button on screen - y |
| 122 | |
| 123 | // if mouse pointer is inside button co-ords the button number is stored in b |
| 124 | if(mousex>=x1 && mousex<=x2 && mousey>=y1 && mousey<=y2) b=x; |
| 125 | } |
| 126 | //either returns a button number or -1 for no button clicked |
| 127 | return (b); |
| 128 | } |
Let me know if this helps or I'd be interested if you find an easier/better way cos I'm quite new to all this and still learning
Thanks for your answers. Thanks for your code, Paul Rowan. That's the way I had done it before as I wrote a game with another library than Open Layer / Allegro. I think I will do it like that.
Here is a class I made for the purpouse. Makes the process easier
| 1 | #ifndef _BUTTON_H_ |
| 2 | #define _BUTTON_H_ |
| 3 | /** |
| 4 | * Class for drawing button on the screen and using actions from it |
| 5 | **/ |
| 6 | |
| 7 | class Button { |
| 8 | public: |
| 9 | Button() |
| 10 | { |
| 11 | button_image = NULL; |
| 12 | } |
| 13 | ~Button() |
| 14 | { |
| 15 | button_image = NULL; |
| 16 | } |
| 17 | |
| 18 | void set_bitmap(BITMAP *bitmap_b) |
| 19 | { |
| 20 | button_image = bitmap_b; |
| 21 | } |
| 22 | void set_coords(int x, int y) |
| 23 | { |
| 24 | button_x = x; |
| 25 | button_y = y; |
| 26 | } |
| 27 | void draw_button(BITMAP *to) const |
| 28 | { |
| 29 | blit(button_image, to, 0, 0, button_x, button_y, button_image->w, |
| 30 | button_image->h); |
| 31 | } |
| 32 | |
| 33 | int button_clicked() |
| 34 | { |
| 35 | // Mouse must be clicked |
| 36 | if(mouse_b & 1) |
| 37 | { |
| 38 | int real_x, real_y; |
| 39 | real_x = button_x + button_image->w - 1; |
| 40 | real_y = button_y + button_image->h - 1; |
| 41 | |
| 42 | if(mouse_x>=button_x && mouse_x<=real_x && mouse_y>=button_y |
| 43 | && mouse_y <=real_y) |
| 44 | { |
| 45 | // CLICKED |
| 46 | return 1; |
| 47 | } |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | private: |
| 52 | int button_x,button_y; |
| 53 | BITMAP *button_image; |
| 54 | }; |
| 55 | |
| 56 | |
| 57 | #endif |
@Vanneto:
Just a small comment: Normally a button fires only if somebody presses and releases the mouse inside the boundaries of the button. Links work the same way.
Besides working like the user expects it, it also solves the problem that the click might be registered on the next page as well, if the page changes before the button was released.
And how do I know if it was released? I will change the class appropriately.
Thanks!
Well, that's the point where it gets more complicated.
Let's say you have a function like this:
| 1 | // you will want to place these vars inside a class |
| 2 | GUIItem lastItem = NULL; |
| 3 | int lastMouseButtonState= 0; |
| 4 | |
| 5 | void handleGUI() { |
| 6 | int x= mouse_x; |
| 7 | int y= mouse_y; |
| 8 | int buttons = mouse_b; |
| 9 | GUIItem item = findGUIItem(x, y); |
| 10 | |
| 11 | if (item == null) { |
| 12 | // mouse is not inside an item. |
| 13 | if (lastItem != NULL) { |
| 14 | lastItem ->handleMouseOut(); |
| 15 | } |
| 16 | } |
| 17 | if (buttons != lastMouseButtonState) { |
| 18 | if (lastItem != NULL && lastItem != item) { |
| 19 | lastItem->handleMouseButton(buttons); |
| 20 | } |
| 21 | if (item != NULL) { |
| 22 | item->handleMouseButton(buttons); |
| 23 | } |
| 24 | |
| 25 | lastMouseButtonState = buttons; |
| 26 | } |
| 27 | lastItem = item; |
| 28 | } |
If you want even more flexibility, you could add the concept of a grabbed item, receiving all related events until it declares itself as no longer interested.
This way your button can grab the events as soon as the mouse button goes down inside his boundaries. It should release the grab as soon as the mouse button is no longer pressed.
The code above was written on the fly and will probably contain errors. I hope the example will be good enough to visualize the idea, though.