Qt 4.x as a game engine


Yannick

Member
Joined
Sep 4, 2008
Messages
345
Age
40
Location
West-Vlaanderen, Belgium
Some interesting links, to show why i am so enthusiastic about this.


All this applies to Qt 4.6, this is the current stable release


For who is this thread?

  • You know the very basics of C++
  • C# / Java programmers that feel like something is missing in C++
  • You might have done a game/demo in another game library like SDL
  • You might have some experience with regular Qt apps and want to try making a game



Glossary


GameObject: ingame representation of a thing (a tank, an NPC)


GameEvent: something that happens in your game universe (tank shoots, talk to NPC)


Qt differences with *regular* C++


Similar to C# classes that always inherit from Object, Qt provides Signals/Slots and Runtime Type Information for classes that inherit from QObject


QObject derived classes support parent/child relations


Signals/Slots mean that function caller/callee connections can be decided at runtime


Runtime type information means, you can query the properties of an object at runtime


Signal / Slot documentation


Basic runtime type information properties documentation


QObject tree documentation


How is this useful for games?


GameObjects tend to be organized in parent/child relations. Setting properties of GameObjects and connection their GameEvents is a very common feature while loading levels, this maps directly to QObject derived classes and can be acomplished with a minimum of code.


The Graphics View Framework


This is the Qt technology that will render your game to the screen. It was originally intended as a way to make free-form UI widgets, overtime so much optimizations have been made it is now perfect for writing entire games. It supports software rendering, OpenGL ES2 and OpenGL2 where applicable on every platform. If needed, you can still talk directly to OpenGL.


Graphics View Documentation


How is this useful for games?


This is for all intents and purposes a full featured 2.5D hardware accelerated scenegraph.


Crossplatform


With some carefull coding around filepaths and constants, your code will compile without modifications on the folowing platforms:


Mac


Linux


Windows


Windows Mobile


S60v5


Show me some code then


Colliding Mice this is the simplest example of how you would organize your code for a game


Asteroids an actual game written in Qt


Sub Attack A more complicated Qt game, using some technologies i haven't talked about yet (Animation and State Machines)


Boxes Demonstration for achieving 2.5D


Interesting reads for advanced users


Some QT labs blogpost i found very interesting:


http://labs.trolltech.com/blogs/2010/01/06/qt-graphics-and-performance-opengl/


http://labs.trolltech.com/blogs/2009/03/13/using-hardware-acceleration-for-graphics


http://labs.trolltech.com/blogs/2010/01/11/qt-graphics-and-performance-the-cost-of-convenience/


http://labs.trolltech.com/blogs/2010/06/29/fun-things-you-can-do-with-the-nokia-qt-sdk/


A video to wet your appetite


This uses Box2D + Tiled Editor + Qt Mobility (for calculating the direction of gravity on the phone)

https://www.youtube.com/embed/QI8xIZqlVtI?feature=oembed

I am going to edit this post as i come across other cool stuff
 
Last edited by a moderator:
Here's a thing I made:


http://blip.tv/file/get/Lulzfish-PlatformerGameSoundTest893.ogg


Firefox and Chrome should open it directly, or you can send the URL to VLC's network open.


It uses Qt to get a window, a custom QWidget for painting, Theora for recording video directly from the QPainter (although this slows down gameplay a lot), SDL_mixer for sound, and Vorbis for recording sound.


It's not really great, I'm not a pro game designer / developer, but QPainter has pretty good performance and it saved me from working with OpenGL. It can also draw vector graphics (used for the bullets), which is not in the stock SDL stuff.


Only thing is, Qt doesn't really support sound. It has Phonon, which handles a lot of media types but doesn't seem to be meant for mixing sound effects, and it has QAudioOutput which can output PCM sound, but you'd have to make your own mixer. Again, I used SDL_mixer, which is a layer over SDL's stock audio. It works pretty well, but the gun takes up like 4 or 5 channels when it's firing, so I'm probably going to write my own mixer that layers over SDL or QAudioOutput. I'll need SDL for joysticks anyway, and the API seems simpler, so I'll probably use that.


So I like this idea.
 
What or who is "OpenGlide"? :D


Seriously though; making games in Qt is soo easy, I only wish that it'd support more of a free-type scene graph.
according to a google search (cause I had never heard of it either)


OpenGLide is a Glide to OpenGL wrapper. It emulates a Voodoo board so you can run old Windows Glide games by translating Glide calls into OpenGL.


