我试图为我在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访问)。