Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/modules/objects/triggers/DistanceMultiTrigger.cc @ 7328

Last change on this file since 7328 was 7301, checked in by dafrick, 14 years ago

Improving documentation for MultiTriggers, also some small bugfixes, simplifications and added features.

  • Property svn:eol-style set to native
File size: 8.5 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*/
33
34#include "DistanceMultiTrigger.h"
35
36#include "core/CoreIncludes.h"
37#include "core/XMLPort.h"
38#include "DistanceTriggerBeacon.h"
39
40namespace orxonox
41{
42
43    CreateFactory(DistanceMultiTrigger);
44
45    /**
46    @brief
47        Default Constructor. Registers the object and initializes default values.
48    */
49    DistanceMultiTrigger::DistanceMultiTrigger(BaseObject* creator) : MultiTrigger(creator)
50    {
51        RegisterObject(DistanceMultiTrigger);
52
53        this->distance_ = 100.0f;
54        this->targetName_ = BLANKSTRING;
55        this->singleTargetMode_ = false;
56    }
57
58    /**
59    @brief
60        Destructor.
61    */
62    DistanceMultiTrigger::~DistanceMultiTrigger()
63    {
64
65    }
66
67    /**
68    @brief
69        Method for creating a DistanceMultiTrigger object through XML.
70    */
71    void DistanceMultiTrigger::XMLPort(Element& xmlelement, XMLPort::Mode mode)
72    {
73        SUPER(DistanceMultiTrigger, XMLPort, xmlelement, mode);
74
75        XMLPortParam(DistanceMultiTrigger, "distance", setDistance, getDistance, xmlelement, mode);
76        XMLPortParam(DistanceMultiTrigger, "targetname", setTargetName, getTargetName, xmlelement, mode);
77    }
78
79    /**
80    @brief
81        This method is called by the MultiTrigger to get information about new trigger events that need to be looked at.
82
83        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.
84    @return
85        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.
86    */
87    std::queue<MultiTriggerState*>* DistanceMultiTrigger::letTrigger(void)
88    {
89
90        std::queue<MultiTriggerState*>* queue = NULL;
91
92        // Check for objects that were in range but no longer are. Iterate through all objects, that are in range.
93        for(std::map<WorldEntity*, WeakPtr<WorldEntity>* >::iterator it = this->range_.begin(); it != this->range_.end(); )
94        {
95            WorldEntity* entity = it->second->get();
96            WorldEntity* key = it->first;
97            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.
98            // If the entity no longer exists.
99            if(entity == NULL)
100            {
101                this->removeFromRange(key);
102                continue;
103            }
104
105            Vector3 distanceVec = entity->getWorldPosition() - this->getWorldPosition();
106            // If the object is no longer in range.
107            if (distanceVec.length() > this->distance_)
108            {
109                // If for some reason the entity could not be removed.
110                if(!this->removeFromRange(key))
111                    continue;
112
113                // If no queue has been created, yet.
114                if(queue == NULL)
115                    queue = new std::queue<MultiTriggerState*>();
116
117                // Create a state and append it to the queue.
118                MultiTriggerState* state = new MultiTriggerState;
119                state->bTriggered = false; // Because the entity went out of range.
120                state->originator = entity;
121                queue->push(state);
122            }
123        }
124
125        // Check for new objects that are in range
126        for(ClassTreeMaskObjectIterator it = this->getTargetMask().begin(); it != this->getTargetMask().end(); ++it)
127        {
128            WorldEntity* entity = static_cast<WorldEntity*>(*it);
129
130            // If the DistanceMultiTrigger is in single-target mode.
131            if(this->singleTargetMode_)
132            {
133                // If the object that is a target is no DistanceTriggerBeacon, then the DistanceMultiTrigger can't be in single-target-mode.
134                if(!entity->isA(ClassIdentifier<DistanceTriggerBeacon>::getIdentifier()))
135                {
136                    this->singleTargetMode_ = false;
137                    COUT(2) << "DistanceMultiTrigger " << this->getName() << " (&" << this <<  ")" << "is in single-target mode but the target is '" << entity->getIdentifier()->getName() << "' instead of DistanceTriggerBeacon. Setting single-target mode to false." << std::endl;
138                }
139                // If the target name and the name of the DistancTriggerBeacon don't match.
140                else if(entity->getName().compare(this->targetName_) != 0)
141                    continue;
142            }
143
144            Vector3 distanceVec = entity->getWorldPosition() - this->getWorldPosition();
145            // If the object is in range.
146            if (distanceVec.length() <= this->distance_)
147            {
148                // Add the object to the objects that are in range.
149                // 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.
150                if(!this->addToRange(entity))
151                    continue;
152
153                // Change the entity to the parent of the DistanceTriggerBeacon (if in single-target-mode), which is the entity to which the beacon is attached.
154                if(this->singleTargetMode_)
155                    entity = entity->getParent();
156
157                // If no queue has been created, yet.
158                if(queue == NULL)
159                    queue = new std::queue<MultiTriggerState*>();
160
161                // Create a state and append it to the queue.
162                MultiTriggerState* state = new MultiTriggerState;
163                state->bTriggered = true; // Because the entity came into range.
164                state->originator = entity;
165                queue->push(state);
166            }
167        }
168
169        return queue;
170    }
171
172    /**
173    @brief
174        Set the target name of DistanceTriggerBeacons that triggers this DistanceMultiTrigger.
175    @param targetname
176        The name of the DistanceTriggerBeacon as a string.
177    */
178    void DistanceMultiTrigger::setTargetName(const std::string& targetname)
179    {
180        // If the targetname is no blank string single-target mode is enabled.
181        if(targetname.compare(BLANKSTRING) != 0)
182            this->singleTargetMode_ = true;
183        else
184            this->singleTargetMode_ = false;
185
186        this->targetName_ = targetname;
187    }
188
189    /**
190    @brief
191        Add a given entity to the entities, that currently are in range of the DistanceMultiTrigger.
192    @param entity
193        A pointer to the entity.
194    @return
195        Returns true if successful, false if not.
196    */
197    bool DistanceMultiTrigger::addToRange(WorldEntity* entity)
198    {
199        WeakPtr<WorldEntity>* weakptr = new WeakPtr<WorldEntity>(entity);
200        std::pair<std::map<WorldEntity*, WeakPtr<WorldEntity>* >::iterator, bool> pair = this->range_.insert(std::pair<WorldEntity*, WeakPtr<WorldEntity>* >(entity, weakptr));
201
202        if(!pair.second)
203        {
204            delete weakptr;
205            return false;
206        }
207
208        return true;
209    }
210
211    /**
212    @brief
213        Remove a given entity from the set of entities, that currently are in range of the DistanceMultiTrigger.
214    @param entity
215        A pointer ot the entity.
216    @return
217        Returns true if successful.
218    */
219    bool DistanceMultiTrigger::removeFromRange(WorldEntity* entity)
220    {
221        WeakPtr<WorldEntity>* weakptr = this->range_.find(entity)->second;
222        bool erased = this->range_.erase(entity) > 0;
223        if(erased)
224            delete weakptr;
225        return erased;
226    }
227
228}
Note: See TracBrowser for help on using the repository browser.