From: Mikko Rasa Date: Sat, 12 Nov 2022 15:49:27 +0000 (+0200) Subject: Provide a way to request events for existing entities and components X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=fce6e7846814e54de9d38000d2f5e2295ee2119e;p=libs%2Fgame.git Provide a way to request events for existing entities and components 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. --- diff --git a/source/game/entity.h b/source/game/entity.h index c4cf83c..8dc5139 100644 --- a/source/game/entity.h +++ b/source/game/entity.h @@ -35,6 +35,7 @@ public: void add_component(Handle); void remove_component(Handle); + const std::vector> &get_components() const { return components; } template Handle get_component(); diff --git a/source/game/eventbus.h b/source/game/eventbus.h index 7da047e..a4de18f 100644 --- a/source/game/eventbus.h +++ b/source/game/eventbus.h @@ -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 void dispatch(const T &) const; + + template + void dispatch_to(EventObserver &, const T &) const; }; @@ -74,6 +78,14 @@ void EventDispatcher::dispatch(const T &event) const h.callback(event); } +template +void EventDispatcher::dispatch_to(EventObserver &obs, const T &event) const +{ + for(const Handler &h: handlers) + if(h.observer==&obs) + h.callback(event); +} + template inline unsigned EventBus::get_event_id() @@ -108,6 +120,14 @@ inline void EventBus::dispatch(const T &event) const static_cast *>(dispatchers[id].dispatcher)->dispatch(event); } +template +inline void EventBus::dispatch_to(EventObserver &obs, const T &event) const +{ + unsigned id = get_event_id(); + if(id *>(dispatchers[id].dispatcher)->dispatch_to(obs, event); +} + } // namespace Msp::Game #endif diff --git a/source/game/eventsource.h b/source/game/eventsource.h index 0856e08..ccb830f 100644 --- a/source/game/eventsource.h +++ b/source/game/eventsource.h @@ -41,6 +41,9 @@ private: public: template void emit(Args &&...) const; + + template + void emit_to(EventObserver &, Args &&...) const; }; @@ -61,6 +64,15 @@ inline void EventSource::emit(Args &&... args) const bus.dispatch(event); } +template +template +inline void EventSource::emit_to(EventObserver &obs, Args &&... args) const +{ + T event(std::forward(args)...); + static_cast &>(*this).dispatch_to(obs, event); + bus.dispatch_to(obs, event); +} + } // namespace Msp::Game #endif diff --git a/source/game/stage.cpp b/source/game/stage.cpp index 8317610..81893e1 100644 --- a/source/game/stage.cpp +++ b/source/game/stage.cpp @@ -35,6 +35,22 @@ void Stage::set_active_camera(Handle c) event_source.emit(active_camera); } +void Stage::synthesize_initial_events(EventObserver &target_observer) +{ + synthesize_initial_events(Handle::from_object(root.get()), target_observer); + if(active_camera) + event_source.emit_to(target_observer, active_camera); +} + +void Stage::synthesize_initial_events(Handle entity, EventObserver &target_observer) +{ + for(Handle c: entity->get_components()) + event_source.emit_to(target_observer, c); + for(Handle e: entity->get_children()) + synthesize_initial_events(e, target_observer); + event_source.emit_to(target_observer, entity); +} + void Stage::tick(Time::TimeDelta dt) { for(const auto &s: systems) diff --git a/source/game/stage.h b/source/game/stage.h index 19e70f4..a046947 100644 --- a/source/game/stage.h +++ b/source/game/stage.h @@ -58,6 +58,11 @@ public: void set_active_camera(Handle); Handle get_active_camera() const { return active_camera; } + void synthesize_initial_events(EventObserver &); +private: + void synthesize_initial_events(Handle, EventObserver &); + +public: void tick(Time::TimeDelta); }; diff --git a/source/gameview/renderer.cpp b/source/gameview/renderer.cpp index 068aa09..ca4e8a9 100644 --- a/source/gameview/renderer.cpp +++ b/source/gameview/renderer.cpp @@ -19,9 +19,7 @@ Renderer::Renderer(Game::Stage &s, GL::View &v): event_observer.observe([this](auto &e){ entity_destroyed(e); }); event_observer.observe([this](auto &e){ camera_changed(e); }); - stage.iterate_objects([this](auto &e){ entity_created({ Game::Handle::from_object(&e) }); }); - if(Game::Handle ac = stage.get_active_camera()) - camera_changed({ ac }); + stage.synthesize_initial_events(event_observer); view.set_camera(&gl_camera); }