Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/dockingsystem2/src/modules/objects/triggers/DistanceMultiTrigger.cc @ 8804

Last change on this file since 8804 was 8206, checked in by dafrick, 14 years ago

Extending DistanceTrigger (both the normal and the MultiTrigger version). DistanceTriggerBeacons, can now also be used to exclude specific objects from triggering a DistanceTrigger.
Beware: The syntax for the DistanceTrigger, used with a DistanceTriggerBeacon has changed.
It was: <DistanceTrigger target="DistanceTriggerBeacon" targetname="someBeacon" />
And is now: <DistanceTrigger target="WhateverTargetYouWantYourTriggerToReactTo" beaconMode="identify" targetname="someBeacon" />
Consult the documentation in DistanceMultiTrigger for it's specific usage, the DistanceTrigger works analogously.

  • Property svn:eol-style set to native
File size: 11.1 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Damian 'Mozork' Frick
24 *   Co-authors:
25 *      ...
26 *
27*/
28
29/**
30    @file DistanceMultiTrigger.cc
31    @brief Implementation of the DistanceMultiTrigger class.
32    @ingroup MultiTrigger
33*/
34
35#include "DistanceMultiTrigger.h"
36
37#include "core/CoreIncludes.h"
38#include "core/XMLPort.h"
39
40#include "DistanceTriggerBeacon.h"
41
42namespace orxonox
43{
44
45    /*static*/ const std::string DistanceMultiTrigger::beaconModeOff_s = "off";
46    /*static*/ const std::string DistanceMultiTrigger::beaconModeIdentify_s = "identify";
47    /*static*/ const std::string DistanceMultiTrigger::beaconModeExlcude_s = "exclude";
48   
49    CreateFactory(DistanceMultiTrigger);
50
51    /**
52    @brief
53        Default Constructor. Registers the object and initializes default values.
54    */
55    DistanceMultiTrigger::DistanceMultiTrigger(BaseObject* creator) : MultiTrigger(creator), beaconMask_(NULL)
56    {
57        RegisterObject(DistanceMultiTrigger);
58
59        this->distance_ = 100.0f;
60        this->setBeaconModeDirect(distanceMultiTriggerBeaconMode::off);
61        this->targetName_ = "";
62    }
63
64    /**
65    @brief
66        Destructor.
67    */
68    DistanceMultiTrigger::~DistanceMultiTrigger()
69    {
70        if(this->beaconMask_ != NULL)
71            delete this->beaconMask_;
72    }
73
74    /**
75    @brief
76        Method for creating a DistanceMultiTrigger object through XML.
77    */
78    void DistanceMultiTrigger::XMLPort(Element& xmlelement, XMLPort::Mode mode)
79    {
80        SUPER(DistanceMultiTrigger, XMLPort, xmlelement, mode);
81
82        XMLPortParam(DistanceMultiTrigger, "distance", setDistance, getDistance, xmlelement, mode);
83        XMLPortParam(DistanceMultiTrigger, "beaconMode", setBeaconMode, getBeaconMode, xmlelement, mode);
84        XMLPortParam(DistanceMultiTrigger, "targetname", setTargetName, getTargetName, xmlelement, mode);
85    }
86
87    /**
88    @brief
89        This method is called by the MultiTrigger to get information about new trigger events that need to be looked at.
90
91        In this implementation we iterate through all possible objects and check whether the fact that they are in range or not has changed and fire and hand a state ofer to the MultiTrigger if so.
92    @return
93        Returns a pointer to a queue of MultiTriggerState pointers, containing all the necessary information to decide whether these states should indeed become new states of the MultiTrigger.
94    */
95    std::queue<MultiTriggerState*>* DistanceMultiTrigger::letTrigger(void)
96    {
97
98        std::queue<MultiTriggerState*>* queue = NULL;
99
100        // Check for objects that were in range but no longer are. Iterate through all objects, that are in range.
101        for(std::map<WorldEntity*, WeakPtr<WorldEntity>* >::iterator it = this->range_.begin(); it != this->range_.end(); )
102        {
103            WorldEntity* entity = it->second->get();
104            WorldEntity* key = it->first;
105            it++; // Incrementing the iterator in advance, since we don't need the current anymore and we potentially are going to delete the current element thus invalidating the iterator.
106            // If the entity no longer exists.
107            if(entity == NULL)
108            {
109                this->removeFromRange(key);
110                continue;
111            }
112
113            Vector3 distanceVec = entity->getWorldPosition() - this->getWorldPosition();
114            // If the object is no longer in range.
115            if (distanceVec.length() > this->distance_)
116            {
117                // If for some reason the entity could not be removed.
118                if(!this->removeFromRange(key))
119                    continue;
120
121                // If no queue has been created, yet.
122                if(queue == NULL)
123                    queue = new std::queue<MultiTriggerState*>();
124
125                // Create a state and append it to the queue.
126                MultiTriggerState* state = new MultiTriggerState;
127                state->bTriggered = false; // Because the entity went out of range.
128                state->originator = entity;
129                queue->push(state);
130            }
131        }
132
133        // Check for new objects that are in range
134        ClassTreeMask targetMask = this->getTargetMask();
135        if(this->beaconMode_ == distanceMultiTriggerBeaconMode::identify)
136            targetMask = *this->beaconMask_;
137
138        for(ClassTreeMaskObjectIterator it = targetMask.begin(); it != targetMask.end(); ++it)
139        {
140            WorldEntity* entity = static_cast<WorldEntity*>(*it);
141
142            // If the DistanceMultiTrigger is in identify mode and the DistanceTriggerBeacon attached to the object has the wrong name we ignore it.
143            if(this->beaconMode_ == distanceMultiTriggerBeaconMode::identify)
144            {
145                if(entity->getName() != this->targetName_)
146                    continue;
147                // If the object, the DistanceTriggerBeacon is attached to, is not a target of this DistanceMultiTrigger.
148                else if(this->getTargetMask().isExcluded(entity->getParent()->getIdentifier()))
149                    continue;
150            }
151           
152            // If the DistanceMultiTrigger is in exclude mode and the DistanceTriggerBeacon attached to the object has the right name, we ignore it.
153            if(this->beaconMode_ == distanceMultiTriggerBeaconMode::exclude)
154            {
155               
156                const std::set<WorldEntity*> attached = entity->getAttachedObjects();
157                bool found = false;
158                for(std::set<WorldEntity*>::const_iterator it = attached.begin(); it != attached.end(); it++)
159                {
160                    if((*it)->isA(ClassIdentifier<DistanceTriggerBeacon>::getIdentifier()) && static_cast<DistanceTriggerBeacon*>(*it)->getName() == this->targetName_)
161                    {
162                        found = true;
163                        break;
164                    }
165                }
166                if(found)
167                    continue;
168            }
169
170            Vector3 distanceVec = entity->getWorldPosition() - this->getWorldPosition();
171            // If the object is in range.
172            if (distanceVec.length() <= this->distance_)
173            {
174                // Add the object to the objects that are in range.
175                // Objects that already are in range are not added twice, because in a map (this->range_) each key can only exist once and thus addToRange() will reject all attempts of duplicate entries.
176                if(!this->addToRange(entity))
177                    continue;
178
179                // Change the entity to the parent of the DistanceTriggerBeacon (if in identify-mode), which is the entity to which the beacon is attached.
180                if(this->beaconMode_ == distanceMultiTriggerBeaconMode::identify)
181                    entity = entity->getParent();
182
183                // If no queue has been created, yet.
184                if(queue == NULL)
185                    queue = new std::queue<MultiTriggerState*>();
186
187                // Create a state and append it to the queue.
188                MultiTriggerState* state = new MultiTriggerState;
189                state->bTriggered = true; // Because the entity came into range.
190                state->originator = entity;
191                queue->push(state);
192            }
193        }
194
195        return queue;
196    }
197   
198    /**
199    @brief
200        Set the beacon mode.
201    @param mode
202        The mode as an enum.
203    */
204    void DistanceMultiTrigger::setBeaconModeDirect(distanceMultiTriggerBeaconMode::Value mode)
205    {
206        this->beaconMode_ = mode;
207        if(this->beaconMode_ == distanceMultiTriggerBeaconMode::identify && this->beaconMask_ == NULL)
208        {
209            this->beaconMask_ = new ClassTreeMask();
210            this->beaconMask_->exclude(Class(BaseObject));
211            this->beaconMask_->include(Class(DistanceTriggerBeacon));
212        }
213    }
214   
215    /**
216    @brief
217        Get the beacon mode.
218    @return
219        Returns the mode as a string.
220    */
221    const std::string& DistanceMultiTrigger::getBeaconMode(void) const
222    {
223        switch(this->getBeaconModeDirect())
224        {
225            case distanceMultiTriggerBeaconMode::off :
226                return DistanceMultiTrigger::beaconModeOff_s;
227            case distanceMultiTriggerBeaconMode::identify:
228                return DistanceMultiTrigger::beaconModeIdentify_s;
229            case distanceMultiTriggerBeaconMode::exclude:
230                return DistanceMultiTrigger::beaconModeExlcude_s;
231            default :
232                assert(0); // This is impossible.
233                return BLANKSTRING;
234        }
235    }
236   
237    /**
238    @brief
239        Set the beacon mode.
240    @param mode
241        The mode as a string.
242    */
243    void DistanceMultiTrigger::setBeaconMode(const std::string& mode)
244    {
245        if(mode == DistanceMultiTrigger::beaconModeOff_s)
246            this->setBeaconModeDirect(distanceMultiTriggerBeaconMode::off);
247        else if(mode == DistanceMultiTrigger::beaconModeIdentify_s)
248            this->setBeaconModeDirect(distanceMultiTriggerBeaconMode::identify);
249        else if(mode == DistanceMultiTrigger::beaconModeExlcude_s)
250            this->setBeaconModeDirect(distanceMultiTriggerBeaconMode::exclude);
251        else
252            COUT(1) << "Invalid beacon mode in DistanceMultiTrigger." << endl;
253    }
254
255    /**
256    @brief
257        Add a given entity to the entities, that currently are in range of the DistanceMultiTrigger.
258    @param entity
259        A pointer to the entity.
260    @return
261        Returns true if successful, false if not.
262    */
263    bool DistanceMultiTrigger::addToRange(WorldEntity* entity)
264    {
265        WeakPtr<WorldEntity>* weakptr = new WeakPtr<WorldEntity>(entity);
266        std::pair<std::map<WorldEntity*, WeakPtr<WorldEntity>* >::iterator, bool> pair = this->range_.insert(std::pair<WorldEntity*, WeakPtr<WorldEntity>* >(entity, weakptr));
267
268        if(!pair.second)
269        {
270            delete weakptr;
271            return false;
272        }
273
274        return true;
275    }
276
277    /**
278    @brief
279        Remove a given entity from the set of entities, that currently are in range of the DistanceMultiTrigger.
280    @param entity
281        A pointer ot the entity.
282    @return
283        Returns true if successful.
284    */
285    bool DistanceMultiTrigger::removeFromRange(WorldEntity* entity)
286    {
287        WeakPtr<WorldEntity>* weakptr = this->range_.find(entity)->second;
288        bool erased = this->range_.erase(entity) > 0;
289        if(erased)
290            delete weakptr;
291        return erased;
292    }
293
294}
Note: See TracBrowser for help on using the repository browser.