我有一款扫雷游戏,是一种练习QML的方法。
我所面临的问题是取决于网格大小的,无法控制的内存使用量迅速增长(> 700 Mb)。
我将其调整为最大150 * 150(更大的网格会导致崩溃,因为它是win32)。
像这样构建网格(使用Expose 2D C++ Game Board to QML using QAbstractItemModel中的位)(图像用于显示“bomb.png”,即用于显示地雷数量的文本):
Flickable {
id: flickable
width: parent.width
height: parent.height
enabled: false
Column {
id: cols
Repeater {
id: colRepeater
model: mapSize //defined by user
Row {
id: rows
property int y_pos: index
Repeater {
id: rowRepeater
model: mapSize
Tile{
id: tile
x_coord: index
y_coord: y_pos
...
}
}
}
}
}
这是我的Tile对象:
Rectangle {
id: root
...
Rectangle {
id: tileDecoration
visible: false
anchors.centerIn: parent
opacity:0
Image{
id: tileImage
anchors.fill: parent
visible: false
source: ""
}
Text{
id: minesText
anchors.centerIn: parent
}
}
}
编辑:我的问题是如何提高内存使用率?对于扫雷车,我没想到它需要那么多。我还打算在Android上对其进行测试,因此有限的内存使用是一回事。
最佳答案
在查看QtQuick和QML性能时,我的主要原则通常是做得尽可能少。不要创建您现在不需要向用户显示的项目和绑定(bind)。
我无法提供确切的数字(毕竟,实际上并没有一个数字-它取决于项目和硬件),但是我建议QtQuick最适合以个位数显示数千个项目中的数字。屏幕上的时间。不仅如此,资源使用和性能也会开始变得有些粗糙。
不论好坏,QML是一种非常容易表达的语言,它很容易隐藏成本。在其中工作时,您需要在编写此代码时考虑实际情况。您创建的每个Item都是分配的QQuickItem子类,而您设置的每个属性都是一个C++函数调用。对于绑定(bind),JavaScript引擎甚至需要进行该函数调用来设置属性值之前,还需要评估该绑定(bind)(还评估其依赖的其他内容)。
查看您的Flickable代码段,您将看到一个列的重复器,其中包含行的重复器。您说您最多允许使用150x150的网格。让我们对这个数字做一些粗略的数学运算。对于每个图块,您(至少)有两个矩形,一个图像和一个文本项,每个Tile.qml实例总共提供4个项。此外,每个行和一个中继器的固定成本。
这意味着网格上单行的总创建成本为:2 + (4 * mapSize)
项,每行总共602个项。然后,将其乘以150,得出创建该网格的总成本为90,300。
每行也有许多绑定(bind):我在图块中计数9(在图块本身中计数7,不包括有些特殊的“id”分配,再加上两个x和y坐标),另外两个分别用于行和中继器绑定(bind),即每行2 + (9 * mapSize)
绑定(bind)-每行1352个绑定(bind),整个网格的202,800个绑定(bind)。
总而言之,这是一次要使用的非常大量项目和绑定(bind)。
这些项目中的每一项都具有很高的成本-例如,每个项目本身到处都是一百字节,为您在每个项目上创建的绑定(bind)分配了额外的分配,为项目创建以实际获得 yield 的QSGNode实例的分配屏幕,并且使用Repeater也意味着您在JavaScript堆上为每个委托(delegate)分配了一些额外的分配...这全部可能会增加非常大的内存,具体取决于您一次创建多少东西。
因此,要直接回答您的问题,简单的答案是“不要创造太多东西”。我不确定您如何实现这一目标,但是有以下几种可能性:
Image { Text { anchors.centerIn: parent } }
这样的图块GridView
来帮助您,但这会给您的设计带来一些限制。 对于最后一个选项,它会像这样。您需要研究
QQuickItem
的子类化(在C++方面),并具有Q_PROPERTY(QQmlComponent* tileDelegate READ tileDelegate WRITE setTileDelegate NOTIFY tileDelegateChanged)
。在setTileDelegate setter 中,调用QQuickItem::polish
,然后覆盖QQuickItem::updatePolish
,然后在其中创建(或重新放置)所提供tileDelegate组件的实例,该实例从屏幕上当前显示的位置偏移,直到“GameViewThing”再次完全被图块覆盖。我在这里有点含糊-抱歉-但是完整的示例将包含很多代码,所以我希望我已给您足够的信息和指导,使您能够自己开始。
关于c++ - 大网格上的QML内存使用情况,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41609641/