I am attempting to create a fast & robust object management system that allows adding, removing and retrieving objects from a "scene". I am trying to wrap my head around the best way to do this regarding ownership and object lifecycle. Code:
main.cpp:
int main()
{
r3d::scene main_scene;
game_object& obj = main_scene.create_object("obj", glm::vec3(0, 0, 0), glm::vec3(-90, 0, -90), glm::vec3(1, 1, 1));
main_scene.remove_object("obj");
return 0;
}
scene.hpp:
namespace r3d
{
class scene
{
public:
scene::scene() { }
game_object& create_object(std::string name,
glm::vec3 position = glm::vec3(0, 0, 0),
glm::vec3 euler_angles = glm::vec3(0, 0, 0),
glm::vec3 scale = glm::vec3(1, 1, 1));
void remove_object(std::string);
game_object& get_object(std::string);
private:
std::map<std::string, r3d::game_object> game_objects;
};
}
scene.cpp:
game_object& scene::create_object(std::string name, glm::vec3 position, glm::vec3 euler_angles, glm::vec3 scale)
{
game_objects.emplace(name, game_object { name, position, euler_angles, scale });
return game_objects[name];
}
void scene::remove_object(std::string name)
{
game_objects.erase(name);
}
game_object& scene::get_object(std::string name)
{
return game_objects[name];
}
game_object.hpp
namespace r3d
{
class game_object
{
public:
std::string name;
game_object() {}
// constructor
game_object(std::string name, glm::vec3 position, glm::vec3 euler_angles, glm::vec3 scale)
: name(name),
position(position),
euler_angles(euler_angles),
scale(scale)
{
printf("New game_object: %s [address: %p]\n", name.c_str(), this);
}
// destructor
~game_object()
{
printf("Delete game_object: %s [address: %p]\n", name.c_str(), this);
}
// copy constructor
game_object(const game_object& source)
: name { source.name },
position { source.position },
euler_angles { source.euler_angles },
scale { source.scale }
{
printf("Copy game_object: %s [from: %p to: %p]\n", source.name.c_str(), &source, this);
}
// move constructor
game_object(game_object&& source)
: name { source.name },
position { source.position },
euler_angles { source.euler_angles },
scale { source.scale }
{
printf("Move game_object: %s [from: %p to: %p]\n", source.name.c_str(), &source, this);
}
protected:
glm::vec3 position;
glm::vec3 euler_angles;
glm::vec3 scale;
};
}
1 Answer 1
the idea being that any other class can access a game_object by name if given a reference to main_scene, even if it doesn't hold a reference to the actual object
You've stated that one of your primary goals is speed. Based on your description above, you can still achieve object lookup and avoid the performance hit of a string dictionary.
One of the easiest ways to do this is to add a header file to the application that defines an enum
of numeric, sequential object IDs. This will allow for much faster lookup, and depending on how you define and load your data, you wouldn't even need a map
- simply a fixed array.
std::map
orstd::unordered_map
(with name as a key) instead of astd::set
? Can't you emplace thegame_object
? \$\endgroup\$#include
s to the code listings and make sure your code compiles and runs correctly. I'd be surprised if this compiles, since std::map operator[] requires a default constructor and game_object doesn't have one. \$\endgroup\$