![]() |
|
GUI Design and Implementation for Noobs |
kingnoob
Member #18,984
January 2021
|
We Noobs tend not to know how to code things like a GUI. That is until we learn how everyone else does it. However, that is when a Noob stops being a Noob. Noobs that join the establishment cannot be King Noobs! King Noobs always forge their own path even if it ends up not being optimal. So if you are a Noob and would like to become a King Noob then this example of noobishness might be for you! First of all King Noobs never imprison themselves in a prepackaged cookie cutter solution that limits their creativity or dulls their excitement about what they have created. Nor do we need more functionality than what will get the job done. And we definitely cannot learn other peoples source code and how to modify it. It is just against our nature. So, now that every Noob reading here knows what it means to be a King Noob we can begin. First we need some code to get events. Even though we are King Noobs we still right noobish code. We plan on cleaning it up later but as long as it works it is not a priority. In the following GetEvent() function at least two very noobish things are done. One, global variables are used that should be placed in a GUI structure. And two, some processing that should be in ProcessEvent() is in GetEvent(). Here is the code for GetEvent(). 1bool GetEvent() {
2 if (al_get_next_event(queue, &event)) {
3 switch (event.type) {
4 case ALLEGRO_EVENT_KEY_DOWN:
5 switch (event.keyboard.keycode) {
6 case ALLEGRO_KEY_ESCAPE:
7 return false;
8 break;
9 case ALLEGRO_KEY_PAD_MINUS:
10 if (rate < 40) rate++;
11 break;
12 case ALLEGRO_KEY_PAD_PLUS:
13 if (rate > 1) rate--;
14 break;
15 case ALLEGRO_KEY_D:
16 demo = 1 - demo;
17 break;
18 }
19 break;
20 case ALLEGRO_EVENT_MOUSE_AXES:
21 mx = event.mouse.x;
22 my = event.mouse.y;
23 break;
24 case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
25 mbu = false;
26 mbd = event.mouse.button;
27 mdx = event.mouse.x;
28 mdy = event.mouse.y;
29 break;
30 case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
31 mbd = false;
32 mbu = event.mouse.button;
33 mux = event.mouse.x;
34 muy = event.mouse.y;
35 break;
36 }
37 }
38 return true;
39}
1void ProcessEvent() {
2 switch (gui[ui]) {
3 case NONE:
4 None();
5 break;
6 case SEND:
7 Send();
8 break;
9 case STAND:
10 Stand();
11 break;
12 case GAME:
13 Game();
14 break;
15 case SELECT:
16 Select();
17 break;
18 case PAUSED:
19 Paused();
20 break;
21 }
22}
Also King Noobs are not known for their code commenting skills. You can take the king out of the noob but you can't take the noob out of the king. Don't try to understand that. King Noobs do not always make sense. Looking at the function all it does is proceed to the active GUI element which includes NONE. It is the responsibility of None() to detect the desired activation of a GUI element. 1void None() {
2 if (mbu) {
3 org = GetStar();
4 if (org == numStars) {
5 if (mbu == 2) {
6 paused = true;
7 ui++;
8 gui[ui] = PAUSED;
9 }
10 else if (mbu == 1) {
11 paused = true;
12 ui++;
13 gui[ui] = PAUSED;
14 ui++;
15 gui[ui] = GAME;
16 }
17 }
18 else {
19 ui++;
20 gui[ui] = SELECT;
21 }
22 mbu = false;
23 }
24}
1DrawSelect() {
2 int d, dx, i, j, x, y, X, Y;
3 ALLEGRO_COLOR c;
4 char buf[10];
5
6 i = GetStar();
7 if (i < numStars) {
8 x = star[i].x; y = star[i].y;
9 }
10 else {
11 x = mx; y = my;
12 }
13 c = RED;
14 inRange = false;
15 for (int j = 0; j < numStars; j++) {
16 if (star[j].owner == 1) {
17 X = star[j].x - x;
18 Y = star[j].y - y;
19 d = sqrt(pow(X, 2) + pow(Y, 2));
20 if (d <= maxDist) {
21 c = GREEN;
22 inRange = true;
23 break;
24 }
25 }
26 }
27 al_draw_line(star[org].x, star[org].y, x, y, c, 2);
28 X = star[org].x - x;
29 Y = star[org].y - y;
30 d = sqrt(pow(X, 2) + pow(Y, 2));
31 _itoa_s(d, buf, 10, 10);
32 dx = x + 54; j = ALLEGRO_ALIGN_RIGHT;
33 if (star[org].x > x) {
34 dx = x - 54;
35 j = ALLEGRO_ALIGN_LEFT;
36 }
37 al_draw_text(font15, GREEN, x, y - 32, ALLEGRO_ALIGN_CENTRE, buf);
38}
Since the GUI mode is now in "select" mode the next time ProcessEvent() is called the switch statement will jump to the Select() function which does one of the following. We are going to look at number 3. standing orders. I have not yet displayed the draw GUI selector code. It will be displayed just after Select(). It will look familiar. 1void Select() {
2 if (mbu) {
3 dst = GetStar();
4 if (dst == org) {
5 orders[org].over = 0;
6 gui[ui] = NONE;
7 ui--;
8 } else
9 if (dst == numStars || dst == org) {
10 gui[ui] = NONE;
11 ui--;
12 }
13 else {
14 if (star[org].owner == 1) {
15 if (mbu == 1) {
16 if (star[dst].owner == 1 || InRange(dst)) {
17 gui[ui] = SEND;
18 send = 0;
19 }
20 }
21 else {
22 if (star[dst].owner) {
23 gui[ui] = STAND;
24 active = 0;
25 }
26 }
27 }
28 }
29 mbu = false;
30 }
31}
Draw selection code called from DrawFrame() in the main game loop. 1void DrawGui() {
2 switch (gui[ui]) {
3 case NONE:
4 DrawInfo();
5 break;
6 case SEND:
7 DrawSend();
8 break;
9 case STAND:
10 DrawStand();
11 break;
12 case GAME:
13 DrawGame();
14 break;
15 case SELECT:
16 DrawSelect();
17 DrawInfo();
18 break;
19 case PAUSED:
20 DrawInfo();
21 break;
22 }
23}
Follows is the standing orders draw code. It is drawn every single frame. If I were not such a noob I'd put it in memory so that all that would need done is blit the unchanging parts to be more efficient. However, since the game runs plenty fast enough already, the King Noob way is to remain noobish about it, for now. 1void DrawStand() {
2 int i, x, y;
3 char buf[12];
4 i = dst;
5 if (i < numStars) {
6 x = star[dst].x; y = star[dst].y;
7 gx = x = (x < sw / 2) ? x + 20 : x - 500;
8 gy = y = (y < 640) ? y : 640;
9 al_draw_filled_rounded_rectangle(x, y, x + 479, y + 398, 10, 10, STEEL);
10 al_draw_filled_rounded_rectangle(x + 435, y + 4, x + 475, y + 44, 10, 10, DARKSTEEL);
11 al_draw_text(font35, STEEL, x + 455, y + 4, ALLEGRO_ALIGN_CENTER, "X");
12 al_draw_text(font70, BLACK, x + 239, y, ALLEGRO_ALIGN_CENTRE, star[i].name);
13 al_draw_line(x + 10, y + 80, x + 469, y + 80, BLACK, 4.0f);
14 for (i = 0; i < 10; i++) {
15 _itoa_s(i, buf, 12, 10);
16 al_draw_text(font70, BLACK, x + 33 + i * 46, y + 80, ALLEGRO_ALIGN_CENTER, buf);
17 }
18
19 al_draw_line(x + 10, y + 158, x + 469, y + 158, BLACK, 4.0f);
20
21 al_draw_text(font35, LIGHTSTEEL, x + 10, y + 168, 0, "If Over");
22 al_draw_filled_rectangle(x + 140, y + 168, x + 340, y + 208, LIGHTSTEEL);
23 if (active == 0) al_draw_filled_circle(x + 146, y + 173, 4, DARKSTEEL);
24 _itoa_s(over, buf, 12, 10);
25 al_draw_text(font35, BLACK, x + 240, y + 168, ALLEGRO_ALIGN_CENTER, buf);
26 al_draw_filled_rectangle(x + 350, y + 168, x + 420, y + 208, LIGHTSTEEL);
27 al_draw_text(font25, BLACK, x + 385, y + 173, ALLEGRO_ALIGN_CENTER, "Clear");
28 al_draw_filled_triangle(x + 430, y + 188, x + 450, y + 168, x + 450, y + 208, LIGHTSTEEL);
29 al_draw_filled_rectangle(x + 450, y + 168, x + 469, y + 208, LIGHTSTEEL);
30 al_draw_text(font35, BLACK, x + 457, y + 168, ALLEGRO_ALIGN_CENTER, "X");
31
32 al_draw_line(x + 10, y + 218, x + 469, y + 218, BLACK, 4.0f);
33
34 al_draw_text(font35, LIGHTSTEEL, x + 10, y + 228, 0, "Send");
35 al_draw_filled_rectangle(x + 140, y + 228, x + 340, y + 268, LIGHTSTEEL);
36 if (active == 1) al_draw_filled_circle(x + 146, y + 233, 4, DARKSTEEL);
37 _itoa_s(ships, buf, 12, 10);
38 al_draw_text(font35, BLACK, x + 240, y + 228, ALLEGRO_ALIGN_CENTER, buf);
39 al_draw_filled_rectangle(x + 350, y + 228, x + 469, y + 268, LIGHTSTEEL);
40 al_draw_text(font25, BLACK, x + 410, y + 233, ALLEGRO_ALIGN_CENTER, "Stop All");
41
42 al_draw_line(x + 10, y + 278, x + 469, y + 278, BLACK, 4.0f);
43
44 al_draw_text(font35, LIGHTSTEEL, x + 10, y + 288, 0, "Bump");
45 al_draw_filled_rectangle(x + 140, y + 288, x + 340, y + 328, LIGHTSTEEL);
46 if (active == 2) al_draw_filled_circle(x + 146, y + 293, 4, DARKSTEEL);
47 _itoa_s(bump, buf, 12, 10);
48 al_draw_text(font35, BLACK, x + 240, y + 288, ALLEGRO_ALIGN_CENTER, buf);
49 al_draw_filled_rectangle(x + 350, y + 288, x + 469, y + 328, LIGHTSTEEL);
50 al_draw_text(font25, BLACK, x + 410, y + 293, ALLEGRO_ALIGN_CENTER, "Order");
51
52 al_draw_line(x + 10, y + 338, x + 469, y + 338, BLACK, 4.0f);
53
54 al_draw_filled_rounded_rectangle(x + 10, y + 348, x + 469, y + 388, 10, 10, DARKSTEEL);
55 al_draw_text(font15, LIGHTSTEEL, x + 240, y + 359, ALLEGRO_ALIGN_CENTER, "Reasign ALL Standing Orders To Destination");
56 }
57}
GOT IT WORKING. |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
I'm sorry, but your nick is well deserved. If bambams were paying attention, he would mention that global variables are just a bad idea generally frowned upon. Place them in an object, a namespace, etc... If jmasterx were here, he would say you use too many magic numbers. Too many loose literal const values littered in your code. For goodness sake, use a struct and an extra variable. If ML was feeling bored he might say you're suffering from spaghetti code, although you've done a nice job separating code into relevant functions so I give you props there. And I would have to agree with them. That gives you a n00b13 score of 3 / 3. Seriously, we can be pretty critical here, but I assure you we're doing it out of love. EDIT My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Dizzy Egg
Member #10,824
March 2009
![]() |
....and then there’s you.....dr whatever who told us all to go f ourselves because we didn’t download your game. Kiss my shell.
---------------------------------------------------- |
|