[Orxonox-commit 1161] r5882 - in code/branches/core5: data/levels src/libraries/core src/modules/objects/eventsystem

landauf at orxonox.net landauf at orxonox.net
Mon Oct 5 21:57:05 CEST 2009


Author: landauf
Date: 2009-10-05 21:57:05 +0200 (Mon, 05 Oct 2009)
New Revision: 5882

Added:
   code/branches/core5/data/levels/events.oxw
Modified:
   code/branches/core5/src/libraries/core/BaseObject.cc
   code/branches/core5/src/libraries/core/BaseObject.h
   code/branches/core5/src/modules/objects/eventsystem/EventDispatcher.cc
   code/branches/core5/src/modules/objects/eventsystem/EventTarget.cc
   code/branches/core5/src/modules/objects/eventsystem/EventTarget.h
Log:
Again some changes in the event-system:
 - Added "mainstate" event-state to BaseObject. It leads to the state which was defined with the mainstate attribute in XML.
 - Support event-forwarding to the mainstate of event-listeners.
 - The "targets" subsection of the EventDispatcher now supports all kinds of objects (not just EventTargets).
 - EventTarget now works in all places of the XML-file, not just in the "targets" section of EventDispatcher.

Added a sample XML-file which explains several aspects of the event-system.

Added: code/branches/core5/data/levels/events.oxw
===================================================================
--- code/branches/core5/data/levels/events.oxw	                        (rev 0)
+++ code/branches/core5/data/levels/events.oxw	2009-10-05 19:57:05 UTC (rev 5882)
@@ -0,0 +1,187 @@
+<?lua
+  include("hudtemplates3.oxo")
+  include("stats.oxo")
+  include("templates/spaceship_assff.oxt")
+  include("templates/spaceship_H2.oxt")
+?>
+
+<Level
+ name         = "Event testing"
+ description  = "A simple level to test the event-system (with comments)"
+>
+  <Scene
+   ambientlight = "0.5, 0.5, 0.5"
+   skybox       = "Orxonox/skypanoramagen1"
+  >
+    <Light type=directional position="0,0,0" direction="0.253, 0.593, -0.765" diffuse="1.0, 0.9, 0.9, 1.0" specular="1.0, 0.9, 0.9, 1.0" />
+
+    <SpawnPoint position="0,-100,0" lookat="0,0,0" roll=180 spawnclass=SpaceShip pawndesign=spaceshipassff />
+
+    <Billboard position=" 300,100,  0" material="Examples/Flare" colour="1.0, 0.0, 0.0" />
+    <Billboard position=" 200,100,  0" material="Examples/Flare" colour="1.0, 0.5, 0.0" />
+    <Billboard position=" 200,100,100" material="Examples/Flare" colour="1.0, 0.5, 0.0" />
+    <Billboard position=" 100,100,  0" material="Examples/Flare" colour="1.0, 1.0, 0.0" />
+    <Billboard position="   0,100,  0" material="Examples/Flare" colour="0.0, 1.0, 0.0" />
+    <Billboard position="-100,100,  0" material="Examples/Flare" colour="0.0, 1.0, 1.0" />
+    <Billboard position="-100,100,100" material="Examples/Flare" colour="0.0, 1.0, 1.0" />
+    <Billboard position="-200,100,  0" material="Examples/Flare" colour="0.0, 0.0, 1.0" />
+    <Billboard position="-300,100,  0" material="Examples/Flare" colour="1.0, 0.0, 1.0" />
+
+
+    <!--
+      Note:
+      All following examples use only one subobject (in nested layouts). But of course you can add more
+      objects. They will all follow the same rules (depending on the example receive, send or pipe events).
+
+      Some examples address objects by name. Those methods always address ALL objects with this name, no
+      matter where they are in the XML-file (before or after the addressing object). Of course this also
+      works with all amounts of objects from zero to infinity. In the examples I used two objects each.
+    -->
+      
+
+    <!-- red -->
+    <!--
+      Standard:
+      Direct event-connection between an event-listener (Billboard) and an event source (DistanceTrigger).
+      Every fired event of the source is mapped to the "visibility" state of the listener.
+
+      This is a 1:1 mapping between event-listener and event-source.
+    -->
+    <Billboard position="300,150,0" material="Examples/Flare" colour="1.0, 1.0, 1.0" visible=0>
+      <events>
+        <visibility>
+          <DistanceTrigger position="300,100,0" distance=25 target="ControllableEntity" />
+        </visibility>
+      </events>
+    </Billboard>
+
+
+    <!-- orange -->
+    <!--
+      EventListener:
+      The EventListener object forwards all events from objects, whose names equal the "event" attribute
+      of the EventListener, to the enclosing object (Billboard).
+      In this case, both triggers have the name "trigger2" and thus both triggers send events to the Billboard.
+
+      The EventListener provides an 1:n mapping between one listener and multiple event-sources.
+    -->
+    <Billboard position="200,150,0" material="Examples/Flare" colour="1.0, 1.0, 1.0" visible=0>
+      <events>
+        <visibility>
+          <EventListener event="trigger2" />
+        </visibility>
+      </events>
+    </Billboard>
+    <DistanceTrigger name="trigger2" position="200,100,0" distance=25 target="ControllableEntity" />
+    <DistanceTrigger name="trigger2" position="200,100,100" distance=25 target="ControllableEntity" />
+
+
+    <!-- yellow -->
+    <!--
+      EventTarget:
+      The EventTarget object forwards the events, received from objects whithin the "events" subsection,
+      to all  objects whose names equal the "name" attribute.
+      In this case, the EventTarget forwards the event from the DistanceTrigger to all listeners with
+      name "bb3".
+
+      The EventTarget provides an n:1 mapping between several listeners and one event-source.
+    -->
+    <Billboard name="bb3" position="100,150,0" material="Examples/Flare" colour="1.0, 1.0, 1.0" visible=0 />
+    <Billboard name="bb3" position="100,150,100" material="Examples/Flare" colour="1.0, 1.0, 1.0" visible=0 />
+    <EventTarget name="bb3">
+      <events>
+        <visibility>
+          <DistanceTrigger position="100,100,0" distance=25 target="ControllableEntity" />
+        </visibility>
+      </events>
+    </EventTarget>
+
+
+    <!-- green -->
+    <!--
+      EventDispatcher:
+      The EventDispatcher catches events from objects in its "events" subsection. Those events are forwared
+      to all objects in the "targets" subsection. The EventDispatcher resembles the EventTarget, but
+      doesn't address objects with the "name" attribute. It rather places them directly inside the "targets"
+      subsection.
+      In this case, the EventDispatcher receives events from the DistanceTrigger and forwards those events
+      to the Billboard object.
+
+      The EventDispatcher provides an n:1 mapping between several targets (listeners) and one event source.
+    -->
+    <EventDispatcher>
+      <targets>
+        <Billboard position="0,150,0" material="Examples/Flare" colour="1.0, 1.0, 1.0" visible=0 />
+      </targets>
+      <events>
+        <visibility>
+          <DistanceTrigger position="0,100,0" distance=25 target="ControllableEntity" />
+        </visibility>
+      </events>
+    </EventDispatcher>
+
+
+    <!-- turquoise -->
+    <!--
+      Combination:
+      By combinding the above three classes, namely EventDispatcher, EventTarget and EventListener, you can
+      extract the event logic completely from the actual objects (Billboards and DistanceTriggers).
+      In this case, both triggers (whith names "trigger5") send events to both Billboards (with names "bb5").
+
+      This combination allows an n:n mapping between event-listeners and event-sources.
+    -->
+    <Billboard name="bb5" position="-100,150,0" material="Examples/Flare" colour="1.0, 1.0, 1.0" visible=0 />
+    <Billboard name="bb5" position="-100,150,100" material="Examples/Flare" colour="1.0, 1.0, 1.0" visible=0 />
+    <DistanceTrigger name="trigger5" position="-100,100,0" distance=25 target="ControllableEntity" />
+    <DistanceTrigger name="trigger5" position="-100,100,100" distance=25 target="ControllableEntity" />
+    <EventDispatcher>
+      <targets>
+        <EventTarget name="bb5" />
+      </targets>
+      <events>
+        <visibility>
+          <EventListener event="trigger5" />
+        </visibility>
+      </events>
+    </EventDispatcher>
+
+
+    <!-- blue -->
+      Mainstate:
+      Apart from the standard states (like activity and visibility), each object can have a mainstate.
+      You can define the mainstate with an xml-attribute: mainstate="state". "state" must be one of the
+      supported boolean states of the object. If the mainstate is set (by default that's not the case),
+      you can send events to the "mainstate" state. This allows you to hide the actually affected state
+      in the event-listener, while the event-source just sends events.
+      Note that this example is exactly like the standard case, but the event is sent to the main-state,
+      which in turn is set to "visibility".
+    <!--
+    -->
+    <Billboard position="-200,150,0" material="Examples/Flare" colour="1.0, 1.0, 1.0" visible=0 mainstate="visibility">
+      <events>
+        <mainstate>
+          <DistanceTrigger position="-200,100,0" distance=25 target="ControllableEntity" />
+        </mainstate>
+      </events>
+    </Billboard>
+
+
+    <!-- violet -->
+    <!--
+      Event forwarding:
+      As a consequence of the mainstate, events can also be sent without any explicit declaration of
+      the targets state. This allows us to forward events from an event-source directly to a bunch of
+      event-listeners. The events are automatically piped into the mainstate. Therefore the listeners
+      have to declare their main-state.
+      In this example, the DistanceTrigger forwards the events to the Billboards main-state (visibility).
+      This does the same like the example above, but instead of piping events backwards from the source
+      into the mainstate of the listener, we're forwarding the event implicitly to the mainstate.
+    -->
+    <DistanceTrigger position="-300,100,0" distance=25 target="ControllableEntity">
+      <eventlisteners>
+        <Billboard position="-300,150,0" material="Examples/Flare" colour="1.0, 1.0, 1.0" visible=0 mainstate="visibility" />
+      </eventlisteners>
+    </DistanceTrigger>
+
+  </Scene>
+</Level>

Modified: code/branches/core5/src/libraries/core/BaseObject.cc
===================================================================
--- code/branches/core5/src/libraries/core/BaseObject.cc	2009-10-05 16:28:21 UTC (rev 5881)
+++ code/branches/core5/src/libraries/core/BaseObject.cc	2009-10-05 19:57:05 UTC (rev 5882)
@@ -117,12 +117,13 @@
         XMLPortParam(BaseObject, "mainstate", setMainStateName, getMainStateName, xmlelement, mode);
 
         XMLPortObjectTemplate(BaseObject, Template, "templates", addTemplate, getTemplate, xmlelement, mode, Template*);
+        XMLPortObject(BaseObject, BaseObject, "eventlisteners", addEventListener, getEventListener, xmlelement, mode);
         
         Element* events = 0;
         if (mode == XMLPort::LoadObject || mode == XMLPort::ExpandObject)
             events = xmlelement.FirstChildElement("events", false);
         else if (mode == XMLPort::SaveObject)
-            ;
+            {}
         if (events)
             this->XMLEventPort(*events, mode);
     }
