c++duplicatesnodesogre3d

Ogre3d having unique node names error


I am working on city generation for a pcg game of mine. I have a for loop which makes 3 cities in random locations, I assign parentIteration to get that "id" for the city and do the same in the for loop where I make a building

for (int i = 0; i < 3; i++)
{
    parentIteration = i;
    std::srand(i);
    _rootNode = GameManager::getSingletonPtr()->getSceneManager()->getRootSceneNode();

    _cityNode = _rootNode->createChildSceneNode("cityNode " + parentIteration);
    generateCity(std::rand() % 10000 + 10, std::rand() % 10000 + 10, std::rand() % 11 +1);
}

building

for (int i = 0; i < _numberOfBuildings; i++)
    {
        childIteration = i;
        printf(" parent  %d and child %d \n", parentIteration, childIteration);
        Ogre::SceneNode* buildingNode  = _cityNode->createChildSceneNode("citybuildingNode"+childIteration+parentIteration );
}

However when I try to launch the game it will crash on creating the second city. Saying it already has a name similar to what it is trying to write. Yet my printf clearly show that the numbers at that point are all unique. Anyone know how to resolve this issue? (added picture for proof of output)

enter image description here


Solution

  • The "itybuildingNode" in the error message suggests that

    "citybuildingNode"+childIteration+parentIteration
    

    is not working quite the way you wanted.

    This is because of a couple things working against you:

    1. "citybuildingNode" is a String Literal, and not a string object. It is litteraly just a bunch of characters in a row terminated by a null character and represented as a const char *, a pointer to that array of characters. It is low-level voodoo, the sort of stuff you might make a string class around. For more information see String Literals

    2. Because it's not a string object, you can't pull any of the usual string object tricks like concatenating with a + and comparing with ==. But because it is a pointer, the compiler interprets + as an attempt to perform pointer arithmetic and reference another location in the array. It compiles, but note how it turned "citybuildingNode" into "itybuildingNode". Oops.

    What this looks like is something like:

    const char* temp = "citybuildingNode"
    _cityNode->createChildSceneNode(temp + childIteration + parentIteration);
    

    which resolves to

    const char* temp = "citybuildingNode"
    _cityNode->createChildSceneNode(&temp[childIteration + parentIteration]);
    
    1. Even if it was a string object, the C++ standard string object, std::string does not allow you to add numbers to strings. It only adds strings together to build a bigger string. To add a number to a std::string, you have to turn the number into a std::string. std::to_string can help you here, but there is a cleaner-looking way to do this with std::stringstream

    Eg:

    std::stringstream nodename("citybuildingNode"); 
    // builds a string stream around the string literal
    nodename << childIteration << parentIteration;
    // writes the numbers into the stream the same way `cin << number;` would
    // turning the number into a string for you
    Ogre::SceneNode* buildingNode  = _cityNode->createChildSceneNode(nodename.str());
    // gets the assembled string from the stringstream 
    // null-terminated string like ogre expects
    

    This gets you started in the right direction, but still allows for collision between child 1 and parent 10 ("citybuildingNode110") and child 11 and parent 0 (also "citybuildingNode110") and similar. So you really want something more like

    nodename << childIteration << '_' << parentIteration;
    

    to force a separator between the two numbers.

    Documentation for std::stringstream.

    There is also another possible nasty. The string we just supplied to ogre will only exist for as long as std::stringstream nodename exists and it will die at the end of the loop that generates it. I do not see anything in a quick perusal of the documentation that says ogre makes its own copy of this string. So play around a bit to make sure that you don't have to store this name somewhere to prevent it from falling out of scope, being destroyed, and leaving ogre with a dangling reference.