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.
- independent of their entity relationship via a
ms::ComponentMap
fromscene.getComponents<typename ComponentType>()
- 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;
}