开发者

Templates and runtime component loading in a component-based game engine

Suppose I have an component based game engine, and in that engine I have an object that stores a repository of properties in a form of a stl map and can be accessed through the object access() method, which is a templated call so you can access and store any type of data into the repository, eg:

class component {
    private:
        object * parent;

    public:
        component() : parent(0) { }
        void setparent(object * p) { parent = p; }
        virtual void tick() = 0;
}

class object {
    private:
        std::list compipeline;

    public:
        template<typename prop_t>
            access(std::string propname) {
                static std::map<std::string, prop_t> repository;
                return repository;
            }

        void attach(component * c) {
            compipelane.push_back(c);
            c->setparent(this);
        }
};

In this schema, components will call something like

parent.access<double>("health) = 0;

Thats 开发者_C百科fine so far but suppose I want to support dynamic loading of components. I know that templates are resolved in compile time, then all code for access() calls like the one above will be generated when my engine code is compiled. But then I develop a component and compile it as a loadable shared library that does an parent.access("damage"), eg:

class health : public component {
    public:
        health(object & parent) : component(parent) { }
        virtual void tick() {
            double damage = parent.access<double>("damage");
            parent.access<double>("health") -= damage;
            parent.access<double>("damage") = 0;
        }
}

Well then begins my sea of questions and doubts: Will this code compile as a shared library? If yes, what will happen when I load it at runtime and plug in a already created and populated with other components object? Suppose other components that already made the access<double>(...) call, will the map be the same?

Suppose the component also had a type created, like struct position { int x,y; } that was not defined before so this code hasn't been compiled in the main engine, what will happen in access<position>(...) in this recently-plugged component?

Sorry about the big question, but its a big question in my head also. I am fairly familiar with C++ but still understanding how templates works...

Does anybody have experience with this that could enlighten me?

Also I feel that a static std::map inside a function call is not the best approach but I cannot think of another that will let me create spans of different property repositories based on a call...

Thank you!


Besides of the wrong signature of access in your code, it all boils down to how your platform deals with instantiating global objects from shared libraries. As I see it, you will end up with different instances of std::map<std::string, Whatever> per library loaded into process...


Doing that is fine. In fact because of link order issues and construction order issues you want to have your templatized container as a static in a function. The rules state that all static objects must be created before the first function is called. I use a function called GetRegistry that only holds the registry since multiple functions cannot access other functions statics. So you can have something like this:

class GameWorld
{
    template <typename T>
    T& GetRegistry
    {
        static T registry;
        return registry;
    }

public:
    template <typename T>
    void Add(const T& gameThing)
    {
        GetRegistry<T>().push_back(gameThing);
    }

    template <typename T>
    void Update()
    {
        for_each(GetRegistry<T>().begin(), GetRegitry<T>.end(), Render);
    }
};

void main()
{
    GameWorld world;

    Animal cow;
    Soldier sniper;
    Soldier cook;

    world.Add(cow);
    world.Add(sniper);
    world.Add(cook);

    world.Update<Animal>();
    world.Update<Soldier>();
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