Updated useEvent

This commit is contained in:
2023-02-28 22:18:26 -08:00
parent 8e04742d5a
commit 3f361130fd
10 changed files with 135 additions and 46 deletions

View File

@ -8,6 +8,7 @@
#include "asset/Asset.hpp" #include "asset/Asset.hpp"
#include "scene/debug/SceneDebugLine.hpp" #include "scene/debug/SceneDebugLine.hpp"
#include "physics/ScenePhysicsManager.hpp" #include "physics/ScenePhysicsManager.hpp"
#include "state/State.hpp"
namespace Dawn { namespace Dawn {
class DawnGame; class DawnGame;
@ -20,7 +21,7 @@ namespace Dawn {
template<class T> template<class T>
T * _sceneForwardGetComponent(SceneItem *item); T * _sceneForwardGetComponent(SceneItem *item);
class Scene { class Scene : public StateOwner {
private: private:
sceneitemid_t nextId; sceneitemid_t nextId;
std::map<sceneitemid_t, SceneItem*> items; std::map<sceneitemid_t, SceneItem*> items;

View File

@ -76,7 +76,7 @@ namespace Dawn {
/** /**
* Cleanup the SceneItemComponent. * Cleanup the SceneItemComponent.
*/ */
~SceneItemComponent(); virtual ~SceneItemComponent();
}; };

View File

@ -78,7 +78,7 @@ glm::vec3 Camera::getRayDirectionFromScreenSpace(glm::vec2 screenSpace) {
void Camera::onStart() { void Camera::onStart() {
// Render Target // Render Target
useEffect(renderTarget, [&]{ useEffect([&]{
if(renderTarget.previous != nullptr) { if(renderTarget.previous != nullptr) {
renderTarget.previous->eventRenderTargetResized.removeListener( renderTarget.previous->eventRenderTargetResized.removeListener(
this, &Camera::onRenderTargetResize this, &Camera::onRenderTargetResize
@ -94,21 +94,30 @@ void Camera::onStart() {
rt->getWidth(), rt->getHeight() rt->getWidth(), rt->getHeight()
); );
this->event2RenderTargetResized.invoke(rt->getWidth(), rt->getHeight()); this->event2RenderTargetResized.invoke(rt->getWidth(), rt->getHeight());
}); }, renderTarget);
// All regular properties. // All regular properties.
auto cbUpdateProj = [&]{ useEffect([&]{
this->projectionNeedsUpdating = true; this->projectionNeedsUpdating = true;
}; }, {
&fov,
&type,
&orthoLeft,
&orthoRight,
&orthoBottom,
&orthoTop,
&clipNear,
&clipFar
});
useEffect(fov, cbUpdateProj); // useEffect(fov, cbUpdateProj);
useEffect(type, cbUpdateProj); // useEffect(type, cbUpdateProj);
useEffect(orthoLeft, cbUpdateProj); // useEffect(orthoLeft, cbUpdateProj);
useEffect(orthoRight, cbUpdateProj); // useEffect(orthoRight, cbUpdateProj);
useEffect(orthoBottom, cbUpdateProj); // useEffect(orthoBottom, cbUpdateProj);
useEffect(orthoTop, cbUpdateProj); // useEffect(orthoTop, cbUpdateProj);
useEffect(clipNear, cbUpdateProj); // useEffect(clipNear, cbUpdateProj);
useEffect(clipFar, cbUpdateProj); // useEffect(clipFar, cbUpdateProj);
getRenderTarget()->eventRenderTargetResized.addListener(this, &Camera::onRenderTargetResize); getRenderTarget()->eventRenderTargetResized.addListener(this, &Camera::onRenderTargetResize);
} }

View File

@ -55,11 +55,11 @@ void PixelPerfectCamera::onStart() {
assertNotNull(this->camera); assertNotNull(this->camera);
this->updateDimensions(); this->updateDimensions();
useEvent(this->camera->event2RenderTargetResized, [&](float_t w, float_t h){ useEvent([&](float_t w, float_t h){
this->updateDimensions(); this->updateDimensions();
}); }, this->camera->event2RenderTargetResized);
useEffect(scale, [&]{ useEffect([&]{
this->updateDimensions(); this->updateDimensions();
}); }, scale);
} }

View File

@ -42,7 +42,7 @@ void SimpleRenderTargetQuad::onStart() {
// Create quad mesh // Create quad mesh
this->meshHost->mesh.createBuffers(QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT); this->meshHost->mesh.createBuffers(QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT);
useEffect(this->renderTarget, [&]{ useEffect([&]{
if(this->renderTarget.previous != nullptr) { if(this->renderTarget.previous != nullptr) {
this->renderTarget.previous->eventRenderTargetResized.addListener( this->renderTarget.previous->eventRenderTargetResized.addListener(
this, &SimpleRenderTargetQuad::onRenderTargetResized this, &SimpleRenderTargetQuad::onRenderTargetResized
@ -66,7 +66,7 @@ void SimpleRenderTargetQuad::onStart() {
((RenderTarget*)this->renderTarget)->eventRenderTargetResized.addListener( ((RenderTarget*)this->renderTarget)->eventRenderTargetResized.addListener(
this, &SimpleRenderTargetQuad::onRenderTargetResized this, &SimpleRenderTargetQuad::onRenderTargetResized
); );
}); }, this->renderTarget);
// Perform first resize. // Perform first resize.
if(this->renderTarget != nullptr) { if(this->renderTarget != nullptr) {

View File

@ -11,24 +11,40 @@ namespace Dawn {
class StateOwner { class StateOwner {
private: private:
std::vector<IStateEvent*> eventsSubscribed; std::vector<IStateEvent*> eventsSubscribed;
public: public:
/** /**
* Listen for changees to a state property and involke the provided func * Listen for changes to a state property and invoke the provided func
* when the value is changed. * when the value is changed.
* *
* @tparam V The type of the state property.
* @param property Property to listen for affect changees to.
* @param fn The callback to be invoked when the state value changes. * @param fn The callback to be invoked when the state value changes.
* @param property Property to listen for affect changees to.
*/ */
template<class V>
void useEffect( void useEffect(
StateProperty<V> &property, const std::function<void()> &fn,
const std::function<void()> &fn IStateProperty &property
) { ) {
property._effectListners.push_back(fn); property._effectListners.push_back(fn);
} }
/**
* Listen for changes to a set of state properties and invoke the provided
* func when any of their values are changed.
*
* @param fn The callback to be invoked when the state value changes.
* @param property Vector list of properties to listen for changes to.
*/
void useEffect(
const std::function<void()> &fn,
std::vector<IStateProperty*> props
) {
auto itProp = props.begin();
while(itProp != props.end()) {
(*itProp)->_effectListners.push_back(fn);
++itProp;
}
}
/** /**
* Listen for when an event is invoked by a state event. This is intended * Listen for when an event is invoked by a state event. This is intended
* to allow for cross-state-owner communication in a simple and effective * to allow for cross-state-owner communication in a simple and effective
@ -36,16 +52,38 @@ namespace Dawn {
* *
* @tparam F The type of the callback function. * @tparam F The type of the callback function.
* @tparam A The arguments from the state event that are calledback. * @tparam A The arguments from the state event that are calledback.
* @param event The event that is being subscribed to.
* @param fn The function to be inokved on event trigger. * @param fn The function to be inokved on event trigger.
* @param event The event that is being subscribed to.
*/ */
template<typename F, typename... A> template<typename F, typename... A>
void useEvent(StateEvent<A...> &event, F fn) { std::function<void()> useEvent(F fn, StateEvent<A...> &event) {
event._eventListeners[this].push_back(fn);
this->eventsSubscribed.push_back(&event); // Create a listener structure
struct StateEventListener<A...> listener;
listener.listener = fn;
listener.owner = this;
listener.event = &event;
listener.unsubWithParams = [&](struct StateEventListener<A...> listener) {
auto itFound = listener.event->_eventListeners.begin();
while(itFound != listener.event->_eventListeners.end()) {
if(itFound->id == listener.id) {
listener.event->_eventListeners.erase(itFound);
break;
}
++itFound++;
}
};
listener.id = event.stateEventId++;
listener.unsub = std::bind(listener.unsubWithParams, listener);
// Put that listener structure on to the event stack
event._eventListeners.push_back(listener);
this->eventsSubscribed.push_back(&event);
return listener.unsub;
} }
~StateOwner() { virtual ~StateOwner() {
auto it = this->eventsSubscribed.begin(); auto it = this->eventsSubscribed.begin();
while(it != this->eventsSubscribed.end()) { while(it != this->eventsSubscribed.end()) {
(*it)->_stateOwnerDestroyed(this); (*it)->_stateOwnerDestroyed(this);

View File

@ -9,8 +9,28 @@
namespace Dawn { namespace Dawn {
class StateOwner; class StateOwner;
template<typename...A>
class StateEvent;
template<typename...A>
struct StateEventListener {
uint32_t id;
StateOwner *owner;
std::function<void(A...)> listener;
std::function<void(StateEventListener<A...>)> unsubWithParams;
std::function<void()> unsub;
StateEvent<A...> *event;
};
class IStateEvent { class IStateEvent {
protected: protected:
/**
* Received notification from a state owner to let this state event know
* that it wishes to unsubscribe all the event listeners that it may have
* attached to this event.
*
* @param owner State owner that is being disposed.
*/
virtual void _stateOwnerDestroyed(StateOwner *owner) = 0; virtual void _stateOwnerDestroyed(StateOwner *owner) = 0;
friend class StateOwner; friend class StateOwner;
@ -19,12 +39,21 @@ namespace Dawn {
template<typename...A> template<typename...A>
class StateEvent : public IStateEvent { class StateEvent : public IStateEvent {
protected: protected:
uint32_t stateEventId = 0;
void _stateOwnerDestroyed(StateOwner *owner) override { void _stateOwnerDestroyed(StateOwner *owner) override {
this->_eventListeners.erase(owner); auto it = this->_eventListeners.begin();
while(it != this->_eventListeners.end()) {
if(it->owner == owner) {
it = this->_eventListeners.erase(it);
} else {
++it;
}
}
} }
public: public:
std::map<StateOwner*, std::vector<std::function<void(A...)>>> _eventListeners; std::vector<StateEventListener<A...>> _eventListeners;
/** /**
* Invokes the event and emits to all of the listeners. * Invokes the event and emits to all of the listeners.
@ -32,15 +61,22 @@ namespace Dawn {
* @param args Arguments for this event to pass to the listeners. * @param args Arguments for this event to pass to the listeners.
*/ */
void invoke(A... args) { void invoke(A... args) {
auto itListeners = this->_eventListeners.begin(); auto it = this->_eventListeners.begin();
while(itListeners != this->_eventListeners.end()) { while(it != this->_eventListeners.end()) {
auto itLists = itListeners->second.begin(); it->listener(args...);
while(itLists != itListeners->second.end()) { ++it;
(*itLists)(args...);
++itLists;
}
++itListeners;
} }
// auto itListeners = this->_eventListeners.begin();
// while(itListeners != this->_eventListeners.end()) {
// auto itLists = itListeners->second.begin();
// while(itLists != itListeners->second.end()) {
// (*itLists)(args...);
// ++itLists;
// }
// ++itListeners;
// }
} }
friend class StateOwner;
}; };
} }

View File

@ -7,8 +7,13 @@
#include "assert/assert.hpp" #include "assert/assert.hpp"
namespace Dawn { namespace Dawn {
class IStateProperty {
public:
std::vector<std::function<void()>> _effectListners;
};
template<class V> template<class V>
class StateProperty { class StateProperty : public IStateProperty {
private: private:
/** /**
* Method that is invoked every time that the value of this state property * Method that is invoked every time that the value of this state property
@ -31,7 +36,6 @@ namespace Dawn {
public: public:
V _realValue; V _realValue;
std::vector<std::function<void()>> _effectListners;
V previous; V previous;
/** /**

View File

@ -25,7 +25,6 @@ void TicTacToeTile::onStart() {
} }
}; };
useEffect(tileState, cb); useEffect(cb, { &tileState, &hovered });
useEffect(hovered, cb);
cb(); cb();
} }

View File

@ -17,6 +17,8 @@ namespace Dawn {
class TicTacToeScene : public Scene { class TicTacToeScene : public Scene {
protected: protected:
Camera *camera; Camera *camera;
StateProperty<int32_t> age;
StateEvent<int32_t> ageEvent;
void stage() override { void stage() override {
camera = Camera::create(this); camera = Camera::create(this);