|
|
| Problem with unresponsive event managing |
|
Øyvind Andersson
Member #14,671
November 2012
|
Hi! I have a problem with my game loop, or the event handling. The loop or allegro seems to miss out on certain events, which is mostly notices on keyboard (up/down) events. I have created a class for the keyboard, that stores key presses (key[true|false]) to enable IsKeyPressed(int key), for i.e. move player on screen, and such. The problem though - although not every time - is that when I press for example UP and LEFT at the same time, either LEFT or UP does not receive the KEY_UP state when I release one of them, thus making the character move in that direction until I press it again to re-send the UP event. Here is a few details and some code: Timer speeds 1const float DRAW_FPS = 30.0f;
2const float UPDATE_TICK = 60.0f;
Timer init 1m_pDrawTimer = new CGameTimer(1.0 / DRAW_FPS);
2m_pUpdateTimer = new CGameTimer(1.0 / UPDATE_TICK);
3m_pGameTimer = new CGameTimer(1.0);
4
5/****
6 In CGameTimer ctor
7****/
8CGameTimer::CGameTimer(double speed_seconds)
9{
10 m_pTimer = NULL;
11 m_pTimer = al_create_timer(speed_seconds);
12}
13
14...
15
16/*
17 Declared in CGameTimer header
18*/
19CTimer *GetTimer() { return m_pTimer; }
20CTimer *m_pTimer; // CTimer = typedef ALLEGRO_TIMER CTimer
Game loop 1m_pGameTimer->StartTimer(); // Records our in-game time
2 m_pDrawTimer->StartTimer();
3 m_pUpdateTimer->StartTimer();
4 m_dPrevGameTime = m_pGameTimer->GetTime();
5
6 /*********************************
7 *
8 * Run the game loop!
9 *
10 **********************************/
11 m_bIsRunning = true;
12 while(m_bIsRunning)
13 {
14 WaitForEvent(&g_Event);
15
16 /*
17 Update when the timer has hit, and if the game is enabled
18 */
19 if( m_bShouldUpdate && m_bIsEnabled )
20 {
21 /*
22 Update input devices
23 */
24 g_InputManager->UpdateInputDevices(g_Event);
25
26 /*
27 Update game components
28 */
29 Update(m_pGameTimer);
30 }
31
32 /*
33 Draw when the draw timer has hit, and when the event queue is empty,
34 to make sure we rather update user input than render a frame.
35 @todo Pause game if focus is lost
36 */
37 if( m_bShouldDraw && CEventManager::IsEventQueueEmpty(GetQueue()) )
38 {
39 PreDraw(); // Clear buffer and other pre-proc
40 Draw(); // Overridable, so no critical buffer operations here. Hence pre/post. Draw gamecomponents
41 PostDraw(); // Swap buffers, calc fps
42 }
43
44 /*
45 When the display is closed, we initiate end game procs.
46 @todo Change state to Quit, and handle savegame stuff..
47 */
48 if(g_Event.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
49 {
50 EndGameLoop();
51 }
52
53 if( g_Event.type == ALLEGRO_EVENT_TIMER )
54 {
55 if( g_Event.timer.source == m_pUpdateTimer->GetTimer() && m_bShouldUpdate == false)
56 {
57 m_bShouldUpdate = true;
58 }
59 if( g_Event.timer.source == m_pDrawTimer->GetTimer() && m_bShouldDraw == false)
60 {
61 m_bShouldDraw = true;
62 }
63 }
64 }
65
66
67....
68
69/*
70 Here is the Update function called within StartGameLoop()
71*/
72void CBaseGame::Update(CGameTimer *pGameTime)
73{
74 /*
75 Update our game components
76 */
77 for( vGameObjectIterator iter = m_GameObjectCollection.begin(); iter != m_GameObjectCollection.end(); iter++)
78 {
79 CBaseGameObject *ent = (*iter);
80 if( ent->IsEnabled() && ent->GetShouldUpdate() )
81 {
82 ent->Update(pGameTime);
83 }
84 else
85 {
86 ent->SetShouldUpdate(true);
87 }
88 }
89
90 m_bShouldUpdate = false;
91}
Here are parts of CEventManager functions that are used in the loop. 1void CEventManager::WaitForEvent(CEvent *ev)
2 {
3 if( !m_pEventQ )
4 {
5 g_Log->ConPrint(0, "%qf Error!: Unable to poll events! Event queue is NULL!", "CEventManager", "WaitForEvent(CEvent *ev)");
6 }
7 al_wait_for_event(m_pEventQ, ev);
8 }
9
10...
11
12bool CEventManager::IsEventQueueEmpty(CEventQueue *queue)
13 {
14 return al_is_event_queue_empty(queue);
15 }
And finally, here are the keyboard device functions used to get keypress stuff. 1void CInputManager::UpdateInputDevices(CEvent &ev)
2{
3 vInputDeviceIterator iter;
4 for( iter = m_vDevices.begin(); iter != m_vDevices.end(); iter++ )
5 {
6 /*
7 Update device, if it's initialized and installed
8 */
9 if( (*iter)->IsInitialized() && (*iter)->IsInstalled() )
10 {
11 (*iter)->UpdateInput(ev);
12 }
13 }
14}
15
16CKeyboardState *CInputManager::GetKeyboard()
17{
18 if( !m_pKeyboard || !m_pKeyboard->IsInitialized() || !m_pKeyboard->IsInstalled() )
19 return NULL;
20
21 return m_pKeyboard;
22}
23
24
25void CKeyboardState::UpdateInput(CEvent &ev)
26{
27 m_ev = ev;
28 if( ev.type == ALLEGRO_EVENT_KEY_DOWN )
29 {
30 m_bKeys[ev.keyboard.keycode] = true;
31 }
32
33 if( ev.type == ALLEGRO_EVENT_KEY_UP )
34 {
35 m_bKeys[ev.keyboard.keycode] = false;
36 }
37
38 /**
39 * @todo - Check for modifiers...
40 */
41}
42
43
44bool CKeyboardState::IsKeyPressed(int key)
45{
46 return m_bKeys[key];
47}
Ok. A lot of code, but hopefully organized well enough. I think that is most of the parts that is part of updating, getting events, checking keyboard input etc etc. Here is a rough breakdown of a call-stack to get keyboard input from the game's update function: StartGameLoop So, are there any off-the-bat errors and/or grave speed issues? It runs fast and upkeeps 30 FPS at all times. Also a sidenote: I just changed the update speed to 60.0f. It has always been at 30.0f, but the problem did not change. The higher I set it, the more event problems occurs (I set it to 80.0f to test, and it missed almost every key up/down event. Very hacky behaviour). I hope you can help, as I don't want to continue very far before I have solved this. |
|
Slartibartfast
Member #8,789
June 2007
|
If I understand your code correctly, after every time you update, you call Update which sets m_bShouldUpdate to false. m_bShouldUpdate stays false until the next timer event. Once m_bShouldUpdate is true and an event happens, you set it to false and again only set it back to true once a timer event happens. ---- |
|
Øyvind Andersson
Member #14,671
November 2012
|
Holy shit.... Well that was easy, hehe. 1/*
2 Update input devices
3 */
4 g_InputManager->UpdateInputDevices(g_Event);
5
6 /*
7 Update when the timer has hit, and if the game is enabled
8 */
9 if( m_bShouldUpdate && m_bIsEnabled )
10 {
11 /*
12 Update game components
13 */
14 Update(m_pGameTimer);
15 }
Thanks mate, that fixed it! |
|
|