I wanted to write some simple game in android using opengl es but immediately ran into trouble with the main game loop. As I read here: http://developer.android.com/resources/tutorials/opengl/opengl-es10.html the app calls public void onDrawFrame(GL10 gl)
every time it needs to redraw the surface. Or smth like that. My problem was - how to create an update loop that is independent of draw calls. I mean - it can't work like that, I can't update the game logic only when the device (app?) wants to redraw the surface (or am I wrong?).
After some googling I came to a conclusion that I have to create another thread for update loop. But then I had another problem - with one thread taking care of drawing and another one taking care of updating the game logic I didn't know how to make them cooperate. First, they were two separate classes (at least in my implementation) so they couldn't use the same game variables and objects (sprites, timers, different variables, counters and so on... pretty much everything these two classes needed to do their jobs). Now I think I could somehow pack them both into one class. But - second, I needed to synchronize the two threads somehow.
Finally, I came out with this general idea:
public class MyRenderer implements GLSurfaceView.Renderer
with onSurfaceCreated()
method taking care of drawingpublic class UpdateThread implements Runnable
with run()
and update()
methods. run()
was calling update()
method exactly 60 times a second (I wanted a fixed step loop)public class SpritesHolder
used as a container for all the game objects/variables/stuff (like sprites, timers, state variables and so on...) with all the fields public.SpritesHolder
class was a box holding all the needed variables in one place, so MyRenderer
and UpdateThread
classes could access it and use it.As for synchronization - I just did smth like this:
public void update(float delta)
{
synchronized (spritesHolder)
{
// whole method code...
}
}
and:
public void onDrawFrame(GL10 gl)
{
synchronized (spritesHolder)
{
// whole method code...
}
}
so that both threads didn't use the spritesHolder at the same time. So updates were done 60 times per second and drawing took place whenever app (device?) needed.
A lot of talking, sorry, I've almost finished writing this post. ;) So anyway - this (described above) works and I even did write some game based on this 'template' but I think my ideas might be crazy and one can desing it all a whole lot better. I'd be very grateful for all comments and advices.
I didn't use this with OpenGL yet, but UpdateThread should be a TimerTask. In you activity launch it with
new Timer().schedule(new UpdateThread(view), 0, 15); //where view is your view, and 15 is the wait time
in your TimerTask call the view with a Handler. e.g (in your view class)
Handler refreshHandler = new Handler() {
public void handleMessage(Message msg) {
//Handle it; e.g. for canvas invalidate()
}};
In your UpdateThread run method do this:
view.refreshHandler.sendMessage(new Message());
Now it is independent of your gameloop. Furthermore your gameloop should not be in the MainActivity but in a Thread (unidirectional OO).
Your solution probably will work, though it might be suboptimal for performance. If you think about it the render thread and the update thread don't really need to be 100% exclusive.
I recently spent a while thinking about this for my game, and this is what I ended up coming up with (not necessarily better, but just something to think about):
For every renderable object, I have an object owned by the update thread, and another object owned by the rendering thread that is just a plain container that contains instructions for how to draw an object (model matrix, uniform values, meshID, etc). I run through the update thread computing all the final positions and values for my renderable objects, and then I synchronize for a small window where I pass any values that changed during that frame to the objects in the renderable thread. Then as soon as the new information has passed, the frame rendering begins while the next update frame runs simultaneously. Because there's only a small exclusion window it allows the update and draw threads to run simultaneously most of the time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With