@@ -136,6 +137,7 @@
     {
         XMLPortEventState(BaseObject, BaseObject, "activity", setActive, xmlelement, mode);
         XMLPortEventState(BaseObject, BaseObject, "visibility", setVisible, xmlelement, mode);
+        XMLPortEventState(BaseObject, BaseObject, "mainstate", setMainState, xmlelement, mode);
         
         this->bRegisteredEventStates_ = true;
     }
@@ -241,6 +243,30 @@
         return 0;
     }
 
+    /**
+        @brief Adds an object which listens to the events of this object.
+    */
+    void BaseObject::addEventListener(BaseObject* listener)
+    {
+        this->eventListenersXML_.insert(listener);
+        listener->addEventSource(this, "mainstate");
+    }
+    
+    /**
+        @brief Returns an event listener with a given index.
+    */
+    BaseObject* BaseObject::getEventListener(unsigned int index) const
+    {
+        unsigned int i = 0;
+        for (std::set<BaseObject*>::const_iterator it = this->eventListenersXML_.begin(); it != this->eventListenersXML_.end(); ++it)
+        {
+            if (i == index)
+                return *it;
+            ++i;
+        }
+        return 0;
+    }
+
     void BaseObject::addEventState(const std::string& name, EventState* state)
     {
         std::map<std::string, EventState*>::const_iterator it = this->eventStates_.find(name);

Modified: code/branches/core5/src/libraries/core/BaseObject.h
===================================================================
--- code/branches/core5/src/libraries/core/BaseObject.h	2009-10-05 16:28:21 UTC (rev 5881)
+++ code/branches/core5/src/libraries/core/BaseObject.h	2009-10-05 19:57:05 UTC (rev 5882)
@@ -156,6 +156,9 @@
             void addEventSource(BaseObject* source, const std::string& state);
             void removeEventSource(BaseObject* source);
             BaseObject* getEventSource(unsigned int index, const std::string& state) const;
+            
+            void addEventListener(BaseObject* listener);
+            BaseObject* getEventListener(unsigned int index) const;
 
             void fireEvent();
             void fireEvent(bool activate);
@@ -207,6 +210,7 @@
             
             std::map<BaseObject*, std::string>  eventSources_;           //!< List of objects which send events to this object, mapped to the state which they affect
             std::set<BaseObject*>               eventListeners_;         //!< List of objects which listen to the events of this object
+            std::set<BaseObject*>               eventListenersXML_;      //!< List of objects which listen to the events of this object through the "eventlisteners" subsection in XML
             std::map<std::string, EventState*>  eventStates_;            //!< Maps the name of the event states to their helper objects
             bool                                bRegisteredEventStates_; //!< Becomes true after the object registered its event states (with XMLEventPort)
     };

