【问题标题】:Qt Quick Game LoopQt 快速游戏循环
【发布时间】:2018-06-14 07:21:18
【问题描述】:

对于 QML/QtQuick,我仍然感到困惑的一件事是:我应该如何实现一个像乒乓球这样使用循环的简单游戏?

我用谷歌搜索了一下,在这里查看了类似的问题,但没有一个解决以下问题:

  • 我想创建一个简单的游戏,例如使用循环的乒乓球。在这个循环中,首先更新所有对象(在乒乓球和杠铃的情况下),然后渲染所有内容。对于渲染部分,我认为一旦设置了所有属性,QML 就可以完成这项工作。

  • 我想使用 QML 和 QtQick 而不是 QGraphicsScene。

  • 我见过一些例子,只是使用一个计时器,然后调整属性,例如这个:https://github.com/NicholasVanSickle/QtQuickTests/blob/master/Pong.qml但这真的是这样做的方法吗?在这种情况下,您将拥有更新 QML 属性和计时器的循环,我不明白它们是如何协同工作的。

  • 还有一些使用 QML 的游戏引擎。我想知道如何在游戏循环中使用 QML。例如,您可以在 C++ 中编写游戏循环,然后在其上添加 QML 吗?或者推荐的方法是什么。遗憾的是,我在任何 Qt 文档中都找不到这个。

【问题讨论】:

  • 您链接的示例(在第 3 点)显示了一个 Timer,它在 onTriggered 回调中每 5 毫秒更新一次属性。但我看不到您所说的附加循环。
  • 在 QML 中使用计时器是否正确?如果是,为什么?

标签: qt qml qt-quick


【解决方案1】:

当我第一次开始使用 Qt 时,我遇到了一个similar 的问题,并得到了与您相同的答案(这是正确的)。与使用 SDL 相比,这是一种不同的思维方式。

我想添加一种方法,让您可以控制更新。有人与我分享此内容已有一段时间了,但据我所知,这与确保一致的更新频率有关。

无论它是否比仅使用简单的计时器有所改进,拥有一些实际代码将帮助您入门。此外,获得 delta(计算球和球拍的位置)是您必须自己做的事情,这段代码已经为您做了。

这是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;
    }
}

在 C++ 中使用,如 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);
        }
    }
}

因为这个例子 (quickpather) 是基于 QML 的,所以它有一个复杂的 setter 用于连接到计时器。如果您不需要像示例中那样在 QML 中添加内容,您可以在 C++ 中创建计时器并在必要时直接连接到其更新信号:

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

增量以秒为单位(1.0 == 一秒)。

您可以从示例中获取所需的任何内容来帮助您开始游戏。


直接回答您的一些问题:

我见过一些例子,只是使用一个计时器,然后调整属性,例如这个:https://github.com/NicholasVanSickle/QtQuickTests/blob/master/Pong.qml但这真的是这样做的方法吗?在这种情况下,您将拥有更新 QML 属性和计时器的循环,我不明白它们是如何协同工作的。

我不建议像这个游戏那样在 QML/JavaScript 中执行逻辑。 C++ 比 JavaScript 更适合这个(又名更快)。不过,像脚本这样的东西非常适合 JavaScript。

还有一些使用 QML 的游戏引擎。我想知道如何在游戏循环中使用 QML。例如,您可以在 C++ 中编写游戏循环,然后在其上添加 QML 吗?或者推荐的方法是什么。遗憾的是,我在任何 Qt 文档中都找不到这个。

我的“引擎”使用 C++ 处理所有逻辑(脚本除外,它们相对较小),使用 QML 处理 GUI 和实体(动画、精灵等)。

我认为没有关于这个确切主题的任何文档(用 C++ 编写的带有 QML 前端的游戏),但有一些基于 QML 的游戏示例:

【讨论】:

  • 感谢您提供如此详尽的答案!等我回家试试看。
  • 对于乒乓球游戏,C++ 完全是矫枉过正。在达到 QML 引擎限制之前,您可以远离 pong。一个合适的游戏引擎将是可扩展的和模块化的,因此您可以在 QML 中更快地制作原型,并且如果需要更好的性能,可以轻松地将引擎替换为基于 C++ 的引擎。
  • 是的,QML 非常适合 pong,但假设 OP 对游戏开发的兴趣不仅仅是短暂的兴趣,那么当他们开始处理更大的项目时,他们最终会希望转向 C++。我知道,如果是我在他们的位置上,拥有设置计时器的实际代码会很有帮助。
【解决方案2】:

您不需要 QML 中的游戏循环,整个事情都是由事件驱动的,并且由底层事件循环提供支持。

您可以轻松地利用它,使用计时器、信号、动画以及开箱即用的东西。

游戏循环本质上是锁定的。而在 QML 中,您只能使用主线程。并且您不应锁定主线程 - 它必须旋转,否则您的应用将停止响应。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-03
    • 2014-01-21
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多