Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Apr 9, 2011, 3:33:06 PM (13 years ago)
Author:
dafrick
Message:

Adding changes made to DistanceTrigger also in trunk.
Also documenting trigger.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • code/trunk/src/modules/objects/triggers/DistanceTrigger.cc

    r8079 r8213  
    3737#include "core/CoreIncludes.h"
    3838#include "core/XMLPort.h"
     39
    3940#include "worldentities/pawns/Pawn.h"
     41
    4042#include "DistanceTriggerBeacon.h"
    4143
    4244namespace orxonox
    4345{
    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    }
    182292}
Note: See TracChangeset for help on using the changeset viewer.