Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.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++ 如何使用tinyxml2从XML加载父实体和子实体?_C++_Game Engine - Fatal编程技术网

C++ 如何使用tinyxml2从XML加载父实体和子实体?

C++ 如何使用tinyxml2从XML加载父实体和子实体?,c++,game-engine,C++,Game Engine,我正在使用XML为我正在开发的游戏引擎存储我的级别文件。我最近添加了实体家长制,其中每个实体都有指向其子对象的指针向量,以及指向其父对象的指针。每个实体都有一个方法,该方法接受一个指针来添加父对象,该父对象也会将其添加到父对象的子对象向量中。还有一种方法可以添加一个子对象,该子对象执行相同的操作,但执行相反的操作。问题:我不知道如何从XML加载带有子对象的实体。下面是我想要的典型场景文件的样子(我已经有了加载实体及其组件的代码,只是不知道如何加载它们) 因此,本质上我需要做的是循环所有实体,

我正在使用XML为我正在开发的游戏引擎存储我的级别文件。我最近添加了实体家长制,其中每个实体都有指向其子对象的指针向量,以及指向其父对象的指针。每个实体都有一个方法,该方法接受一个指针来添加父对象,该父对象也会将其添加到父对象的子对象向量中。还有一种方法可以添加一个子对象,该子对象执行相同的操作,但执行相反的操作。问题:我不知道如何从XML加载带有子对象的实体。下面是我想要的典型场景文件的样子(我已经有了加载实体及其组件的代码,只是不知道如何加载它们)



因此,本质上我需要做的是循环所有实体,并使用我的实体管理器的
createEntity
方法(返回指向新实体的指针)创建它们,检查它们在XML中是否有子实体,然后如果有子实体,则使用指向子实体的指针调用父实体的
addChild
方法,或当前实体的
addParent
方法,该方法带有指向父实体的指针。我猜我需要使用递归函数,但是我该如何编写这样的函数呢?

这是一种使用递归的经典任务类型。递归虽然很棘手,但在处理tinyxml时尤其如此——这不是最友好的API

步骤1:A
find
Helper 让我们更友好一些。在所有级别,我们都希望访问所有“实体”元素。让我们制作一个方便的助手,使用TinyXML获取以下内容:

auto find(TiXmlElement const* node, char const* name) {
    std::vector<TiXmlElement const*> found;
    for (
            auto el = node->FirstChildElement(name);
            el;
            el = el->NextSiblingElement(name)
        )
    {
        found.push_back(el);
    }
    return found;
}
步骤3:构建树 听起来很复杂。但实际上,使用上面的
find
helper,我们所需要的只是:

void parse_sub_entities(TiXmlElement const* node, Entity* parent = nullptr) {
    for (auto el : find(node, "entity")) {
        auto entity = parse_entity(el);

        if (parent && entity) {
            entity->addParent(parent);
            parent->addChild(entity);
        }

        parse_sub_entities(el, entity);
    }
}
所有子节点都使用步骤2中的
parse_entity
进行解析,并且只有当我们有父节点时,我们才添加关系

为了完成这一切,我们将递归到子实体中,这次将当前实体作为父实体传递

完整演示 ****⑨


在我所知道的任何在线编译器上都没有安装tinyxml,使用“您可以不使用帮助程序:哇!这比我想象的要多!非常感谢!
void parse_sub_entities(TiXmlElement const* node, Entity* parent = nullptr) {
    for (auto el : find(node, "entity")) {
        auto entity = parse_entity(el);

        if (parent && entity) {
            entity->addParent(parent);
            parent->addChild(entity);
        }

        parse_sub_entities(el, entity);
    }
}
#include <tinyxml.h>
#include <vector>
#include <list>
#include <iostream>
#include <iomanip>

namespace { // helper functions for XML searching
    auto find(TiXmlElement const* node, char const* name) {
        std::vector<TiXmlElement const*> found;
        for (
                auto el = node->FirstChildElement(name);
                el;
                el = el->NextSiblingElement(name)
            )
        {
            found.push_back(el);
        }
        return found;
    }
}

auto scene = R"(<scene>
    <entity name="Parent Entity">
        <transform posx="500" posy="100" scalex="1" scaley="1" rotation="0"/>
        <sprite image="Assets/Sprites/Avatar2.png"/>

        <entity name="Child Entity">
            <transform posx="0" posy="0" scalex="1" scaley="1" rotation="0"/>
            <sprite image="crimson-logo.png"/>
        </entity>
    </entity>

</scene>)";

struct Entity {
    std::string _name;
    Entity* _parent = nullptr;
    std::vector<Entity*> _children;

    explicit Entity(std::string name = "unnamed") : _name(std::move(name)) {}

    void addChild(Entity* e) { _children.push_back(e); }
    void addParent(Entity* e) {
        assert(!_parent || _parent == e);
        _parent = e;
    }
};
struct Mgr {
    std::list<Entity> _entities;
    Entity* createEntity(std::string name) {
        return &_entities.emplace_back(name);
    };
} g_manager;

Entity* parse_entity(TiXmlElement const* node) {
    Entity* entity = g_manager.createEntity(node->Attribute("name"));
    // todo transforms, sprite info etc.
    return entity;
}

void parse_sub_entities(TiXmlElement const* node, Entity* parent = nullptr) {
    for (auto el : find(node, "entity")) {
        auto entity = parse_entity(el);

        if (parent && entity) {
            entity->addParent(parent);
            parent->addChild(entity);
        }

        parse_sub_entities(el, entity);
    }
}

int main() {
    TiXmlDocument doc;
    doc.Parse(scene);

    parse_sub_entities(doc.RootElement());

    std::cout << "Manager has " << g_manager._entities.size() << " entities\n";

    for (auto& e: g_manager._entities) {
        std::cout << "==== Entity: " << std::quoted(e._name) << "\n";
        if (e._parent)
            std::cout << " - has parent " << std::quoted(e._parent->_name) << "\n";
        for (auto child : e._children)
            std::cout << " - has child " << std::quoted(child->_name) << "\n";
    }
}
Manager has 2 entities
==== Entity: "Parent Entity"
 - has child "Child Entity"
==== Entity: "Child Entity"
 - has parent "Parent Entity"