0

This is one of the things that still confuses me about QML / QtQuick: How shall I implement a simple game like pong that uses a loop?

I googled a bit and looked through similar questions here but none of them addressed the following:

  • I want to create a simple game like pong that uses a loop. In this loop first all the objects are updated (in case of pong the ball and the bars) and then everything is rendered. For the rendering part I think QML will do the job once all the properties are set.

  • I want to use QML and QtQick and not QGraphicsScene.

  • I have seen some examples that just use a timer and then adjust the properties, for example this one: https://github.com/NicholasVanSickle/QtQuickTests/blob/master/Pong.qml But is this really the way to do it. In this case you would have the loop that updates the QML properties and the timer as well and I don't understand how the work together.

  • Also there are some game engines that use QML. I would like to know how to use QML within a game loop. For example could you write the game loop in C++ and then have QML on top of it? Or what is the recommended way of doing it. Sadly I could not find this in any of the Qt documentation.

Nils
  • 13,319
  • 19
  • 86
  • 108

2 Answers2

2

You don't need a game loop in QML, the whole thing is event driven and powered by an underlying event loop anyway.

You can readily tap into that, use timers, signals, animations and what not out of the box.

Game loop are locking in nature. And in QML you can only use the main thread. And thou shalt not lock the main thread - it has to spin or your app will stop responding.

dtech
  • 47,916
  • 17
  • 112
  • 190
2

I had a similar question when I first started with Qt and got the same answers you're getting (which are correct). It's a different way of thinking than if you had come from using say, SDL.

I want to add an approach that lets you have some control over the updates. It's been a while since someone shared this with me, but from what I remember, it has something to do with ensuring a consistent update frequency.

Regardless of whether or not it's an improvement over just using a simple timer or not, having some actual code will help get you started. In addition, having the delta (to calculate the position of the ball and paddles) is something you'd have to do yourself, which this code already does for you.

Here's the meat of GameTimer:

void GameTimer::doUpdate()
{
    // Update by constant amount each loop until we've used the time elapsed since the last frame.
    static const qreal delta = 1.0 / mFps;
    // In seconds.
    qreal secondsSinceLastUpdate = mElapsedTimer.restart() * 0.001;
    mRemainder += secondsSinceLastUpdate;
    while (mRemainder > 0) {

        emit updated(delta);

        mDateTime = dateFromSimulatedTime();

        mRemainder -= delta;
        mSimulatedTime += delta;
    }
}

It's used in C++ like this:

void DirectPather::timerUpdated(qreal delta)
{
    QHashIterator<QuickEntity*, DirectPathData> it(mData);
    while (it.hasNext()) {
        it.next();
        QuickEntity *entity = it.key();
        DirectPathData pathData = it.value();
        if (mSteeringAgent->steerTo(entity, pathData.targetPos, delta)) {
            mData.remove(entity);
        }
    }
}

Since this example (quickpather) is QML-based, it has a complex setter for connecting to the timer. If you don't need stuff to be in QML like the example is, you can just create the timer in C++ and connect to its update signal directly wherever necessary:

connect(mTimer, &GameTimer::updated, foo, &MyGameObject::update);
// ...
connect(mTimer, &GameTimer::updated, bar, &MyOtherGameObject::update);

The delta is in seconds (1.0 == one second).

You can take anything you need from the example to help you get started with your game.


To answer some of your questions directly:

I have seen some examples that just use a timer and then adjust the properties, for example this one: https://github.com/NicholasVanSickle/QtQuickTests/blob/master/Pong.qml But is this really the way to do it. In this case you would have the loop that updates the QML properties and the timer as well and I don't understand how the work together.

I wouldn't recommend doing the logic in QML/JavaScript as this game does. C++ is better suited to this (aka faster) than JavaScript. Things like scripting are well suited for JavaScript though.

Also there are some game engines that use QML. I would like to know how to use QML within a game loop. For example could you write the game loop in C++ and then have QML on top of it? Or what is the recommended way of doing it. Sadly I could not find this in any of the Qt documentation.

My "engine" uses C++ for all of the logic (except scripts, which are kept relatively small) and QML for the GUI and also the entities (animations, sprites, etc.).

I don't think there's any documentation about this exact topic (games written in C++ with QML frontends), but there are some QML-based game examples:

Mitch
  • 23,716
  • 9
  • 83
  • 122
  • Thx for such an elaborate answer! I will try it out when I am back home. – Nils Jun 14 '18 at 08:39
  • For a pong game C++ is complete overkill. You can go a long way from pong before hitting QML engine limitations. A proper game engine will be scalable and modular, so you can prototype much quicker in QML, and easily substitute the engine for a C++ based one if the need for better performance is to arise. – dtech Jun 14 '18 at 14:20
  • Yeah, QML is fine for pong, but assuming OP has anything more than a fleeting interest in game development, they'll want to move to C++ eventually when they start tackling bigger projects. I know that if it was me in their position, having the actual code that sets up the timers would really help. – Mitch Jun 15 '18 at 09:49