A Guide to Writing Games with QML

My last post on QML had a lot of people asking for an example, as opposed to a general discourse. In my opinion, if you want concrete examples you need to move from blogs into real code. Given that I have written a, hopefully simple, application demonstrating the points in my last post (designing C++ code for QML use), this post (writing games with QML), and the next QML post I plan to write (QML's versioning system, when I'll use version 2 of this example). It's a C++ module containing word-game related logic designed for use from QML, plus a QML game using it, and they can be found in the qt-qml-demo-playground repository in the wordgame and longwords folders, respectively. They are merely intended to provide some concrete examples, and you don't have to play with them before reading the rest of this post (but it is a game, so you can :) ). Now onto the topic of this post, writing games with QML.

QML is designed for smooth application UIs, and it does that job very well. I've found that it is also flexible enough to implement a game inside that UI. So for simple games, where the intuitive and smooth user interface is often as hard as the game part, QML works surprisingly well for creating the whole thing. I'm going to arbitrarily split games into two groups here: Simple games, and Complex games. Simple games being the ones that are 2D, tile-based or with very simple geometry, and with fairly simple logic. Complex games are everything else (3D, or large maps, or with complex geometry or with a lot of collision detection or physics...). Since you can do everything with QML ;) you can obviously construct both types with QML. However, simple games can be easily produced using just QML and JS. If you want to just write simple games for your mobile devices, like Symbian and Meego which will in time have Qt 4.7 shipped on them, QML will likely be sufficient.

Of course, the distinction I've drawn between simple and complex blurs more every day. Those of you who read the recent QML/3D labs blog will be quite confused by my emphasis on 2D. With QML/3D, you will be able to make simple games with 3D visuals (so long as you don't end up having complex 3D logic too such as realistic physics), using just QML and Javascript (QML/JS). You can also make simple games with pre-existing C++ parts, like using the WordGame module, despite my grouping of C++ with complex games. You can even make complex games using my simple game formula, although that would lead to rather messy and long code. Of course in the real world they all seem simple to start with. A key point is that, with QML, you can adapt to increased complexity without having to scrap either your code or your vision to make it work.

I'll now provide a basic guide on how to put QML pieces together to form a simple QML/JS game. For further details try the Samegame tutorial in the Qt Quick docs. Note that this isn't a definitive guide, it's just my rambling of how I've manage to do it so far.

A QML/JS game, at least the ones I've written, have the following structure: A main file, containing a GameBoard element and the surrounding UI, a JavaScript file, containing all the game logic, and some QML elements for the game pieces (and UI elements). The main file contains the whole game UI in QML, including the game board appropriately sized and positioned.

The GameBoard element is usually just an Item type, with a background image as a child. However I give it an id that I use from within the logic file, and often I set the size of the game tiles based on its size. This allows you to make that element size itself to make the most of the available space, and thus be resizeable (but this really doesn't matter on mobile).

The logic file, a .js file with all the game logic, is the imperative logic part. If you try to do something too complex without being a javascript master it gets ugly, and this is the main reason I only recommend pure QML/JS for simple games. Since it does all the imperative stuff, it follows a much more imperative flow than the QML. So I tend to have an init() in the .js called on Component.onCompleted in the main .qml, and a newGame() called from the new game button. You may also want a gameOver state in the UI, and the imperative flow from JS sets these properties (on the GameBoard object, which is preferably the only object it knows about) so that the UI can respond.

The game elements, like the stones in samegame, I prefer to create from the imperative side. This means that, in the newGame() function, you create, initialize and position instances of your game pieces, from the QML files that define their look and feel, and then position them on the game board. They will also need to import the game state logic file, so as to call methods that alter the game state (when they're clicked, for example). Last time I checked, it was safe to save state in the logic JS file, and then when the pieces or main file call the JS file, they operate on the same variables. So as long as you store all the game state in the logic JS file, and manipulate it via functions in that file, then you'll all be operating on the same state from all your various components. An extra advantage of making the game elements separate components is easy theming. You can have a different QML file for a differently themed stone for samegame and all you need to do is switch the file loaded in the JS logic; everything else can still work if you used QML components correctly. These different elements can be more than just different images, but have different animations as well.

So, to sum up, simple games can be easily written in QML/JS by combining the following three things.

  • A central element in the UI to parent all the game items to.
  • QML files defining the look and feel of the game elements, so that they can be fluid in their movements.
  • A JS file with all the imperative logic and game state.

Unfortunately, it's hard to be more specific than that because every game is different. Even QML cannot come up with a brilliant game idea for you. You can check out the Samegame and Snake demos (pictured below, as examples) in the Qt demos for some examples, and the minehunt demo is similar but with the logic in a C++ plugin instead. There is also the WordGame example, mentioned above, which provides a C++ module that you can write your own QML game with as well as one game using it.
Samegame, all in QML and JS
Snake, all in QML and JS

To return to the complex games as a postscript, the way to start writing them in QML is more like the minehunt example. You do the game logic and complex parts in C++, and expose them to a QML front end. For example, you can have the C++ just know where the 'player' sprite is, do all the complex logic manipulating that position to move it, and the QML file could optionally cycle through sprites for a walking animation or not; this gives the designer a lot more flexibility. Unfortunately, there is not so great a dummy data solution for this approach as with other QML UIs. If your game is too complex for QML in the main part (for example, a modern 3D RTS or FPS with thousands of actors and realistic physics), QML would still work great for the UI overlay on top. It's unfortunate that I don't have the time to write an epic RTS just to prove that last point :) .

The new Qt DevNet beta is great, and has forums for both Qt Quick development and game development with Qt. I recommend that comments or questions not specifically about this post go there instead of the comments on labs, as they'll get seen a lot easier and by more people.


Blog Topics:

Comments