![]() |
|
Splash Screens and Setup Screens Part of Event loop? |
AceBlkwell
Member #13,038
July 2011
![]() |
Just thinking in advance. I've got my simple game operational, granted without any safe guards for the moment. Eventually I'm going to want to allow for an entry screen and/or setup screen for player names. My question, when implementing screens like instruction screens or game setup screens do you run that through a separate loop? I envision a main loop with the gameplay loop called from that loop. When the game was over or player quits, you would return to the main loop responsible for the opening screen? Is that a common approach or a problematic approach? Thanks |
DanielH
Member #934
January 2001
![]() |
You can create another variable, game_state. Some options: You can make separate functions that handle events for certain game states or have one function, but it gets confusing. I don't know how well you are at reading code, but I have a simple tictactoe game. It has game state. There is an opening screen with a menu. You can escape during gameplay back to the menu and the menu changes (from new game to continue game). I kept it to one function for the logic, but multiple functions for drawing the screen depending on game state. In the game there are numerous game states. enum class GameState { Undefined, Initializing, TitleScreen, HelpScreen, AboutScreen, Shuttingdown, PlayerXTurn, PlayerOTurn, PlayerXWin, PlayerOWin, Tie }; most of the logic is triggered by mouse or key up. It gets messy. I only show you to show the mess. 1case ALLEGRO_EVENT_KEY_UP:
2 {
3 this->m_input.OnEventKeyUp(event.keyboard.keycode);
4
5 if (event.keyboard.keycode == ALLEGRO_KEY_OPENBRACE)
6 {
7 Theme::incTheme();
8 }
9 if (event.keyboard.keycode == ALLEGRO_KEY_CLOSEBRACE)
10 {
11 Theme::decTheme();
12 }
13
14 this->m_dirty = true;
15 switch (this->m_gameState)
16 {
17 case GameState::PlayerXWin:
18 case GameState::PlayerOWin:
19 {
20 if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
21 {
22 this->m_grid.reset();
23 this->m_gameState = GameState::TitleScreen;
24 }
25 } break;
26 case GameState::PlayerXTurn:
27 case GameState::PlayerOTurn:
28 {
29 if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
30 {
31 this->m_gameState = GameState::TitleScreen;
32 }
33 } break;
34
35 case GameState::HelpScreen:
36 case GameState::AboutScreen:
37 {
38 if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
39 {
40 this->m_gameState = GameState::TitleScreen;
41 }
42 } break;
43
44 case GameState::TitleScreen:
45 {
46 if (event.keyboard.keycode == ALLEGRO_KEY_ENTER ||
47 event.keyboard.keycode == ALLEGRO_KEY_PAD_ENTER)
48 {
49 switch (this->m_option)
50 {
51 case App::TitleOptions::New:
52 {
53 this->m_gameState = GameState::PlayerXTurn;
54 al_show_mouse_cursor(this->m_display);
55 } break;
56 case App::TitleOptions::Help:
57 {
58 this->m_gameState = GameState::HelpScreen;
59 } break;
60 case App::TitleOptions::About:
61 {
62 this->m_gameState = GameState::AboutScreen;
63 } break;
64 case App::TitleOptions::Quit:
65 {
66 this->m_kill = true;
67 } break;
68 }
69 }
70
71 if (event.keyboard.keycode == ALLEGRO_KEY_UP ||
72 event.keyboard.keycode == ALLEGRO_KEY_PAD_8)
73 {
74 if (this->m_option == App::TitleOptions::New)
75 {
76 this->m_option = App::TitleOptions::Quit;
77 }
78 else
79 {
80 this->m_option = App::TitleOptions(static_cast<int32_t>(this->m_option) - 1);
81 }
82 }
83 if (event.keyboard.keycode == ALLEGRO_KEY_DOWN ||
84 event.keyboard.keycode == ALLEGRO_KEY_PAD_2)
85 {
86 if (this->m_option == App::TitleOptions::Quit)
87 {
88 this->m_option = App::TitleOptions::New;
89 }
90 else
91 {
92 this->m_option = App::TitleOptions(static_cast<int32_t>(this->m_option) + 1);
93 }
94 }
95 if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
96 {
97 this->m_kill = true;
98 }
99 } break;
100 case GameState::Tie:
101 {
102 if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
103 {
104 this->m_gameState = GameState::TitleScreen;
105 this->m_grid.reset();
106 }
107 } break;
108 default: break;
109 }
110 } break;
|
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
This is easily handled with a little inheritance and a screen pointer. Have a base Scene class with a few virtual functions to override like so : For instance, here is my Scene class for the latest game I am working on : 1#ifndef Scene_HPP
2#define Scene_HPP
3
4#include "Eagle/Events.hpp"
5#include "Eagle/AnimationBase.hpp"
6
7class EagleGraphicsContext;
8
9enum SCENE_STATUS {
10 SCENE_NOTREADY = 0,
11 SCENE_READY = 1,
12 SCENE_RUNNING = 2,
13 SCENE_COMPLETE = 4,
14 SCENE_ERROR = 8
15};
16
17#define NUM_SCENES 3
18
19class Scene : public AnimationBase {
20
21protected :
22 bool redraw;
23 bool quit;
24 bool complete;
25 SCENE_STATUS status;
26
27 void OnComplete() {complete = true;}
28
29public :
30 Scene();
31
32 virtual ~Scene() {}
33
34 virtual bool Init(EagleGraphicsContext* win)=0;
35
36 virtual SCENE_STATUS HandleEvent(EagleEvent ev)=0;
37 virtual SCENE_STATUS Update(double dt)=0;
38 virtual void Display(EagleGraphicsContext* win)=0;
39
40 bool Redraw();
41 bool Quit();
42 bool Complete();
43 SCENE_STATUS Status();
44
45 virtual void Reset();
46};
47
48#endif // Scene_HPP
It lays the framework to derive new classes of scene. One for each screen you want to have, because each will have different inputs, handle events differently, and draw different things. That's what the virtual functions are for.
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
![]() |
Damn Edgar that makes we want to start making a new game!
---------------------------------------------------- |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
{"name":"giphy.gif","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/3\/4351345c99eba961790182ff75abacf7.gif","w":332,"h":168,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/3\/4351345c99eba961790182ff75abacf7"} 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 |
AceBlkwell
Member #13,038
July 2011
![]() |
Thanks for the input all. I'm not very familiar with virtual functions Edgar but sounds like I need to learn. Daniel, I'm assuming all of this runs within the same while loop? I was looking over my last game using A4, It didn't work with events but I think the concept will work the same. Previously I used main to call all other functions. IE Title screen. Instruction screen, Playing screen. Outside of calling inits and declaring arrays/variables, main was less than 20 lines of code. I used while loops to keep the game running with in the different functions but stopped for readkeys. I think that will be the major difference. Again I appreciate the input. |
DanielH
Member #934
January 2001
![]() |
Polymorphism 1class Base
2{
3public:
4 Base();
5 virtual ~Base();
6 virtual void draw();
7};
8
9class TitleScreen : public Base
10{
11public:
12 TitleScreen();
13 ~TitleScreen();
14 void draw()
15};
16
17
18class MenuScreen : public Base
19{
20public:
21 MenuScreen();
22 ~MenuScreen();
23 void draw()
24};
Each subclass inherits everything from the base class. Then you can have one Base class variable. Each subclass can have it's own logic, drawing, event handling. TitleScreen* title = new TitleScreen(); MenuScreen* menu = new MenuScreen(); Base* base = nullptr; Depending which game state you are in, you assign base to that subclass. base = (Base*)title; base->draw(); Then switch if game state switches. base = (Base*)menu; base->draw(); Virtual tells the compiler to use the function of the child class if there is one. Otherwise use the function of the base class. The functions of the subclass is optional. You can force it by declaring your virtual function like this class Base { public: Base(); virtual ~Base(); virtual void draw() = 0; }; Not each child class is required to have it's own draw function. |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
https://cplusplus.com/doc/tutorial/classes/ The virtual keyword is just a signal to the compiler and base classes that they may override the behavior of this function. If it is a pure absolute function (virtual and ends with )=0; ) then it must be implemented in the derived class before it can be instantiated. 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 |
AceBlkwell
Member #13,038
July 2011
![]() |
I'll have to read up on it some more. I'm familiar with base classes and inheritance from the stand point that I've read up on them. I've even done a few exercises. My limited used of classes isn't much different than structs. Well other than private and public. As such I typically use structs. I guess it's time to graduate on. |
DanielH
Member #934
January 2001
![]() |
It has it's uses. Don't for get protected keyword also. Here is my dialog class, which is a subclass of a widget. It's abstract, meaning you can't create a Dialog. 1namespace Wind
2{
3 class Dialog : public Widget
4 {
5 public:
6 Dialog();
7 virtual ~Dialog();
8
9 virtual bool OnStart() = 0;
10 virtual bool OnStop() = 0;
11 virtual bool OnInitialize() = 0;
12 virtual bool OnShutDown() = 0;
13 virtual bool OnUpdate(int32_t tick_count) = 0;
14 virtual bool OnRender(Allegro::Display& display) = 0;
15
16 virtual bool OnJoystickAxis(const Allegro::Event& event);
17 virtual bool OnJoystickButtonDown(const Allegro::Event& event);
18 virtual bool OnJoystickButtonUp(const Allegro::Event& event);
19 virtual bool OnJoystickConfiguration(const Allegro::Event& event);
20 virtual bool OnKeyDown(const Allegro::Event& event);
21 virtual bool OnKeyUp(const Allegro::Event& event);
22 virtual bool OnKeyChar(const Allegro::Event& event);
23 virtual bool OnMouseClick(const Allegro::Event& event);
24 virtual bool OnMouseAxes(const Allegro::Event& event);
25 virtual bool OnMouseButtonDown(const Allegro::Event& event);
26 virtual bool OnMouseButtonUp(const Allegro::Event& event);
27 virtual bool OnMouseEnterDisplay(const Allegro::Event& event);
28 virtual bool OnMouseLeaveDisplay(const Allegro::Event& event);
29 virtual bool OnMouseWarped(const Allegro::Event& event);
30 virtual bool OnDisplayResize(const Allegro::Event& event);
31 virtual bool OnDisplayClose(const Allegro::Event& event);
32 virtual bool OnDisplayLost(const Allegro::Event& event);
33 virtual bool OnDisplayFound(const Allegro::Event& event);
34 virtual bool OnDisplaySwitchIn(const Allegro::Event& event);
35 virtual bool OnDisplaySwitchOut(const Allegro::Event& event);
36 virtual void NotifyParent(int32_t n, void* data);
37
38 void AddWidget(Widget* widget);
39 virtual Widget* GetWidget(int32_t x, int32_t y);
40
41 protected:
42
43 Dialog(const Dialog& Dialog) = delete;
44 Dialog& operator = (const Dialog& Dialog) = delete;
45 std::vector<Dialog*> m_children;
46 std::vector<Widget*> m_widgets;
47 };
48}
My starting dialog. I don't use most of the events in this class. I left them in there, but commented them out. 1 class Game : public Wind::Dialog
2 {
3 public:
4 Game();
5 ~Game();
6
7 bool OnStart();
8 bool OnStop();
9 bool OnInitialize();
10 bool OnShutDown();
11 bool OnUpdate(int32_t tick_count);
12 bool OnRender(Allegro::Display& display);
13
14 //bool OnJoystickAxis(const Allegro::Event& event);
15 //bool OnJoystickButtonDown(const Allegro::Event& event);
16 //bool OnJoystickButtonUp(const Allegro::Event& event);
17 //bool OnJoystickConfiguration(const Allegro::Event& event);
18 //bool OnKeyDown(const Allegro::Event& event);
19 //bool OnKeyUp(const Allegro::Event& event);
20 //bool OnKeyChar(const Allegro::Event& event);
21 //bool OnMouseClick(const Allegro::Event& event);
22 //bool OnMouseDoubleClick(const Allegro::Event& event);
23 //bool OnMouseAxes(const Allegro::Event& event);
24 //bool OnMouseButtonDown(const Allegro::Event& event);
25 //bool OnMouseButtonUp(const Allegro::Event& event);
26 //bool OnMouseEnterDisplay(const Allegro::Event& event);
27 //bool OnMouseLeaveDisplay(const Allegro::Event& event);
28 //bool OnMouseWarped(const Allegro::Event& event);
29 bool OnDisplayResize(const Allegro::Event& event);
30 bool OnDisplayClose(const Allegro::Event& event);
31 //bool OnDisplayLost(const Allegro::Event& event);
32 //bool OnDisplayFound(const Allegro::Event& event);
33 //bool OnDisplaySwitchIn(const Allegro::Event& event);
34 //bool OnDisplaySwitchOut(const Allegro::Event& event);
35 void NotifyParent(int32_t n, void* data);
36
37 private:
38 };
|
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
Java's one listener class for every event is total over-engineering. In my opinion so is having an OnEvent method for every event type. It's simple enough to let a widget or a dialog or a screen or an object to handle a single event and modify it's behavior based on the type. 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 |
DanielH
Member #934
January 2001
![]() |
In your opinion, you can keep to yourself. |
AceBlkwell
Member #13,038
July 2011
![]() |
In any case, talking with you guys lets me know how much I really don't know |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
Wouldn't want to offend anyone with my opinion. 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 |
|