Search code examples
c++shared-ptr

Adding std::shared_ptr to a map ruins programs behaviour


I'm sorry that I was not able to think of a better title for my question. I've encountered the following problem:

I have a GameObject class, representing everything possible in the world. It can hold several components defining its behaviour. A GameObject is made renderable as following:

    //GameObjectPtr is std::shared_ptr<GameObject>
    GameObjectPtr skyBoxGameObject = GameObject::makeGameObject();
    skyBoxGameObject->AddComponent<RenderComponent>(skyBox);

In the main Loop, if I now take the RenderComponent from the GameObject as follows:

    planeGameObject->GetComponent<RenderComponent>()->Draw();
    skyBoxGameObject->GetComponent<RenderComponent>()->Draw();

Everything works fine. On the other hand I now want to implement a RenderSystem which stores the GameObjects by ID and hold a reference to them using, again, std::shared_ptr:

    //In RenderSystem:
    std::map<unsigned int, std::shared_ptr<GameObject>> m_gameObjects;

Adding a GameObject to the RenderingSystem is done with:

    void RenderSystem::AddGameObject(std::shared_ptr<GameObject> gameObjectPtr)
    {
      if (m_gameObjects.count(gameObjectPtr->GetId()) > 0)
        throw std::runtime_error("GameObject already registered");
      if (gameObjectPtr->GetComponent<RenderComponent>() == nullptr)
        throw std::runtime_error("GameObject doesn't provide rendercomponent");
      m_gameObjects[gameObjectPtr->GetId()] = gameObjectPtr;
    }

And the drawing is done in this way:

   void RenderSystem::DrawAll() const
   {
     for (auto const & gameObject : m_gameObjects)
     {
       gameObject.second->GetComponent<RenderComponent>()->Draw();
     }
   }

Unfortunately the Objects are not displayed properly. Is there anything wrong with my code or is something copied/moved by adding it to the map that shouldn't be? I've got no clue.

Thanks for your help!


Solution

  • Looking at this code:

    void RenderSystem::DrawAll() const
       {
         for (auto const & gameObject : m_gameObjects)
         {
           gameObject.second->GetComponent<RenderComponent>()->Draw();
         }
       }
    

    The Draw function gets called in the order of gameObject stored in the map m_gameObjects, not in the order that you actually need.

    A vector or deque seems to be better alternative to store the objects but in the order in which you want to draw.