存储时,TiXmlElement丢失其子元素

时间:2017-05-02 19:49:28

标签: c++ xml tinyxml

我试图为我在c ++中为一个类制作的游戏设置基本的动态对象构造。我几乎让它工作了,但是,我现在设置它的方式要求我从XML文件生成对象。为了动态创建它们而不是一次性创建它们,我试图做的是存储需要在" prefab&中动态生成的对象的初始化数据(在称为初始化器的GAME_OBJECTFACTORY_INITIALIZERS结构中)。 #34;稍后使用的映射,即当需要实例化对象时。

我遇到的问题是TiXmlElement * levelElement是这些初始值设定项的一部分。它被传递到我的对象工厂的Create方法中,以便可以循环子元素以生成相关组件。这适用于静态生成的对象,即除了"箭头"在这种情况下。但是,当我在预制件映射中存储箭头的初始化器时(在初始化器中是levelElement引用),所有levelElement的ChildElements都是NULL,这意味着创建的对象没有任何组件。

我知道有许多活动部件难以简洁地描述,但我会尝试提供与之相关的所有代码。

Arrow的GameAsset XML

<GameAsset name="Arrow"> //read in as "levelElement"
    <Component name="Sprite"/> //read in as "componentElement"
    <Component name="Body" x="0.0f" y="0.0f" angle="0.0f" bodyType = "dynamic"
           objectShape = "rectangle" density = "0.5f" friction = "0.0f"
           restitution = "1.0f" angularDamping = "0.0f" linearDamping = "0.0f"/>
    <Component name="Arrow"/>
</GameAsset>

来自Game.LoadLevel的相关代码(levelElement放入初始值设定项)

    //...

    //Gets the first game asset element as child of the level element
    TiXmlElement* levelElement = (levelConfig.FirstChildElement("Level1"))->FirstChildElement("GameAsset");

    //...

    //Checks each levelElement
    while (levelElement != NULL) {
        //Sets up the shared initializers (others set in ObjectFactory.create())
        GAME_OBJECTFACTORY_INITIALIZERS initializers;
        initializers.levelElement = levelElement;

        //...other stuff added to initializers...

        if (std::string(levelElement->Attribute("name")) != "Arrow") {
            //Creates and initializes the new object with data from XML file, puts it into objects
            objects.push_back(oFactory->create(initializers));
        }
        else {
            //puts arrow in prefabs to be created later
            prefabs[std::string(levelElement->Attribute("name"))] = initializers;
        }

        levelElement = levelElement->NextSiblingElement("GameAsset");
    }

Game.Update(如果事件被触发,告诉objectfactory(oFactory)创建预制箭头)Prefabs.at(&#34; Arrow&#34;)获取初始化器。

//Creates an arrow from prefabs
if (iDevice->GetEventStatus(GAME_ARROW_FIRED)) {
    //When passing levelElement in using initializers here, it loses reference to its children. :(
    objects.push_back(oFactory->create(prefabs.at("Arrow")));
}

最后,为了显示错误的可见位置,这里是ObjectFactory.Create的开头,它尝试从initializers.levelElement获取第一个子元素。

std::shared_ptr<Object> ObjectFactory::create(GAME_OBJECTFACTORY_INITIALIZERS initializers) {

//Gets the first component element of the game asset element
TiXmlElement* componentElement = (initializers.levelElement->FirstChildElement("Component"));

//***Here, componentElement is NULL for an "Arrow." 
// However, it correctly obtains the child for objects that are created
// immediately after levelElement is stored in initializers. 

基本上,我不确定我做错了什么,因为我在这两种情况下都以相同的方式传递levelElement。唯一的区别是对于动态对象,我将初始化器存储在一个映射中,而不是立即将它们传递给ObjectFactory.Create。无论哪种方式,levelElement都存储在初始化程序中。但是,我只是失去了为它预先引用它的孩子的能力:注意,初始化器中的所有其他东西(包括levelElement本身)都是正确的。

有关如何解决此问题或可能导致问题的原因的任何想法?我希望我能够清楚地解释它。非常感谢提前。如果有什么令人困惑的话,请告诉我,我会尝试澄清。

编辑:根据要求,这是此问题的MCVE代码。在这个例子中,它在预制件中存储了Arrow的levelElement,创建了一个&#34; Rock&#34; (将&#34; true&#34;推到createReturns上),然后开始循环更新。在尝试创建箭头后,它会中断。

textXML.xml

<?xml version="1.0" ?>
<Level1>
  <GameAsset name="Arrow">
    <Component name="Component"/>
  </GameAsset>
  <GameAsset name="Rock">
    <Component name="Component"/>
  </GameAsset>
</Level1>

Source.cpp

#include "Game.h"

int main(int argc, char *argv[])
{
    Game* game = new Game;

    std::string levelConfigFile = "testXML.xml";

    game->LoadLevel(levelConfigFile);

    for (;;) {
        game->Update();
    }

    return 0;
}

Game.h

#pragma once

#include <string>
#include <vector>
#include <map>

#include"tinyxml/tinyxml.h"

//Initializers
struct GAME_OBJECTFACTORY_INITIALIZERS
{
    TiXmlElement* levelElement;
};

class Game {
public:
    Game();
    ~Game();

    bool LoadLevel(std::string);
    bool Update();
    bool Create(GAME_OBJECTFACTORY_INITIALIZERS);

private:
    std::map<std::string, GAME_OBJECTFACTORY_INITIALIZERS> prefabs; //<name, initializers>
    std::vector<bool> createReturns;
};

Game.cpp

#include "Game.h"

Game::Game(){}

Game::~Game(){}

bool Game::LoadLevel(std::string levelConfigFile)
{
    TiXmlDocument levelConfig(levelConfigFile.c_str());
    levelConfig.LoadFile();

    TiXmlElement* levelElement = (levelConfig.FirstChildElement("Level1"))->FirstChildElement("GameAsset");

    while (levelElement != NULL) {
        GAME_OBJECTFACTORY_INITIALIZERS initializers;
        initializers.levelElement = levelElement;

        if (std::string(levelElement->Attribute("name")) != "Arrow") {
            createReturns.push_back(Create(initializers));
        }
        else {
            prefabs[std::string(levelElement->Attribute("name"))] = initializers;
        }

        levelElement = levelElement->NextSiblingElement("GameAsset");
    }
    return true;
}

bool Game::Update()
{
    //Creates an arrow on update
    createReturns.push_back(Create(prefabs.at("Arrow")));
    return true;
}

bool Game::Create(GAME_OBJECTFACTORY_INITIALIZERS initializers)
{
    if(initializers.levelElement->FirstChildElement("Component")){
        return true;
    }
    else return false;
}
编辑:我试图重做代码,因此初始化器有一个std :: vector而不是一个TiXmlElement *,而不是给它levelElement,我用levelElements子元素(Components)填充了vector。这并没有解决问题,并且尝试访问这些元素的属性会导致箭头崩溃(仍然可以从Prefabs访问)。

0 个答案:

没有答案