- Timestamp:
- Apr 9, 2011, 3:33:06 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
code/trunk/src/modules/objects/triggers/DistanceTrigger.cc
r8079 r8213 37 37 #include "core/CoreIncludes.h" 38 38 #include "core/XMLPort.h" 39 39 40 #include "worldentities/pawns/Pawn.h" 41 40 42 #include "DistanceTriggerBeacon.h" 41 43 42 44 namespace orxonox 43 45 { 44 CreateFactory(DistanceTrigger); 45 46 DistanceTrigger::DistanceTrigger(BaseObject* creator) : Trigger(creator) 47 { 48 RegisterObject(DistanceTrigger); 49 50 this->distance_ = 100; 51 this->targetMask_.exclude(Class(BaseObject)); 52 this->targetName_ = ""; 53 this->singleTargetMode_ = false; 54 } 55 56 DistanceTrigger::~DistanceTrigger() 57 { 58 } 59 60 void DistanceTrigger::XMLPort(Element& xmlelement, XMLPort::Mode mode) 61 { 62 SUPER(DistanceTrigger, XMLPort, xmlelement, mode); 63 64 XMLPortParam(DistanceTrigger, "distance", setDistance, getDistance, xmlelement, mode).defaultValues(100.0f); 65 XMLPortParamLoadOnly(DistanceTrigger, "target", addTargets, xmlelement, mode).defaultValues("Pawn"); 66 XMLPortParam(DistanceTrigger, "targetname", setTargetName, getTargetName, xmlelement, mode); 67 } 68 69 void DistanceTrigger::addTarget(Ogre::Node* targetNode) 70 { 71 this->targetSet_.insert(targetNode); 72 } 73 74 void DistanceTrigger::removeTarget(Ogre::Node* targetNode) 75 { 76 int returnval = this->targetSet_.erase(targetNode); 77 if (returnval == 0) 78 { 79 COUT(2) << "Warning: Node " << targetNode << " did not exist in targetSet of trigger " << this << " !" << std::endl; 80 COUT(4) << "Content of targetSet of trigger " << this << " :" << std::endl; 81 std::set<Ogre::Node*>::iterator it; 82 for (it = this->targetSet_.begin(); it != this->targetSet_.end(); ++it) 83 { 84 COUT(4) << *it << std::endl; 85 } 86 COUT(4) << "End of targetSet of trigger " << this << std::endl; 87 } 88 } 89 90 void DistanceTrigger::addTargets(const std::string& targets) 91 { 92 Identifier* targetId = ClassByString(targets); 93 94 //! Checks whether the target is (or is derived from) a ControllableEntity. 95 Identifier* pawnId = Class(Pawn); 96 Identifier* distanceTriggerBeaconId = Class(DistanceTriggerBeacon); 97 if(targetId->isA(pawnId) || targetId->isA(distanceTriggerBeaconId)) 98 { 99 this->setForPlayer(true); 100 } 101 102 if (!targetId) 103 { 104 COUT(1) << "Error: \"" << targets << "\" is not a valid class name to include in ClassTreeMask (in " << this->getName() << ", class " << this->getIdentifier()->getName() << ')' << std::endl; 105 return; 106 } 107 108 this->targetMask_.include(targetId); 109 110 // trigger shouldn't react on itself or other triggers 111 this->targetMask_.exclude(Class(Trigger), true); 112 113 // we only want WorldEntities 114 ClassTreeMask WEMask; 115 WEMask.include(Class(WorldEntity)); 116 this->targetMask_ *= WEMask; 117 118 this->notifyMaskUpdate(); 119 } 120 121 void DistanceTrigger::removeTargets(const std::string& targets) 122 { 123 Identifier* targetId = ClassByString(targets); 124 this->targetMask_.exclude(targetId); 125 } 126 127 bool DistanceTrigger::checkDistance() 128 { 129 // Iterate through all objects 130 for (ClassTreeMaskObjectIterator it = this->targetMask_.begin(); it != this->targetMask_.end(); ++it) 131 { 132 WorldEntity* entity = orxonox_cast<WorldEntity*>(*it); 133 if (!entity) 134 continue; 135 136 // If the DistanceTrigger is in single-target mode. 137 if(this->singleTargetMode_) 138 { 139 // If the object that is a target is no DistanceTriggerBeacon, then the DistanceTrigger can't be in single-target-mode. 140 if(!(*it)->isA(ClassIdentifier<DistanceTriggerBeacon>::getIdentifier())) 141 { 142 this->singleTargetMode_ = false; 143 COUT(2) << "DistanceTrigger " << 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; 144 } 145 // If the target name and the name of the DistancTriggerBeacon don't match. 146 else if(entity->getName().compare(this->targetName_) != 0) 147 continue; 148 } 149 150 Vector3 distanceVec = entity->getWorldPosition() - this->getWorldPosition(); 151 if (distanceVec.length() < this->distance_) 152 { 153 154 // If the target is a player (resp. is a, or is derived from a, ControllableEntity) the triggeringPlayer is set to the target entity. 155 if(this->isForPlayer()) 156 { 157 158 // Change the entity to the parent of the DistanceTriggerBeacon (if in single-target-mode), which is the entity to which the beacon is attached. 159 if(this->singleTargetMode_) 160 entity = entity->getParent(); 161 162 Pawn* player = orxonox_cast<Pawn*>(entity); 163 this->setTriggeringPlayer(player); 164 } 165 166 return true; 167 } 168 } 169 170 return false; 171 } 172 173 bool DistanceTrigger::isTriggered(TriggerMode::Value mode) 174 { 175 if (Trigger::isTriggered(mode)) 176 { 177 return checkDistance(); 178 } 179 else 180 return false; 181 } 46 47 /*static*/ const std::string DistanceTrigger::beaconModeOff_s = "off"; 48 /*static*/ const std::string DistanceTrigger::beaconModeIdentify_s = "identify"; 49 /*static*/ const std::string DistanceTrigger::beaconModeExlcude_s = "exclude"; 50 51 CreateFactory(DistanceTrigger); 52 53 /** 54 @brief 55 Constructor. Registers and initializes the object. 56 @param creator 57 The creator of this trigger. 58 */ 59 DistanceTrigger::DistanceTrigger(BaseObject* creator) : Trigger(creator), beaconMask_(NULL) 60 { 61 RegisterObject(DistanceTrigger); 62 63 this->distance_ = 100; 64 this->targetMask_.exclude(Class(BaseObject)); 65 this->targetName_ = ""; 66 } 67 68 /** 69 @brief 70 Destructor. 71 */ 72 DistanceTrigger::~DistanceTrigger() 73 { 74 // Delete the beacon mask if it exists. 75 if(this->beaconMask_ != NULL) 76 delete this->beaconMask_; 77 } 78 79 /** 80 @brief 81 Method for creating a DistanceTrigger object through XML. 82 */ 83 void DistanceTrigger::XMLPort(Element& xmlelement, XMLPort::Mode mode) 84 { 85 SUPER(DistanceTrigger, XMLPort, xmlelement, mode); 86 87 XMLPortParam(DistanceTrigger, "distance", setDistance, getDistance, xmlelement, mode).defaultValues(100.0f); 88 XMLPortParamLoadOnly(DistanceTrigger, "target", addTarget, xmlelement, mode).defaultValues("Pawn"); 89 XMLPortParam(DistanceTrigger, "beaconMode", setBeaconMode, getBeaconMode, xmlelement, mode); 90 XMLPortParam(DistanceTrigger, "targetname", setTargetName, getTargetName, xmlelement, mode); 91 } 92 93 /** 94 @brief 95 Add some target to the DistanceTrigger. 96 @param targetStr 97 The target class name as a string. 98 */ 99 void DistanceTrigger::addTarget(const std::string& targetStr) 100 { 101 Identifier* targetId = ClassByString(targetStr); 102 103 // Checks whether the target is (or is derived from) a Pawn and if so set the PlayerTrigger aspect of this trigger to be for the player, meaning, that from this Trigger one can derive the Pawn that caused it to trigger. 104 Identifier* pawnId = Class(Pawn); 105 if(targetId->isA(pawnId)) 106 this->setForPlayer(true); 107 108 if (targetId == NULL) 109 { 110 COUT(1) << "Error: \"" << targetStr << "\" is not a valid class name to include in ClassTreeMask (in " << this->getName() << ", class " << this->getIdentifier()->getName() << ')' << std::endl; 111 return; 112 } 113 114 // Add the target to the target mask. 115 this->targetMask_.include(targetId); 116 117 // The DistanceTrigger shouldn't react to itself or other triggers. 118 this->targetMask_.exclude(Class(TriggerBase), true); 119 120 // We only want WorldEntities (since only they have a position) 121 ClassTreeMask WEMask; 122 WEMask.include(Class(WorldEntity)); 123 this->targetMask_ *= WEMask; 124 125 this->notifyMaskUpdate(); // Inform interested parties that the target mask has been updated. 126 } 127 128 /** 129 @brief 130 Remove some target from the DistanceTrigger. 131 @param targetStr 132 The target class name as a string. 133 */ 134 void DistanceTrigger::removeTarget(const std::string& targetStr) 135 { 136 Identifier* targetId = ClassByString(targetStr); 137 this->targetMask_.exclude(targetId); 138 } 139 140 /** 141 @brief 142 Check, whether there are entities that are targets of this DistanceTrigger in its range. 143 @return 144 Returns true if there are valid entities in its range. 145 */ 146 bool DistanceTrigger::checkDistance() 147 { 148 // Check whether there is a cached object, it still exists and whether it is still in range, if so nothing further needs to be done. 149 if(this->cache_.get() != NULL) 150 { 151 if((this->cache_.get()->getWorldPosition() - this->getWorldPosition()).length() < this->distance_) 152 return true; 153 else 154 this->cache_.reset(); 155 } 156 157 // Check for new objects that are in range 158 ClassTreeMask targetMask = this->targetMask_; 159 // If we are in identify-mode another target mask has to be applies to find the DistanceTriggerBeacons. 160 if(this->beaconMode_ == distanceTriggerBeaconMode::identify) 161 targetMask = *this->beaconMask_; 162 163 // Iterate through all objects that are targets of the DistanceTrigger. 164 for (ClassTreeMaskObjectIterator it = targetMask.begin(); it != targetMask.end(); ++it) 165 { 166 WorldEntity* entity = static_cast<WorldEntity*>(*it); 167 168 // If the DistanceTrigger is in identify-mode and the DistanceTriggerBeacon attached to the object has the wrong name we ignore it. 169 if(this->beaconMode_ == distanceTriggerBeaconMode::identify) 170 { 171 if(entity->getName() != this->targetName_) 172 continue; 173 // If the object, the DistanceTriggerBeacon is attached to, is not a target of this DistanceMultiTrigger. 174 else if(this->targetMask_.isExcluded(entity->getParent()->getIdentifier())) 175 continue; 176 } 177 178 // If the DistanceTrigger is in exclude mode and the DistanceTriggerBeacon attached to the object has the right name, we ignore it. 179 if(this->beaconMode_ == distanceTriggerBeaconMode::exclude) 180 { 181 182 const std::set<WorldEntity*> attached = entity->getAttachedObjects(); 183 bool found = false; 184 for(std::set<WorldEntity*>::const_iterator it = attached.begin(); it != attached.end(); it++) 185 { 186 if((*it)->isA(ClassIdentifier<DistanceTriggerBeacon>::getIdentifier()) && static_cast<DistanceTriggerBeacon*>(*it)->getName() == this->targetName_) 187 { 188 found = true; 189 break; 190 } 191 } 192 if(found) 193 continue; 194 } 195 196 // Check if the entity is in range. 197 Vector3 distanceVec = entity->getWorldPosition() - this->getWorldPosition(); 198 if (distanceVec.length() < this->distance_) 199 { 200 // If the target is a player (resp. is a, or is derived from a, Pawn) the triggeringPlayer is set to the target entity. 201 if(this->isForPlayer()) 202 { 203 // Change the entity to the parent of the DistanceTriggerBeacon (if in identify-mode), which is the entity to which the beacon is attached. 204 if(this->beaconMode_ == distanceTriggerBeaconMode::identify) 205 entity = entity->getParent(); 206 207 Pawn* player = orxonox_cast<Pawn*>(entity); 208 this->setTriggeringPlayer(player); 209 } 210 211 // Add the entity to the cache. 212 this->cache_ = WeakPtr<WorldEntity>(entity); 213 214 return true; 215 } 216 } 217 218 return false; 219 } 220 221 /** 222 @brief 223 Set the beacon mode. 224 @param mode 225 The mode as an enum. 226 */ 227 void DistanceTrigger::setBeaconModeDirect(distanceTriggerBeaconMode::Value mode) 228 { 229 this->beaconMode_ = mode; 230 if(this->beaconMode_ == distanceTriggerBeaconMode::identify && this->beaconMask_ == NULL) 231 { 232 this->beaconMask_ = new ClassTreeMask(); 233 this->beaconMask_->exclude(Class(BaseObject)); 234 this->beaconMask_->include(Class(DistanceTriggerBeacon)); 235 } 236 } 237 238 /** 239 @brief 240 Get the beacon mode. 241 @return 242 Returns the mode as a string. 243 */ 244 const std::string& DistanceTrigger::getBeaconMode(void) const 245 { 246 switch(this->getBeaconModeDirect()) 247 { 248 case distanceTriggerBeaconMode::off : 249 return DistanceTrigger::beaconModeOff_s; 250 case distanceTriggerBeaconMode::identify: 251 return DistanceTrigger::beaconModeIdentify_s; 252 case distanceTriggerBeaconMode::exclude: 253 return DistanceTrigger::beaconModeExlcude_s; 254 default : 255 assert(0); // This is impossible. 256 return BLANKSTRING; 257 } 258 } 259 260 /** 261 @brief 262 Set the beacon mode. 263 @param mode 264 The mode as a string. 265 */ 266 void DistanceTrigger::setBeaconMode(const std::string& mode) 267 { 268 if(mode == DistanceTrigger::beaconModeOff_s) 269 this->setBeaconModeDirect(distanceTriggerBeaconMode::off); 270 else if(mode == DistanceTrigger::beaconModeIdentify_s) 271 this->setBeaconModeDirect(distanceTriggerBeaconMode::identify); 272 else if(mode == DistanceTrigger::beaconModeExlcude_s) 273 this->setBeaconModeDirect(distanceTriggerBeaconMode::exclude); 274 else 275 COUT(1) << "Invalid beacon mode in DistanceTrigger." << endl; 276 } 277 278 /** 279 @brief 280 Check whether the DistanceTrigger is triggered. 281 It is triggered if it is triggered according only to its mode (i.e. its sub-triggers) and if a target is in range. 282 @param 283 Returns true if it is triggered ,false if not. 284 */ 285 bool DistanceTrigger::isTriggered(TriggerMode::Value mode) 286 { 287 if (Trigger::isTriggered(mode)) 288 return checkDistance(); 289 else 290 return false; 291 } 182 292 }
Note: See TracChangeset
for help on using the changeset viewer.