From http://openglide.sourceforge.net/


Edit: Since I found no OpenGlide2 info, I assume it was meant to say OpenGL?
 
Last edited by a moderator:
Edit: Since I found no OpenGlide2 info, I assume it was meant to say OpenGL?

now that i googled it some more, it seems i've been calling OpenGL OpenGlide for over a decade, assuming GL stands for Glide, prolly being confused by 3DFXGlide last century ;)


however 3DFXGlide is a dialect of SGI GL, the latter evolved to OpenGL


*sigh* editing post to correct terms
 
Last edited by a moderator:
Last I checked, QGraphicsView can only do 2d, no? iue: all those scene.add() type methods can only accept rect-bounded objects, nothing cube-bounded. It had some level of Z control IIRC (for ordering who is on top), but nothing really fancy there, IIRC? You can't tip an image over, or do 3d object manipulation in QT yet, can you?


jeff
 
Last I checked, QGraphicsView can only do 2d, no? iue: all those scene.add() type methods can only accept rect-bounded objects, nothing cube-bounded. It had some level of Z control IIRC (for ordering who is on top), but nothing really fancy there, IIRC? You can't tip an image over, or do 3d object manipulation in QT yet, can you?


jeff

That sounds correct


I've been calling it 2.5D for that reason. you can use 3D meshes + shaders, but limited to 2D plane + Z ordering. You can tip over an image with a 3D transformation matrix, but it is still defined in 2D plane + Z


see the Boxes demo i linked to.


more 3D stuff is planned for 4.8
 
Last edited by a moderator:
yeah; I looked at it back years ago, and in the end.. writing a basic 2d scene engine is pretty easy; collisions are easy in that space :) Back10 years ago I had an all C engine that coudl render 480x320 every frame, with about 200 sprites (smallish) in the scene, of which some 20 or 30 of them were on-screen; it woudl over-render (larger than the screen) and clip/blit the screen-size (faster than trying to clip mid-sprite), and had no problem doing about 30fps at about 150-200mhz IIRC; going to ASM blitters was a speed increase from there, of course. So we're talking about QT's pretty darned handy classes making easier/faster coding, but still.. not a big deal for 2d.


When QT has scene.addQuake3Model ( Q3Model *foo );


_Then_ we're talking :)


jeff
 
If there's interest I'd suggest making Qt-compatible interfaces for pandora. For instance, Qt doesn't have support for joysticks. It would be nice to have a class that generated events based on game control input. Also simple SDL/OpenAL sound wrapper classes with appropriate slots for sound could be a good idea. I support using Qt for games. Simple ones, at least. I don't know how well the signal/slot stuff scales (though if I understand correctly it should be very efficient).


Lulzfish, that looks like a good start for something metal slug-ish. Would you like to share the code? I'd like to take a look at how you've implemented, for example, platforming collision detection, projectiles and steady scene updating in Qt. Just curious about how other people do those :) . These kind of prototypes are always the best learning material :D


This will be one thread more to follow closely :)
 
If there's interest I'd suggest making Qt-compatible interfaces for pandora.

SDL_Sound and SDL_Joystick should easily be wrapped, it's on my todo list when i need it :D

Just curious about how other people do those :) . These kind of prototypes are always the best learning material :D

I am trying to do without a renderloop, no global updating timer either


each animation should come with it's own timer (so there are no synchronized low FPS updates)


I don't want to be wasting time copying background tiles to the exact same spot they were the frame before, so i am doing a dirty rectangles renderer, possibly using pandora's mountain of memory as buffer memory as well


This is all for extending the life of our overlord the pandora's battery


(craziness in theorie: the animation speeds could scale with pandora Mhz)


Concerning Signal/Slot speed, i believe I read somewhere that if you short circuit 2 classes, each slot raises a signal, connected to the others slot. that this setup runs just shy of 100 million calls / second on an 1.6 GHz Atom
 
Lulzfish, that looks like a good start for something metal slug-ish. Would you like to share the code? I'd like to take a look at how you've implemented, for example, platforming collision detection, projectiles and steady scene updating in Qt. Just curious about how other people do those :) . These kind of prototypes are always the best learning material :D


This will be one thread more to follow closely :)
Yeah, I'll put the code on my Gitorious account some day. Right now, I've forgotten the passphrase to my SSH keys, so I'll have to fix that.


