Systems - m1keall1son/ofxMediaSystem GitHub Wiki

Systems in ofxMediaSystem are a bit vague. There's no best practice for using them other than that they are generically stored in a generic std::map<type_id_t,std::shared_ptr<void>> typed hashmap inside ms::SystemManager. A Scene has a SystemManager with a passthrough interface for convenience.

auto mySystem = scene.createSystem<MySystem>(...);
...
if(auto mySystem = scene.getSystem<MySystem>()){
    //do something here
}
...
scene.destroySystem<MySystem>();

Systems are useful for performing operations on a set or multiple sets of components. There are two ways to gain access to components.

  1. independent of their entity relationship via a ms::ComponentMap from scene.getComponents<typename ComponentType>()
  2. intercept the ms::NewComponent<typename ComponentType> event and gain access to the entity involved. Anytime a new component is created, the scene automatically dispatches an event containing the new component and the entity it belongs to.
struct MyComponent {
void update(float delta_time);
int order;
...
};

///////////
///Method 1
///////////

class MySystem {
public:
    MySystem(Scene& scene);
...
private:
    ms::Scene& mScene;
    ms::EventStatus onUpdate(const ms::IEventRef& event);
...
};

...

MySystem::MySystem(Scene& scene):mScene(scene)
{
    mComponents = scene.getComponents<MyComponent>();
    scene.addDelegate<ms::Update>(ms::EventDelegate::create<MySystem,&MySystem::onUpdate>(this));
}

MySystem::~MySystem()
{
    //best practice to remove the delegates on destruction
    mScene.removeDelegate<ms::Update>(ms::EventDelegate::create<MySystem,&MySystem::onUpdate>(this));
}

ms::EventStatus MySystem::onUpdate(const ms::IEventRef& event)
{
    auto update_event = std::static_pointer_cast<ms::Update>(event);
    auto delta_time = update_event->getLastFrameTime();
    auto iter = mComponents.iter();
    //update components by whatever means the system needs
    while(auto component = iter.next()){
        component->update(delta_time);
        //do other things...
    }
    return ms::EventStatus::SUCCESS;
}

///////////
///Method 2
///////////

class MySystem {
public:
    MySystem(Scene& scene);
    ~MySystem();
...
private:
    ms::EventStatus onNewComponent(const ms::IEventRef& event);
    ms::EventStatus onUpdate(const ms::IEventRef& event);
    SomeDataStructure mData;
    ms::Scene& mScene;
...
};

...

MySystem::MySystem(Scene& scene):mScene(scene)
{
    scene.addDelegate<ms::NewComponent<MyComponent>>(ms::EventDelegate::create<MySystem,&MySystem::onNewComponent>(this));
    scene.addDelegate<ms::Update>(ms::EventDelegate::create<MySystem,&MySystem::onUpdate>(this));
}

MySystem::~MySystem()
{
    //best practice to remove the delegates on destruction
    mScene.removeDelegate<ms::NewComponent<MyComponent>>(ms::EventDelegate::create<MySystem,&MySystem::onNewComponent>(this));
    mScene.removeDelegate<ms::Update>(ms::EventDelegate::create<MySystem,&MySystem::onUpdate>(this));
}

ms::EventStatus MySystem::onNewComponent(const ms::IEventRef& event)
{
    auto new_comp = std::static_pointer_cast<ms::NewComponent<MyComponent>>(event);
    auto componentHandle = new_comp->getComponentHandle();
    auto entHandle = new_comp->getEntityHandle();
    
    if(auto myComponent = componentHandle.lock()){
        //this example data structure creates pairs of handles
        //in some order defined by the MyComponent::order int
        mData.insertItem(myComponent->order, componentHandle, entHandle);
    }
    return ms::EventStatus::SUCCESS;
}

ms::EventStatus MySystem::onUpdate(const ms::IEventRef& event)
{
    //iterate the data you've gathered, ignoring the data from the ms::Update event
    //if entities have been destroyed etc. remove their handles from the structure
    auto it = mData.begin();
    auto end = mData.end();
    while(it!=end){
        auto& item = *it; //get the std::pair<std::weak_ptr<MyComponent>, std::weak_ptr<SomeOtherComponent>>
        if(auto comp = item.firs.lock()){ //get a shared_ptr to MyComponent, if its expired...
            //otherwise do something with this component and other components accessed through item.second! hooray
            ++it;
        }else{
            //... it means it one was destroyed, then lets forget about this item
            it = mData.erase(it);
        }
    }
    return ms::EventStatus::SUCCESS;
}
⚠️ **GitHub.com Fallback** ⚠️