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)
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:
"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
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]);
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.