如何实现一个系统来显示一个对象的属性//构建一个游戏引擎

时间:2017-03-14 15:33:45

标签: c++ qt vector lambda

我目前正在构建游戏引擎。

UML-图:

[MainWindow]

[CNode]
   [CNode2D]
       [CSprite2D]

每个节点都有自己的属性(例如"名称","宽度","高度"),其中每个node-type有不同的属性。

现在,我想显示我的节点属性(右下角):

My game engine

为了实现这一点,我有一个struct代表

这样的每个属性
struct propertyTemplate {
    propertyTemplate (QString namei, QString valuei, QString expectedi, bool changedi = false) {
        name = namei;
        value = valuei;
        expected = expectedi;
        changed = changedi;
    }

    QString name;
    QString value;
    QString expected; //What the programm expects;
    bool changed = false; //if these are the default values
};

CNode有一个vector of propertyTemplate,它被填入CSprite2D的构造函数

properties.push_back(propertyTemplate("Name", getName(), "string"));
properties.push_back(propertyTemplate("Sprite-link", "", "link"));
properties.push_back(propertyTemplate("Height", "100", "float"));
properties.push_back(propertyTemplate("Width", "100", "float"));
properties.push_back(propertyTemplate("Position X", "0", "float"));
properties.push_back(propertyTemplate("Position Y", "0", "float"));
properties.push_back(propertyTemplate("Rotation", "0", "string"));

当必须显示属性时,我运行此函数:

void MainWindow::listProperties () {
if (ui->treeWidget_2->currentItem()->text(ui->treeWidget_2->columnAt(100)) == "Sprite2D") {
    CSprite2D *sprite = static_cast< CSprite2D* >(getNodeByName(ui->treeWidget_2->currentItem()->text(ui->treeWidget_2->columnAt(0)))); //gets a pointer to the string judging by nam
    if (sprite == NULL) { //if the return value is NULL

    } else {
        int counter = 0; //counter for the while-loop
        //for ( auto momItem :  propertyItems) delete momItem; //item

        ui->treeWidget_3->clear();
        propertyItems.clear();

        while (counter < sprite->properties.size()) {
            propertyTemplate prop = sprite->properties[counter]; //gets the current item in the property-array

            propertyItems.push_back(new QTreeWidgetItem); //gets filled by the while-loop
            propertyItems[propertyItems.size()-1]->setText(0, prop.name); //sets the text of the item
            propertyItems[propertyItems.size()-1]->setText(1, prop.value);//set the text of the other item
            propertyItems[propertyItems.size()-1]->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);;
            ui->treeWidget_3->insertTopLevelItem(ui->treeWidget_3->topLevelItemCount(), propertyItems[propertyItems.size()-1]); //appends the items
            counter ++;
        }
    }
}
}

问题:当用户想要更改属性时,程序真的不知道要调用的setter,因为real properties存储在变量中... propertyTemplate的数组真的很多只是为了显示QTreeWidget内的属性。

我很难说你可以在初始化数组时添加一个函数指针,但我不能,因为指针在函数内部...我也试过一个lambda,但是

properties.push_back(propertyTemplate("Rotation", "0", "string",[&this] () {setName()};));

给了我一个编译错误(因此我更新了propertyTemplate的构造函数,所以不要责怪构造函数;)

我已经和我的橡皮鸭和朋友聊过了,他们都告诉我要用另一种方法,但我无法想到更好的方法。

另外:我是C ++ / Qt的新手,所以我可能只是琐碎错误的受害者。在这种情况下抱歉。

1 个答案:

答案 0 :(得分:1)

我认为你这是错误的做法。你应该真的使用Qt属性系统有很多原因,但主要是那两个:

首先,Qt有MOC--元对象编译器,它为每个对象生成元信息。该信息包含属性的数量,它们的名称等。您可以迭代属性并访问有关它们的详细信息,您可以使用它来通过模型填充属性编辑器。这样它就可以处理任何对象的任意属性,而不是有一些静态配置,你必须返回并为每个新类型或类型更改做。

第二 - 对于Qt属性,您有QObject::property()QObject::setProperty()QVariant协同工作,在大多数情况下,这些属性可以处理类型转换。因此,您只需要拥有属性名称和QVariant保持兼容的值,您不需要知道要调用的调用者等等。这使得获取和设置属性值变得更加容易,无论其类型如何。

您需要查看的课程是QMetaObjectQMetaProperty,可能还有QVariantQAbstractListModel

另外,我发现你正在使用GUI元素进行数据存储,这是一个很大的 NO-NO 。不要将数据放入GUI中,您将来会遇到麻烦。将数据保存在数据层中,并仅从GUI访问该数据。将节点放在向量中,然后为该向量实现模型适配器,然后在GUI中使用model-view-delegate。

所以结构应该是这样的:

node
|
nodes vector                       
|
nodes model <- GUI nodes view <- node delegate  
|
selected node
|
QMetaObject/QMetaProperty query
|
property model <- GUI property view <- property delegate
|
set/get