我目前正在构建一个小型实时策略 2D 引擎。和 我想知道如何处理最终会使我的屏幕变得困惑的许多不断变化的 Sprite .
仅供引用,我的目标不是 AAA 级,我只是想实现一些机器学习方法。因此,我选择了魔兽争霸 II 废弃的 ISO,无耻地拍摄了一些图形,并且在第一个问题上遇到了麻烦。
http://img263.imageshack.us/img263/1480/footman.png
正如您在上面看到的,即使是魔兽争霸 II 的简单仆从也有大约 50 个 Sprite 用于动画。这是很多。它会经常改变 Sprite 。 (黑线只是检查我的 alpha channel 是否正确)
因此,最后一个问题:如何有效地实现不断变化的 QGraphicsObject?如何有效地实现重复改变其外观的 QGraphicsItem?
我是否只是让 paint()
过载? QGraphicsPixmapItem 的方法并继续更改屏幕上使用的像素图?会不会引起一些“口吃”?
我听说有时,明智/可能将所有像素图创建一个,隐藏它们,并在需要时复制它们。 (复制比其他操作便宜)
有没有其他聪明的想法?
感谢您提供任何意见! (RTS 引擎教程、复杂性内容等...)
最佳答案
(我会先从总体思路开始,接下来会是一个可能的 Qt 实现)
我不知道 WCII Sprite 是如何存储的,但您应该使用 Sprite 表(如果需要,请自行构建)。与此表相关联,您将获得一些对 Sprite 的描述,其中至少包含动画列表,对于每个动画,它的标识符/名称以及帧列表。
描述这些动画帧的详细程度由您决定,但必须至少包含要显示的 Sprite 表的矩形。
举个例子,看看this sprite sheet (显然没有优化,但举个例子,没关系:))。这是相关的 animations descriptions (第 12 至 39 行)。不包括所有动画,但你会明白的。
您可以看到“空闲”动画由 3 帧组成,这些子矩形与 Sprite 表中的前 3 帧匹配。与 sub-rect 相关联,此示例中还有 2 个信息:
现在,你将如何在 Qt 中实现它?
动画的描述文件格式完全取决于你,但我推荐一些层次文件格式。由于 Qt 提供了 XML 解析器,所以它可以是完美的。如果你习惯于 boost 并且喜欢像 JSon 这样的轻量级格式,你可以使用 boost.ptree 来无差别地解析 XML/JSon 文件,并有一个通用的接口(interface)来从中提取数据。
对于图形表示,您必须使用一些类:
我将首先描述 TimerProxy 角色。它的作用是发送时间更新消息。这是因为 Qt Graphics 对象不提供任何类型的“定时”更新(即 update(float dt) 其中 dt 是您最喜欢的时间单位)。您可能想知道为什么我们使用代理类来处理时间。这是为了限制事件QTimer的数量;如果您为每个 AnimatedSprite 设置了其中一个,您最终可能会有大量计时器处于事件状态,这显然是一个很大的禁忌。
所以它扮演了两个角色:
现在,对于解决方案的核心:AnimatedSprite。这个类有以下作用:
在初始化时,你应该给它以下信息:
在运行时,更新方法将如下所示:
在 timeUpdated(int) 槽中,您想更新耗时,并检查它是否应该使动画进入下一帧。如果是这样,只需将当前帧指针更新为新帧。
最后,要渲染,您只需重新实现 QGraphicsItem::paint(...) 方法来绘制当前子矩形,它可能如下所示:
void AnimatedSprite::paint(QPainter *painter,
const QStyleOptionGraphicsItem * /*option*/,
QWidget * /*widget*/)
{
painter->drawImage(mCurrentAnim.mCurrentFrame->mOrigin,
mSpriteSheet,
mCurrentAnim.mCurrentFrame->mSubRect);
}
希望有帮助(而且不是太大,哇:s)
关于c++ - Qt : Efficiently handle QGraphicsItems that have "lots of pixmaps"? (RTS),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5542352/