Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Qt:有效地处理具有;很多像素贴图;?(RTS)_C++_Qt_Qgraphicsview - Fatal编程技术网

C++ Qt:有效地处理具有;很多像素贴图;?(RTS)

C++ Qt:有效地处理具有;很多像素贴图;?(RTS),c++,qt,qgraphicsview,C++,Qt,Qgraphicsview,我目前正在建立一个小型的实时战略2D引擎。而且我想知道如何处理那些最终会聚集在我屏幕上的不断变化的精灵 仅供参考,我的目标不是AAA级,我只是尝试实现一些机器学习方法。因此,我选择了《魔兽争霸2》抛弃软件ISOs,不知羞耻地拍摄了一些图片,并在第一期中陷入困境 正如你在上面看到的,即使是《魔兽争霸2》的简单步兵也有大约50个精灵作为动画。这是很多。它会经常改变精灵。(黑线只是检查我的阿尔法通道是否正确) 因此,最后一个问题是:如何有效地实现不断变化的QGraphicsObject?如何有效地实

我目前正在建立一个小型的实时战略2D引擎。而且我想知道如何处理那些最终会聚集在我屏幕上的不断变化的精灵

仅供参考,我的目标不是AAA级,我只是尝试实现一些机器学习方法。因此,我选择了《魔兽争霸2》抛弃软件ISOs,不知羞耻地拍摄了一些图片,并在第一期中陷入困境

正如你在上面看到的,即使是《魔兽争霸2》的简单步兵也有大约50个精灵作为动画。这是很多。它会经常改变精灵。(黑线只是检查我的阿尔法通道是否正确)

因此,最后一个问题是:如何有效地实现不断变化的QGraphicsObject?如何有效地实现反复更改外观的QGraphicsItem?

我是否只是重载QGraphicsPixmapItem的
paint()
方法,并继续更改屏幕上使用的Pixmap?会不会引起口吃? 我听说有时候,创建一个所有的像素贴图,隐藏它们,并在需要时复制它们是明智的/可能的。(复制比其他操作成本更低) 还有其他明智的想法吗

谢谢你的意见!(关于RTS引擎、复杂度等的教程…)

(我将首先从总体思路开始,接下来是一个可能的Qt实现)

我不知道WCII精灵是如何存储的,但您应该使用精灵表(如果需要,可以自己构建)。与此工作表关联,您将拥有精灵的一些描述,其中至少包含动画列表,对于每个动画,它的标识符/名称以及帧列表

描述这些动画帧的详细程度由您决定,但必须至少包含要显示的精灵表的矩形

作为一个例子,看一看(显然没有优化,但作为一个例子,它是好的:))。下面是相关的(第12行到第39行)。不包括所有动画,但你会明白的

您可以看到“空闲”动画由3帧组成,这些子矩形与精灵表中的前3帧相匹配。与sub-rect关联,此示例中还有2个信息:

  • 持续时间:在转到下一帧之前,帧应显示多长时间
  • 原点:框架的固定点是什么
现在,您将如何在Qt中实现它

动画的描述文件格式完全由您决定,但我推荐一些层次文件格式。因为Qt提供了XML解析器,所以它可能是完美的。如果您习惯于boost,并且更喜欢像JSon这样的轻量级格式,那么可以使用boost.ptree解析不同的XML/JSon文件,并使用一个公共接口从中提取数据

对于图形表示,您必须使用一些类:

  • QPixmap:我们将从中绘制与动画帧匹配的子矩形
  • 用于更新精灵的QTimer
  • 您自己的显示类,比如AnimatedSprite(源自QGraphicsObject,您需要信号/插槽支持)
  • 和一个支持类,比如TimerProxy(从QObject派生)
我将从描述TimerProxy角色开始。它的作用是发送时间更新消息。这是因为Qt图形对象不提供任何类型的“定时”更新(即更新(float dt),其中dt是您最喜欢的时间单位)。您可能想知道为什么我们使用代理类来处理时间。这是为了限制活动QTimer的数量;如果每个动画精灵都有一个这样的计时器,那么最终可能会有大量计时器处于活动状态,这显然是一个很大的禁忌

因此,它有两个作用:

  • 在场景构建时:所有动画精灵都将自己注册到它提供的信号中,我们将其命名为updateTime(int毫秒)
  • 在场景运行时,它将启动一个QTimer,将超时设置为您需要的粒度(您可以继续使用16ms,大约60 fps)。QTimer的signal timeout()将与一个私有插槽相关联,该插槽将触发updateTime(int msecs),其中msecs设置为您之前设置的计时器粒度
现在,解决方案的核心是:动画精灵。此类具有以下角色:

  • 读取并存储所需的动画描述
  • 启动、更新和停止动画
  • 在QGraphics场景中绘制活动精灵的帧
初始化时,您应为其提供以下信息:

  • TimerProxy的实例(由场景或拥有场景的类拥有)。提供此实例时,只需将TimerProxy::updateTime(int)信号连接到私有插槽,该插槽将更新当前动画
  • 包含精灵表的QPixmap
  • 以及动画描述
在运行时,更新方法如下所示:

void AnimatedSprite::paint(QPainter *painter,
                           const QStyleOptionGraphicsItem * /*option*/,
                           QWidget * /*widget*/)
{
    painter->drawImage(mCurrentAnim.mCurrentFrame->mOrigin,
                       mSpriteSheet,
                       mCurrentAnim.mCurrentFrame->mSubRect);
}
  • 一个私有时间更新(int)槽,用于检查当前动画的帧是否应更新,并相应地更新
  • 公共动画方法,如startAnim(const QString&animName),它将更改当前动画,重置经过的时间计数器,并更新当前子矩形以绘制新动画的第一帧
在timeUpdated(int)窗口中,您希望更新经过的时间,并检查它是否应使动画继续到下一帧。如果是这样,只需将当前帧指针更新到新帧即可

最后,要进行渲染,只需重新实现QGraphicsItem::paint(…)方法来绘制当前子矩形,它可能如下所示:

void AnimatedSprite::paint(QPainter *painter,
                           const QStyleOptionGraphicsItem * /*option*/,
                           QWidget * /*widget*/)
{
    painter->drawImage(mCurrentAnim.mCurrentFrame->mOrigin,
                       mSpriteSheet,
                       mCurrentAnim.mCurrentFrame->mSubRect);
}

希望这会有帮助(而且不会太大,哇:s)

我建议使用Qt不是开发游戏的最佳库。你有没有研究过其他的选择?同意