|
More efficient way to capture mouse position? |
Trent Gamblin
Member #261
April 2000
|
Thomas, it already did check if there were events... you're just confusing. al_event_queue_is_empty already checks in the code I gave him. That is the best form of the loop, despite what your preference is, in actual games.
|
Mishtiff
Member #15,776
October 2014
|
pkrcel said: 1.Allegro5 is production-grade software 2.I am also under the impression that we are circling around the problem in framerate but are looking at the input handling, which honestly SHOULDN'T be the issue-dealer.
1A. Thank you, that is reassuring. It is obviously my coding that is the culprit (not that i wasn't already expecting that). Thomas Fjellstrom said:
1.or your hardware.
1A. My hardware is strong enough to run most games on high-ultra. Of course most are obviously coded more efficiently than my own But again, i dont see how i can barely run what i am wanting my code to do, since i feel like its so little. Trent Gamblin said: Thomas, it already did check if there were events... you're just confusing. al_event_queue_is_empty already checks in the code I gave him. That is the best form of the loop, despite what your preference is, in actual games.
If this is true i would have no problem using it, but: |
Trent Gamblin
Member #261
April 2000
|
It would only render if you're moving the mouse if you're using al_wait_for_event but it WAITS in that call until it gets an event.
|
Mishtiff
Member #15,776
October 2014
|
Trent Gamblin said: It would only render if you're moving the mouse if you're using al_wait_for_event but it WAITS in that call until it gets an event.
Thank you, even though it clearly says that in the function call, for whatever reaso i wasnt aware that it sits there until something happens. I figured it skipped over it until it had something in the queue. |
Trent Gamblin
Member #261
April 2000
|
al_wait_for_event - if there is an event ready, grabs it, otherwise waits al_get_next_event - if there is an event ready, grabs it and returns true, otherwise returns false without ever waiting What I was saying about not having to check if there is an event returned from al_get_next_event, is because you already know there is an event in the queue because you called al_is_event_queue_empty.
|
Thomas Fjellstrom
Member #476
June 2000
|
Mishtiff said: Also, i see why your while loop makes more sense for a game loop I honestly don't. They should be functionally identical. My loop just acts as both loops at once. Feel free to explain it to me. -- |
Trent Gamblin
Member #261
April 2000
|
Your loop does needless processing. Not much but it's not perfect like mine.
|
Thomas Fjellstrom
Member #476
June 2000
|
Trent Gamblin said: Your loop does needless processing. Not much but it's not perfect like mine. Ok, maybe... But I still don't see how it does more than yours. Both check the events, and the queue for more events. Maybe it executes the if(draw) more often, but its almost always 0, so the cpu will predict that out of the pipeline before it becomes a problem. -- |
Mishtiff
Member #15,776
October 2014
|
I am trying to understand both as well now. let me explain what i understand for both. Trents: 1while(!done)
2{
3
4 while(!al_is_event_queue_empty(event_queue))
5 {
6 ALLEGRO_EVENT ev;
7 al_get_next_event(event_queue, ev);
8 //do all events
9 }
10
11if(render) {}
12}
For this version, all i see it doing is running through the while(!done) loop constantly until the event queue has something in it. obviously the render portion will be false until the timer.tick has ran, so it does seem running code this way is unnecessary? Thomas's: 1while(!done)
2{
3 ALLEGRO_EVENT ev;
4 al_wait_for_event(event_queue, ev);
5 //do event
6
7if(render && al_is_event_queue_empty(event_queue)){}
8}
For Thomas's, it simply waits to run any code until it is given input, then runs the code. if the code was a timer.tick, it will automatically pass over the if(render) statement. However... In Trents version, i understand that it will do any events in the queue until the queue is empty, then it will run into the render. after that it will circle around and hit the event loop, circle through all saved events, then continue again to the render. The thing about Trents is that as long as queue events are being added to the queue, will it ever return to the render portion? i do understand that the computer can do most of the processes in the ev.types extremely fast so it may not matter. you two can tell me if i have the right idea or not on each... The thing that i still am having an issue with is: For whatever reason, after i hit about 4-5 units spawned, it will only render if I move the mouse. the game is still constantly running the timer.tick portion (checked with std::couts), but does not render until i have moved the mouse. strange? the render portion of my code is outside of the while(!al_is_event_queue_empty) from trents code. |
Thomas Fjellstrom
Member #476
June 2000
|
Hm, that first loop will sit and spin at 100% even when there's nothing to do. Otherwise they are functionally equivalent. Both will handle events as they come in. In the bottom loop, it checks for an empty queue to make sure all events are handled, including piled up timer events, before drawing. It's so we always drain the queue, and we get free "Frame dropping" out of the deal, in case the logic and drawing take longer than your timer period, it'll skip frames to catch up. The top loop is similar in that respect, it drains the queue before drawing anything, but it uses an explicit inner loop, instead of making the one loop dual purpose (it drains the events, and handles logic+drawing, where as the inner loop does the event draining and logic, and the outer loop does the drawing). -- |
Trent Gamblin
Member #261
April 2000
|
I actually looked at my code and I guess I do use the second loop most of the time. What I actually have though is more like: while (true) { top: ALLEGRO_EVENT event; al_wait_for_event(queue, &event); // process event if (!al_event_queue_is_empty(queue)) { goto top; } if (render) { // draw } } You can replace the goto with a do-while loop very easily: while (true) { do { ALLEGRO_EVENT event; al_wait_for_event(queue, &event); // process event } while (!al_event_queue_is_empty(queue)); if (render) { // draw } } I think I like that last one the best out of all of them. Just remember to add a timer event source for 1/60 of a second so that the loop keeps pumping even without input.
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
Aside from the two commented lines, that's what I posted earlier. :/ Edgar Reynaldo said: No put it around your event processing loop. do { ALLEGRO_EVENT ev;// implicit al_wait_for_event(queue , &ev);// implicit if (ev.type == ALLEGRO_EVENT_*_*) {/*...do stuff...*/} } while (!al_is_event_queue_empty(queue)); if (render) {draw();render = false;}
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 |
Trent Gamblin
Member #261
April 2000
|
You were right.
|
Mishtiff
Member #15,776
October 2014
|
Thanks for the update. Still having the problem of it not rendering until mouse movement... not sure what to do about it. Occurs after about 10 seconds, only renders if i am moving the mouse constantly, else it never renders, but the game loop is still running. IE: the units are spawning, moving, etc. but the render function never goes until i move the mouse. |
Trent Gamblin
Member #261
April 2000
|
The best way to do that is... 1bool render = false;
2ALLEGRO_TIMER *timer = al_create_timer(1.0/60.0);
3al_register_event_source(queue, al_get_timer_event_source(timer));
4al_start_timer(timer);
5
6// Inside do-while loop...
7
8if (event.type == ALLEGRO_EVENT_TIMER && event.timer.source == timer) {
9 render = true;
10}
11
12// After do-while loop...
13
14if (render) {
15 render = false;
16 // do your drawing
17}
I see in your last code post you're doing rendering where you set render = true. You should put it all after where you have if (render). If that doesn't work, show your loop as it is now.
|
Mishtiff
Member #15,776
October 2014
|
Trent Gamblin said: I see in your last code post you're doing rendering where you set render = true. You should put it all after where you have if (render). If that doesn't work, show your loop as it is now. Currently my render is outside of the loop after it. I did try to put it before the loop, and still had problems. Here is what my code looks like: 1while(!done)
2 {
3 do{
4 ALLEGRO_EVENT ev;
5 al_wait_for_event(event_queue, &ev);
6 //==============================================
7 //GAME UPDATE
8 //==============================================
9 if(ev.type == ALLEGRO_EVENT_TIMER && ev.timer.source == timer)
10 {
11 render = true;
12
13 //=====================
14 //UPDATE FPS
15 //=====================
16
17 if(state == PLAYING)
18 {
19 if(al_current_time() - gameTime >= 1)
20 {
21 gameTime = al_current_time();
22 gameFPS = frames;
23 frames = 0;
24 }
25
26
27 //Spawn More Ships
28 spawner++;
29 if (spawner >= 60)
30 {
31 for(Baseiter = Bases.begin(); Baseiter != Bases.end(); ++Baseiter)
32 {
33 if((*Baseiter)->GetShipCount() > 19) continue; //increase this number to spawn more ships
34 Ship *ship = new Ship();
35 ship->Init();
36 ship->SetPlayerID((*Baseiter)->GetPlayerID());
37 ship->SetX(rand() % 40 + (*Baseiter)->GetX() - 20);
38 ship->SetY(rand() % 40 + (*Baseiter)->GetY() - 20);
39 ship->SetColor((*Baseiter)->GetColor());
40
41 (*Baseiter)->SetShipCount(1); //increase base ship count
42 objects.push_back(ship); //add ship to objects and to ships
43 ships.push_back(ship);
44 }
45 spawner = 0;
46 }
47
48 //used to upgrade ships (VERY BASIC----later will be used after leveling)
49 if(keys[SPACE]) //used to move ships to location of mouse
50 {
51
52 for(Shipiter = ships.begin(); Shipiter != ships.end(); ++Shipiter)
53 {
54 if((*Shipiter)->GetPlayerID() != 1) continue;
55 (*Shipiter)->SetDestX(mousex);
56 (*Shipiter)->SetDestY(mousey);
57 (*Shipiter)->setMoving(true);
58 }
59 }
60 if(keys[W]) //increase ship speed
61 {
62
63 for(Shipiter = ships.begin(); Shipiter != ships.end(); ++Shipiter)
64 {
65 if((*Shipiter)->GetPlayerID() != 1) continue;
66 (*Shipiter)->setSpeed(.05);
67 }
68 }
69
70 if(keys[S]) //increase ship damage
71 {
72
73 for(Shipiter = ships.begin(); Shipiter != ships.end(); ++Shipiter)
74 {
75 if((*Shipiter)->GetPlayerID() != 1) continue;
76 (*Shipiter)->setAttack(5);
77 }
78 std::cout << std::endl;
79 }
80
81 if(keys[A]) //increase ship range
82 {
83
84 for(Shipiter = ships.begin(); Shipiter != ships.end(); ++Shipiter)
85 {
86 if((*Shipiter)->GetPlayerID() != 1) continue;
87 (*Shipiter)->setRange(5);
88 }
89 std::cout << std::endl;
90 }
91
92 if(keys[D]) //increase ship health
93 {
94
95 for(Shipiter = ships.begin(); Shipiter != ships.end(); ++Shipiter)
96 {
97 if((*Shipiter)->GetPlayerID() != 1) continue;
98 (*Shipiter)->setHealth(5);
99 }
100 std::cout << std::endl;
101 }
102
103
104 //Update objects positions/animations and add to quad tree.
105 quad->Clear();
106 for(iter = objects.begin(); iter != objects.end(); ++iter)
107 {
108 (*iter)->Update();
109 if(!(*iter)->GetID() == BASE)
110 quad->AddObject(*iter);
111 }
112
113 //used for collision detection (if this is even somewhat correct) //At the moment, i just randomly move units until there is no collision
114 if(al_is_event_queue_empty(event_queue))
115 {
116 for(Shipiter = ships.begin(); Shipiter != ships.end(); ++Shipiter)
117 {
118 vector<GameObject*> returnedObjects;
119 returnedObjects = quad->GetObjectsAt((*Shipiter)->GetX(), (*Shipiter)->GetY());
120 if(returnedObjects.size() < 2) continue;
121 for(int i = 0; i != returnedObjects.size(); i++)
122 {
123 if((*Shipiter) == returnedObjects[i]) continue;
124 if((*Shipiter)->CheckCollisions(returnedObjects[i]))
125 {
126 returnedObjects[i]->SetX(returnedObjects[i]->GetX() + (-5 + rand() % 10));
127 returnedObjects[i]->SetY(returnedObjects[i]->GetY() + (-5 + rand() % 10));
128 }
129 }
130 }
131 }
132
133
134 //cull the dead
135 for(Shipiter = ships.begin(); Shipiter != ships.end(); )
136 {
137 if(!(*Shipiter)->GetAlive())
138 {
139 Shipiter = ships.erase(Shipiter); //remove from ships
140 }
141 else
142 Shipiter++;
143 }
144 for(iter = objects.begin(); iter != objects.end(); ) //remove from objects and give credit to base that killed
145 {
146 if(! (*iter)->GetAlive())
147 {
148 if((*iter)->GetID() == SHIP)
149 {
150 int id = (*iter)->GetPlayerID();
151 for(Baseiter = Bases.begin(); Baseiter != Bases.end(); Baseiter++)
152 {
153 if((*Baseiter)->GetPlayerID() == id)
154 {
155 (*Baseiter)->SetShipCount(-1);
156 int killer = (*iter)->GetShipKiller();
157 for(Baseiter2 = Bases.begin(); Baseiter2 != Bases.end(); )
158 {
159 if((*Baseiter2)->GetPlayerID() == killer)
160 {(*Baseiter2)->setScore(1); break;}
161 else
162 Baseiter2++;
163 }
164 break;
165 }
166 }
167
168 }
169 (*iter)->Destroy();
170 delete (*iter);
171 iter = objects.erase(iter);
172
173 }
174 else
175 iter++;
176 }
177 }
178 }
179 //==============================================
180 //INPUT
181 //==============================================
182 else if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
183 {
184 switch(ev.keyboard.keycode)
185 {
186 case ALLEGRO_KEY_ESCAPE:
187 done = true;
188 break;
189 case ALLEGRO_KEY_A:
190 keys[A] = true;
191 break;
192 case ALLEGRO_KEY_D:
193 keys[D] = true;
194 break;
195 case ALLEGRO_KEY_W:
196 keys[W] = true;
197 break;
198 case ALLEGRO_KEY_S:
199 keys[S] = true;
200 break;
201 case ALLEGRO_KEY_SPACE:
202 if(state == TITLE)
203 ChangeState(state, PLAYING);
204 else if(state == PLAYING)
205 {
206 keys[SPACE] = true;
207 }
208 else if(state == LOST)
209 ChangeState(state, PLAYING);
210 break;
211 }
212 }
213 else if(ev.type == ALLEGRO_EVENT_KEY_UP)
214 {
215 switch(ev.keyboard.keycode)
216 {
217 case ALLEGRO_KEY_ESCAPE:
218 done = true;
219 break;
220 case ALLEGRO_KEY_A:
221 keys[A] = false;
222 break;
223 case ALLEGRO_KEY_D:
224 keys[D] = false;
225 break;
226 case ALLEGRO_KEY_W:
227 keys[W] = false;
228 break;
229 case ALLEGRO_KEY_S:
230 keys[S] = false;
231 break;
232 case ALLEGRO_KEY_SPACE:
233 keys[SPACE] = false;
234 break;
235 }
236 }
237 else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN)
238 {
239 keys[SPACE] = true;
240 mousex = ev.mouse.x;
241 mousey = ev.mouse.y;
242 }
243 else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP)
244 {
245 keys[SPACE] = false;
246 }
247 } while(!al_is_event_queue_empty(event_queue));
248
249 //==============================================
250 //RENDER
251 //==============================================
252
253 if(render)
254 {
255 render = false;
256 frames++;
257
258
259 //BEGIN PROJECT RENDER================
260 if(state ==TITLE)
261 {}
262 else if(state == PLAYING)
263 {
264 al_draw_textf(font18, al_map_rgb(255, 0, 255), 5, 35, 0, "FPS: %i mouse: %f,%f", gameFPS, mousex, mousey); //display FPS on screen
265
266
267 for(iter = objects.begin(); iter != objects.end(); ++iter)
268 (*iter)->Render();
269
270 //quad->draw(); //used to draw visual for quadrants
271 }
272 else if(state == LOST)
273 {}
274
275 //FLIP BUFFER========================
276 al_flip_display();
277 al_clear_to_color(al_map_rgb(0,0,0));
278 }
279 }
this is my entire while(game running) code. Still having problems with it not doing the render portion after so many units have been spawned. This occurs even if i put the if(render) before the event loop. Any ideas would be excellent. If there is literally anything you see that is inefficient, yell at me. I want criticism to become a more efficient programmer. |
Aikei_c
Member #14,871
January 2013
|
Honestly, I still don't understand how the loop with al_wait_for_event() works. I mean, shouldn't it just halt and do nothing on the al_wait_for_event() line, unless it gets some input? EDIT: Oh well, nevermind, I see he catches a timer event.
EDIT3: Ok, look at what you are doing. You are running all your game code, including collision detection etc. WHILE EVENT QUEUE IS NOT EMPTY. But since your game code can take quite some time, you can receive a new event while running through this loop, so you will have to repeat it again... and again... never reaching your render code. |
Mishtiff
Member #15,776
October 2014
|
al_wait_for_event() sits in this loop until an event is recieved. after its recieved, it removes the event and places it into the ALLEGRO_EVENT ev, that will be executed from that point on. After it reaches the end of the loop, if no new events were placed into the queue, it should break out of the loop and hit the render. As for Edit3: I see your point, but does that mean that i should be placing these things outside of the timer loop the same as the render function? IE: do{ //process collision detection if true //process render if true |
Aikei_c
Member #14,871
January 2013
|
You can do it like this. 1 while(!m_bDone)
2 {
3 m_timeNow = GetTime();
4 m_deltaTime = m_timeNow - m_lastRunTime;
5 if (m_deltaTime < m_oneFrameTime)
6 continue;
7 m_lastRunTime = m_timeNow;
8 ProcessAppMessages();
9 TickEventManager();
10 m_pGameLogic->VOnUpdate(m_deltaTime);
11 m_pIRenderer->VOnRender(m_deltaTime);
12 m_nextTime = m_timeNow+m_oneFrameTime;
13 m_restTime = m_nextTime-GetTime();
14 if (m_restTime > 0)
15 Rest(m_restTime);
16 }
EDIT: Your loop however should work just fine . You can process all your game code if render is true, right before rendering everything. |
Mishtiff
Member #15,776
October 2014
|
Thanks for the help Aikei_c, my game now updates and renders, but it slows down to about ~20-30 frames when it is supposed to be running at 60 fps. I need to figure out how to run the collision detection in a more efficient way. When i remove the collision detection everything runs fine, but once it is back in, it lags it pretty hard. Oddly enough, when i increase the amount of units that can be tested for each quadrant (before splitting into new leafs) the game runs better. If i continue to break the quadrant up at lower numbers (such as, only allowing ~3-10 units per quadrant before splitting) it runs at awful frames. I need to find a good source code that uses this type of collision detection to see how to run it in a more efficient way. When i read about quadtree collision detection, it seemed that most people agreed that it was the way to go in regards to efficiency. Weird that i am having such awful lag due to it (considering that its the only code that could possibly tax the program). |
pkrcel
Member #14,001
February 2012
|
I'd suggest you dive in to profiling your code because seems you can't "debug" the issue further just sectioning the code. It is unlikely that Google shares your distaste for capitalism. - Derezo |
Mishtiff
Member #15,776
October 2014
|
@prkcel As in, Seperating code into different .cpp and .h files? Such as a game.cpp, player.cpp etc? |
Trent Gamblin
Member #261
April 2000
|
Sorry, since this thread is getting long can you post your collision detection again? Maybe we can see where the bottleneck is. EDIT: Mainly the GetObjectsAt and CheckCollisions methods.
|
pkrcel
Member #14,001
February 2012
|
I meant profiling as in using a tool (such as the Visual Studio Debugger suite) that might help in identifying where in code you have bottlenecks. You already know that the collision detection drowns performance, but you don't know which BIT of it. I'm afraid I can't be of much help here, I haven't profiled code since my old time on TRACE32. On the other hand, structuring your code better would help a lot in sharing & understanding for people which might look upon your code....first of all yourself. At the very least, a buch of conveniently placed (as in when calling a fnction or traversing a loop iteration) "debug" printf with timestamps might help. It is unlikely that Google shares your distaste for capitalism. - Derezo |
Aikei_c
Member #14,871
January 2013
|
Mishtiff said: Oddly enough, when i increase the amount of units that can be tested for each quadrant (before splitting into new leafs) the game runs better.
This is because quadtree also takes time to build every tick. If you specify too low number of units per quadrant, it will have to build more quadrants and will take more time. Depending on your number of actors, some quad trees may actually slow down performance instead of improving it. |
|
|