The collision detection was ridiculous. I've probably re-written it 2 or 3 times now, and it uses a custom fixed-point math class. For projectiles, it's continuous, so a bullet can go completely through a wall in one frame, but it will be detected.


I haven't done anything special for like a scene graph. The GameWorld class just has the members, "player", "enemy", and an array of the player's bullets, and it calls collision between which ever members need it, every frame.


The projectiles worried me for a while, but I went with the simplest approach of having an array of 256 particles. They all start out dead. When the player's gun fires, it grabs the first dead particle it can find, moves it to the player's position, and makes it alive. When a bullet hits a wall, it becomes dead (maybe there's a one-frame delay so its tracer still renders) The bullets velocity is added to the player's velocity, so they curve up a little when you jump.


The scene update is handled by a QTimer *somewhere* (I was supposed to figure out where to put it in a big architectural update that I haven't gotten to, maybe I will this weekend). It just fires a signal every 50 milliseconds, which is received by the update() slot of the GameWidget and causes the physics engine to step, and the world to be redrawn. I think they're all in the same thread, so if the game slows down, the QTimer doesn't fire any more signals until the last frame is done. But if the frame takes something like 49 milliseconds to render, the timer should still fire 1 millisecond later, so the delay between frames is consistent.


It's similar to a traditional game loop, except instead of a loop there's an update timer, and you can receive events at any point during the loop.
 
Last edited by a moderator:
The scene update is handled by a QTimer *somewhere*
I wouldn't recommend doing this. Why? Because:

  • Say that your app starts lagging a little, so that every frame takes slightly more than 50 ms to render (or less depending on your wanted FPS) for a short period of time.
  • This means that your QTimer will continue to send out an update event via a signal every 50 ms independent of what happens around it...
  • ...and that your game update method will process new (queued) update events, yet only do so every 60 ms (say).
  • This means that you block the Qt event thread, so even if your application starts running normally again, you'll have an over-saturated event queue because you'll never consume those queued-up events from the lag spike.
  • The result is that since Qt uses one single event thread, you'll get input lag.
  • So if your lag spike increased the rendering time with 10 ms per frame for a total of 4 seconds, every key press you do after that will be delayed by 660 milliseconds, which would be annoying to say the least.


The solution in your situation would be an ugly one IMO. If you really want to continue using a QTimer, you should have a soft mutex of some kind, e.g. a "volatile bool updating;" that gets set every time you enter your update method, and gets unset when you exit. The update method should skip the update completely if the bool is already set when entering the method. This if course assumes that you're using delta times for all your actions (aka that your game doesn't RELY on the fact that it will run with a constant 20 FPS).


A faster method (QTimer lags with up to ±15ms per tick on Windows computers for instance, which makes the game look choppy) would be the classical one: have a loop that runs forever, and include a "sleep" command that eats up any extra unneeded time.
 
I wouldn't recommend doing this.
Disclaimer: I totally forgot the math. It's 50 FPS, 20 milliseconds between each QTimer timeout() and thus each GameWidget::stepWorld() call.


I do have a mutex (not a soft one, a full QMutex, probably backed by the Linux kernel somewhere) that is locked before I start stepping and unlocked after I'm done, and I've run the program many times at 17 FPS, around 59 ms / frame, because of the painfully slow Theora encoding.


There's a debug message that will print if I attempt to lock the mutex twice, yet it doesn't show up.


So, since no problems have occurred (sp?), I guess QTimer won't fire a second time if its last timeout() signal is still being processed.


If it does try to process two steps at once, it would be caught in the mutex and the program would just drop a frame and print a warning.


It might be better to use something loop-based. Would I have to put that in a separate thread, though? I can't have a loop run forever while Qt's main loop is already running forever, unless I tell Qt to process events after each loop...


But that might interfere with the pause menu. I have a pause menu made of QWidgets that's overlaid when the game is paused, so I can't have the update / render loop tied in with Qt's event processing too closely, I might never be unpaused.


I don't use delta time for anything in the game. The physics engine uses discrete collision and no special kind of integration, so changing the timestep might make the player jump a little further or teleport through a wall or something. I'd rather have the game play slowly at low framerates than have the player teleporting around confused. They're not going to enjoy the game either way. And then on a good computer, it's capped at 50 FPS.


It doesn't feel choppy, but I can see it breaking up horizontally, as though something was wrong with v-sync. I'm not sure why. How do LCDs handle v-sync?


It also totally looks like crap on some of the school computers, because their LCDs have a very slow response time between black and grey. It's like on a graphing calculator, everything gets lighter (well, darker, since my scene is grey on black, not black on green) and blurrier when you start moving.
 
Last edited by a moderator:
I believe a timer does not fire, if a previous signal is still on the event loop. Would need to verify this, i think i read you need a QBasicTimer if you do want this.


Timer resolution boils down to the OS scheduler, Windows really likes to prioritize network traffic, linux really likes the same with disk access. Both support 1ms resolution IF nothing else is happening on your pc. Bumping up the priority on windows, changes alot :)


