]> git.tdb.fi Git - libs/game.git/commitdiff
Provide a way to request events for existing entities and components
authorMikko Rasa <tdb@tdb.fi>
Sat, 12 Nov 2022 15:49:27 +0000 (17:49 +0200)
committerMikko Rasa <tdb@tdb.fi>
Sat, 12 Nov 2022 16:02:52 +0000 (18:02 +0200)
The iterate_objects function does not account for derived classes, so
iterating over all Entity instances might not actually give all entities
on the stage.

source/game/entity.h
source/game/eventbus.h
source/game/eventsource.h
source/game/stage.cpp
source/game/stage.h
source/gameview/renderer.cpp

index c4cf83c119b26bce36fce09ac1238be2bebcd1d2..8dc5139558abeba8a676e6fdac67747c53e26df3 100644 (file)
@@ -35,6 +35,7 @@ public:
 
        void add_component(Handle<Component>);
        void remove_component(Handle<Component>);
+       const std::vector<Handle<Component>> &get_components() const { return components; }
 
        template<typename T>
        Handle<T> get_component();
index 7da047ed1851b76b8bd79b6d903aa8b20c64b47e..a4de18f2bb24c699fb73aea61794b73578cdba77 100644 (file)
@@ -26,6 +26,7 @@ struct EventDispatcher
        { std::erase_if(handlers, [obs](auto &h){ return h.observer==obs; }); }
 
        void dispatch(const T &) const;
+       void dispatch_to(EventObserver &, const T &) const;
 };
 
 
@@ -64,6 +65,9 @@ public:
 
        template<typename T>
        void dispatch(const T &) const;
+
+       template<typename T>
+       void dispatch_to(EventObserver &, const T &) const;
 };
 
 
@@ -74,6 +78,14 @@ void EventDispatcher<T>::dispatch(const T &event) const
                h.callback(event);
 }
 
+template<typename T>
+void EventDispatcher<T>::dispatch_to(EventObserver &obs, const T &event) const
+{
+       for(const Handler &h: handlers)
+               if(h.observer==&obs)
+                       h.callback(event);
+}
+
 
 template<typename T>
 inline unsigned EventBus::get_event_id()
@@ -108,6 +120,14 @@ inline void EventBus::dispatch(const T &event) const
                static_cast<EventDispatcher<T> *>(dispatchers[id].dispatcher)->dispatch(event);
 }
 
+template<typename T>
+inline void EventBus::dispatch_to(EventObserver &obs, const T &event) const
+{
+       unsigned id = get_event_id<T>();
+       if(id<dispatchers.size() && dispatchers[id].dispatcher)
+               static_cast<EventDispatcher<T> *>(dispatchers[id].dispatcher)->dispatch_to(obs, event);
+}
+
 } // namespace Msp::Game
 
 #endif
index 0856e08c452a7abd48b263db1bcb54092e4c75bb..ccb830fb9fb3d4da7c91b265e6002285d9b1d937 100644 (file)
@@ -41,6 +41,9 @@ private:
 public:
        template<typename T, typename... Args>
        void emit(Args &&...) const;
+
+       template<typename T, typename... Args>
+       void emit_to(EventObserver &, Args &&...) const;
 };
 
 
@@ -61,6 +64,15 @@ inline void EventSource<E...>::emit(Args &&... args) const
        bus.dispatch(event);
 }
 
+template<typename... E>
+template<typename T, typename... Args>
+inline void EventSource<E...>::emit_to(EventObserver &obs, Args &&... args) const
+{
+       T event(std::forward<Args>(args)...);
+       static_cast<const EventDispatcher<T> &>(*this).dispatch_to(obs, event);
+       bus.dispatch_to(obs, event);
+}
+
 } // namespace Msp::Game
 
 #endif
index 83176104348538a148d667c9126fff11107e7a8b..81893e1e1ef8c27ca72db42e456c78462a999452 100644 (file)
@@ -35,6 +35,22 @@ void Stage::set_active_camera(Handle<Camera> c)
        event_source.emit<Events::CameraChanged>(active_camera);
 }
 
+void Stage::synthesize_initial_events(EventObserver &target_observer)
+{
+       synthesize_initial_events(Handle<Entity>::from_object(root.get()), target_observer);
+       if(active_camera)
+               event_source.emit_to<Events::CameraChanged>(target_observer, active_camera);
+}
+
+void Stage::synthesize_initial_events(Handle<Entity> entity, EventObserver &target_observer)
+{
+       for(Handle<Component> c: entity->get_components())
+               event_source.emit_to<Events::ComponentCreated>(target_observer, c);
+       for(Handle<Entity> e: entity->get_children())
+               synthesize_initial_events(e, target_observer);
+       event_source.emit_to<Events::EntityCreated>(target_observer, entity);
+}
+
 void Stage::tick(Time::TimeDelta dt)
 {
        for(const auto &s: systems)
index 19e70f416f54b512087f4560c5c06c9527f185c8..a046947f57ad7d0f49e43621f003ac739a4d5713 100644 (file)
@@ -58,6 +58,11 @@ public:
        void set_active_camera(Handle<Camera>);
        Handle<Camera> get_active_camera() const { return active_camera; }
 
+       void synthesize_initial_events(EventObserver &);
+private:
+       void synthesize_initial_events(Handle<Entity>, EventObserver &);
+
+public:
        void tick(Time::TimeDelta);
 };
 
index 068aa09221a6647021e51df8c3cfb5f6e095c72b..ca4e8a91323af48ed16ba2fc2ef2ac0cab9c1e62 100644 (file)
@@ -19,9 +19,7 @@ Renderer::Renderer(Game::Stage &s, GL::View &v):
        event_observer.observe<Game::Events::EntityDestroyed>([this](auto &e){ entity_destroyed(e); });
        event_observer.observe<Game::Events::CameraChanged>([this](auto &e){ camera_changed(e); });
 
-       stage.iterate_objects<Game::Entity>([this](auto &e){ entity_created({ Game::Handle<Game::Entity>::from_object(&e) }); });
-       if(Game::Handle<Game::Camera> ac = stage.get_active_camera())
-               camera_changed({ ac });
+       stage.synthesize_initial_events(event_observer);
 
        view.set_camera(&gl_camera);
 }