home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 02 Useful Techniques / 02 Orkin / TriggerSystem.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-09-05  |  4.6 KB  |  176 lines

  1. #include "TriggerSystem.h"
  2. #include "Agent.h"
  3. #include <windows.h>
  4. #include <mmsystem.h>
  5. #include <math.h>
  6. #include <assert.h>
  7.  
  8.  
  9. #define DIST(a, b) sqrt( (b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y) + (b.z - a.z)*(b.z - a.z) )
  10.  
  11. unsigned long TriggerRecordStruct::s_nNextTriggerID = 1;
  12.  
  13. // -----------------------------------------------------------------------
  14.  
  15. TriggerRecordStruct::TriggerRecordStruct(EnumTriggerType _eTriggerType, 
  16.         unsigned long _idSource, const Vector& _vPos, 
  17.         float _fRadius, float _fDuration, bool _bDynamicSourcePos)
  18. {
  19.     eTriggerType        = _eTriggerType;
  20.     idSource            = _idSource;
  21.     vPos                = _vPos;
  22.     fRadius                = _fRadius;
  23.     nTimeStamp            = timeGetTime();
  24.     bDynamicSourcePos    = _bDynamicSourcePos;
  25.  
  26.     // Triggers with duration of 0 do not ever expire.
  27.     if(_fDuration != 0.f)
  28.     {
  29.         nExpirationTime = nTimeStamp + (unsigned long)(_fDuration * 1000.f);
  30.     }
  31.     else {
  32.         nExpirationTime = 0;
  33.     }
  34.  
  35.     // Keep a unique identifier for all triggers.
  36.     nTriggerID = s_nNextTriggerID++;
  37. }
  38.  
  39. // -----------------------------------------------------------------------
  40.  
  41. CTriggerSystem::CTriggerSystem()
  42. {
  43.     m_bTriggerCriticalSection = false;
  44. }
  45.  
  46. CTriggerSystem::~CTriggerSystem()
  47. {
  48. }
  49.  
  50. // -----------------------------------------------------------------------
  51.  
  52. unsigned long CTriggerSystem::RegisterTrigger(EnumTriggerType _eTriggerType, unsigned long _nPriority,
  53.                                        unsigned long _idSource, const Vector& _vPos, float _fRadius, 
  54.                                        float _fDuration, bool _bDynamicSourcePos)
  55. {
  56.     // Create a trigger record, and fill it in.
  57.     TriggerRecordStruct* pTriggerRecord = 
  58.         new    TriggerRecordStruct(_eTriggerType, _idSource, _vPos, 
  59.                                 _fRadius, _fDuration, _bDynamicSourcePos);
  60.  
  61.     // Trigger records are sorted by priority.
  62.     m_mapTriggerMap.insert( TRIGGER_MAP::value_type(_nPriority, pTriggerRecord) );
  63.  
  64.     return pTriggerRecord->nTriggerID;
  65. }
  66.  
  67. // -----------------------------------------------------------------------
  68.  
  69. void CTriggerSystem::RemoveTrigger(unsigned long nTriggerID)
  70. {
  71.     assert(m_bTriggerCriticalSection == false);
  72.  
  73.     TRIGGER_MAP::iterator it = m_mapTriggerMap.begin();
  74.     while( it != m_mapTriggerMap.end() )
  75.     {
  76.         if( it->second->nTriggerID == nTriggerID )
  77.         {
  78.             delete(it->second);
  79.             return;
  80.         }
  81.         else ++it;
  82.     }
  83. }
  84.  
  85. // ----------------------------------------------------------------------- 
  86.  
  87. void CTriggerSystem::Update()
  88. {
  89.     CAgent* pAgent    = NULL;
  90.     float fDistance    = 0.f;
  91.  
  92.     TriggerRecordStruct* pRecord;
  93.     TRIGGER_MAP::iterator it;
  94.  
  95.     unsigned long nCurTime = timeGetTime();
  96.  
  97.     //
  98.     // Delete expired trigger records.
  99.     // Records with expiration time 0 never expire.
  100.     //
  101.     // For records that are not expired, update position
  102.     // if the dynamic flag is set.
  103.     //
  104.     it = m_mapTriggerMap.begin();
  105.     while( it != m_mapTriggerMap.end() )
  106.     {
  107.         pRecord = it->second;
  108.         if( (pRecord->nExpirationTime != 0) && (pRecord->nExpirationTime < nCurTime) )
  109.         {
  110.             delete(pRecord);
  111.             it = m_mapTriggerMap.erase(it);
  112.         }
  113.         else {
  114.             // Update position if dynamic flag is set.
  115.             // Reset time-stamp.
  116.             if(pRecord->bDynamicSourcePos == true)
  117.             {
  118.                 pRecord->vPos = g_pAgentList[pRecord->idSource]->GetPosition();
  119.                 pRecord->nTimeStamp = nCurTime;
  120.             }
  121.  
  122.             ++it;
  123.         }        
  124.     }
  125.  
  126.  
  127.     //
  128.     // Trigger Agents.
  129.     //
  130.  
  131.     // Make sure triggers are not getting removed while in this loop.
  132.     m_bTriggerCriticalSection = true;
  133.  
  134.     // Loop thru agents.
  135.     for(unsigned long iAgent=0; iAgent < g_nNumAgents; ++iAgent)
  136.     {
  137.         pAgent = g_pAgentList[iAgent];
  138.  
  139.         // Check if it's time for this Agent to update.
  140.         if( (pAgent->GetTriggerUpdateRate() > 0.f) && (nCurTime > pAgent->GetNextTriggerUpdate()) )
  141.         {
  142.             pAgent->SetNextTriggerUpdate(nCurTime + (unsigned long)(pAgent->GetTriggerUpdateRate() * 1000.f));
  143.  
  144.             // Loop through existing trigger records.
  145.             for(it = m_mapTriggerMap.begin(); it != m_mapTriggerMap.end(); ++it)
  146.             {
  147.                 pRecord = it->second;
  148.  
  149.                 // Check if this Agent responds to this trigger.
  150.                 if( !(pRecord->eTriggerType & pAgent->GetTriggerFlags()) )
  151.                     continue;
  152.                 
  153.                 // Check that trigger source is not the Agent itself.
  154.                 if( pRecord->idSource == iAgent)
  155.                     continue;
  156.  
  157.                 // Check radius.
  158.                 fDistance = DIST(pRecord->vPos, pAgent->GetPosition());
  159.                 if(fDistance > (pAgent->GetTriggerDistance() + pRecord->fRadius) )
  160.                     continue;
  161.                 
  162.                 // HandleTrigger returns true if the Agent responded to the trigger.
  163.                 if( pAgent->HandleTrigger(pRecord) )
  164.                 {
  165.                     // Only pay attention to the highest priority 
  166.                     // trigger at any one instant.
  167.                     break;
  168.                 }
  169.             }
  170.         }
  171.     }
  172.  
  173.     m_bTriggerCriticalSection = false;
  174. }
  175.  
  176.