So don't network or don't copy files while gaming, depending on platform


for the v-sync like issue, i would need to read some more docs to know what is going on. maybe Qpainter paints onscreen while you make the calls. if so maybe you can fake double buffering by painting to a pixmap and then painting that to your widget in one call.


anyhow, what painting backend are you using? using the software rasterizer (default behaviour) on X11 for anything that is not a colored rectangle is not recommended, ditto on windows without vendor supplied drivers.
 
I believe a timer does not fire, if a previous signal is still on the event loop. Would need to verify this, i think i read you need a QBasicTimer if you do want this.
No, I don't, then I would have all the horrible problems dflemstr described!


I like the default behavior of QTimer, where it thinks, "You're still busy with the last signal I sent, I'll just keep quiet". It works very well.


I think Qt is supposed to handle double-buffering on its own, but I might try redirecting it to a QPixmap.


I haven't specified a painter backend, so I suspect Qt is using the software rasterizer. I'll try something different, I guess. I can always switch to OpenGL / ES directly.


Edit: I tried "-graphicssystem raster" and "-graphicssystem opengl", they both had pretty terrible flickering and now I think my eyes have adjusted to notice the flicker in the stock graphics system, whatever it is.
 
Last edited by a moderator:
I do all my graphics in a QGraphicsView subclass with a QGLWidget as viewport, never had any flickering


maybe you should look into subclassing QGLWidget
 
Just wanted to pop in and say that this is the kind of conversation I wanted to see. I'll add my 2c later when I'm not supposed to be working.


It would be nice to gather some best practices for Qt game coding. What kind of games can do well with the animation framework? How to get accurate timed updates? Pros and cons of using QTimer/QTimeLine/separate update loop/something else for timing? How to optimize drawing? And so on. There is (at least as far as I have searched) way too few resources for Qt game programming aside from a few trivial-ish examples. Also simple examples (not full games, something like Lulzfish's prototype) for architectural or design-affecting practices could help convey the idea.
 
I do all my graphics in a QGraphicsView subclass with a QGLWidget as viewport, never had any flickering


maybe you should look into subclassing QGLWidget
Yeah, I'm afraid I'll have to switch to OpenGL anyway, to get some GLSL shaders going.


But that can be left until I've modified SDL_mixer to my taste (can't remember if I wrote down my idea anywhere, but I have a way of mixing multiple sounds per channel, so I won't worry about the chain gun taking up 5 channels while it's shooting), made some stuff to spawn enemies, got some different kinds of art, maybe made a game even...
 
Last edited by a moderator:
Just wanted to pop in and say that this is the kind of conversation I wanted to see.

Talking about this stuff motivates me to actually try to finish something for once.

It would be nice to gather some best practices for Qt game coding. What kind of games can do well with the animation framework? How to get accurate timed updates? Pros and cons of using QTimer/QTimeLine/separate update loop/something else for timing? How to optimize drawing? And so on.

I seriously recommend not bothering with all those questions. Just write a couple of QTified classes, gather some artwork. When you actually hit a performance wall, we can all have some fun trying to fix it or annoy some nokia people to write us a better framework :p


If you would take a look at the original Quake3 sources from ID, you wouldn't believe what crap C++ design style they used. You can actually see what they bolted on the engine last minute. There's maybe 3 functions that are true genius. And still it's one of the top games ever.


I spend allot of time *wasted* on exercises in over-engineering, just to give up and start over.


Take a look at the giant list of non working abandoned linux games. Beautiful code, but no game.

There is (at least as far as I have searched) way too few resources for Qt game programming aside from a few trivial-ish examples. Also simple examples (not full games, something like Lulzfish's prototype) for architectural or design-affecting practices could help convey the idea.

If you have released a QT4 based game, you are either a KDE programmer or a Nokia Employee, probably both.


Us mere mortals are just wetting our feet.
 
Back
Top