I am making an Sdl game, it\'s 2d shooter. I am using SDL to import surfaces and OpenGL to draw them on the screen (doing so because it works way faster than just SDL). I\'v
Have you tried using something like usleep(50000)
instead of delay(1)
?
This would make your thread sleep for 50 msecs between polling the queue, or equivalently, you would check the queue 20 times per second.
Also, what platform is this on: Linux, Windows?
On Windows you may not have usleep()
, but you can try select()
as follows:
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 50000;
select(0, NULL, NULL, NULL, &tv);
Another suggestion is to try polling in a tight loop until it stops returning events. Once no events are pending, proceed with sleeping for 50 msecs between polls until it starts returning events again.
I'd suggest looking into SDL_EventFilter and the related functions. It's not a polling queue input method, so it doesn't require stalling, although, if I remember correctly, it doesn't happen on the main thread, which may be exactly what you need for performance, but might complicate the code.
If you initialized SDL on GameWorld::GenerateCycles()
's thread and MovementThread
is calling GameWorld::Movement()
then you have a problem:
- Don't call SDL video/event functions from separate threads
I'm not really experienced with SDL or game programming, but here are some random ideas:
Your code:
while (1)
{
while (SDL_PollEvent(&keyevent))
{
switch(keyevent.type)
{
// code to set keyboard state
}
}
// code to calculate movement according to keyboard state
// then act on that movement
}
This means that no matter the fact nothing is happening on your keyboard, you are calculating and setting data.
If setting the data is expensive (hint: synchronized data), then it will cost you even more.
You must wait for an event to happen, instead of the spinning you wrote which causes 100% usage of one processor.
Here's a variation of the event loop I wrote for a test at home:
while(true)
{
// message processing loop
::SDL_Event event ;
::SDL_WaitEvent(&event) ; // THIS IS WHAT IS MISSING IN YOUR CODE
do
{
switch (event.type)
{
// etc.
}
}
while(::SDL_PollEvent(&event)) ;
// re-draw the internal buffer
if(this->m_isRedrawingRequired || this->m_isRedrawingForcedRequired)
{
// redrawing code
}
this->m_isRedrawingRequired = false ;
this->m_isRedrawingForcedRequired = false ;
}
Note : This was single threaded. I'll speak about threads later.
Note 2 : The point about the the two "m_isRedrawing..." boolean is to force redrawing when one of those booleans are true, and when the timer asks the question. Usually, there is no redrawing.
The difference between my code and yours is that at no moment you let the thread "wait".
There is a problem, I guess, with your handling of keyboard events.
Your code:
case SDL_KEYDOWN:
switch(keyevent.key.keysym.sym)
{
case SDLK_LEFT:
x1 = 1;
x2 = 0;
break;
case SDLK_RIGHT:
x1 = 0;
x2 = 1;
break;
// etc.
}
case SDL_KEYUP:
switch(keyevent.key.keysym.sym)
{
case SDLK_LEFT:
x1 = x2 = 0;
break;
case SDLK_RIGHT:
x1 = x2 = 0;
break;
// etc.
}
Let's say You press LEFT, and then RIGHT, then unpress LEFT. What I'd expect is:
In your case, you have:
You're doing it wrong, because:
I'll find the link later, but what you should do is have an array of boolean states for pressed keys. Something like:
// C++ specialized vector<bool> is silly, but...
std::vector<bool> m_aKeyIsPressed ;
You initialize it with the size of available keys:
m_aKeyIsPressed(SDLK_LAST, false)
Then, on key up event:
void MyContext::onKeyUp(const SDL_KeyboardEvent & p_oEvent)
{
this->m_aKeyIsPressed[p_oEvent.keysym.sym] = false ;
}
and on key down:
void MyContext::onKeyDown(const SDL_KeyboardEvent & p_oEvent)
{
this->m_aKeyIsPressed[p_oEvent.keysym.sym] = true ;
}
This way, when you check at regular intervals (and the when you check part is important), you know the exact instantaneous state of the keyboard, and you can react to it.
Threads are cool but then, you must know exactly what you are dealing with.
For example, the event loop thread calls the following method:
MainSurvivor->SetMovementDirection
The resolution (rendering) thread calls the following method:
MainSurvivor->MyTurn(Iterator);
Seriously, are you sharing data between two different threads?
If you are (and I know you are), then you have either:
What I would do instead is communicate the change from one thread to another (via a message to a synchronized queue, for example).
Anyway, threading is an heavy issue, so you should familiarize with the concept before mixing it with SDL and OpenGL. Herb Sutter's blog is a marvelous collection of articles on threads.
What you should do is:
You're obviously using C++ (e.g. void GameWorld::Movement()
), so using 1 or 0 instead of true
or false
will not make your code clearer or faster.