Modified: code/branches/core5/src/modules/objects/eventsystem/EventDispatcher.cc
===================================================================
--- code/branches/core5/src/modules/objects/eventsystem/EventDispatcher.cc	2009-10-05 16:28:21 UTC (rev 5881)
+++ code/branches/core5/src/modules/objects/eventsystem/EventDispatcher.cc	2009-10-05 19:57:05 UTC (rev 5882)
@@ -53,13 +53,13 @@
     {
         SUPER(EventDispatcher, XMLPort, xmlelement, mode);
 
-        XMLPortObject(EventDispatcher, EventTarget, "targets", addTarget, getTarget, xmlelement, mode);
+        XMLPortObject(EventDispatcher, BaseObject, "targets", addTarget, getTarget, xmlelement, mode);
     }
 
     void EventDispatcher::processEvent(Event& event)
     {
         for (std::list<EventTarget*>::iterator it = this->targets_.begin(); it != this->targets_.end(); ++it)
-            (*it)->fireEvent(event);
+            (*it)->processEvent(event);
     }
 
     void EventDispatcher::addTarget(EventTarget* target)

Modified: code/branches/core5/src/modules/objects/eventsystem/EventTarget.cc
===================================================================
--- code/branches/core5/src/modules/objects/eventsystem/EventTarget.cc	2009-10-05 16:28:21 UTC (rev 5881)
+++ code/branches/core5/src/modules/objects/eventsystem/EventTarget.cc	2009-10-05 19:57:05 UTC (rev 5882)
@@ -41,6 +41,11 @@
     EventTarget::~EventTarget()
     {
     }
+    
+    void EventTarget::processEvent(Event& event)
+    {
+        this->fireEvent(event);
+    }
 
     void EventTarget::changedName()
     {

Modified: code/branches/core5/src/modules/objects/eventsystem/EventTarget.h
===================================================================
--- code/branches/core5/src/modules/objects/eventsystem/EventTarget.h	2009-10-05 16:28:21 UTC (rev 5881)
+++ code/branches/core5/src/modules/objects/eventsystem/EventTarget.h	2009-10-05 19:57:05 UTC (rev 5882)
@@ -41,6 +41,8 @@
         public:
             EventTarget(BaseObject* creator);
             virtual ~EventTarget();
+            
+            virtual void processEvent(Event& event);
 
             virtual void changedName();
 




More information about the Orxonox-commit mailing list