GameObject.cpp
上传用户:royluo
上传日期:2007-01-05
资源大小:1584k
文件大小:17k
源码类别:

游戏

开发平台:

Visual C++

  1. /*****************************************************************************
  2. *                                                                             
  3. *   GameObject.cpp                                                            
  4. *                                                                             
  5. *   Electrical Engineering Faculty - Software Lab                             
  6. *   Spring semester 1998                                                      
  7. *                                                                             
  8. *   Tanks game                                                                
  9. *                                                                             
  10. *   Module description: Implements the GameObject hierarchy :
  11. *                                   GameObject (abstract)
  12. *                                      /   
  13. *                           MovingObject   ExplodingObject
  14. *                       All game objects (tanks, shells, etc.) are derived from 
  15. *                       one or more (multiple inheritance) of these classes.
  16. *                       
  17. *                                                                             
  18. *   Authors: Eran Yariv - 28484475                                           
  19. *            Moshe Zur  - 24070856                                           
  20. *                                                                            
  21. *                                                                            
  22. *   Date: 23/09/98                                                           
  23. *                                                                            
  24. ******************************************************************************/
  25. #include <stdafx.h>
  26. #include <math.h>
  27. #include <GameObject.h>
  28. #include <GameConsts.h>
  29. #include <Tanks.h>
  30. CGameObject::CGameObject () :
  31.     m_ListPosition (NULL),
  32.     m_UpdateRect (m_Pos, m_Size),
  33.     m_GlobalImageManager (TANKS_APP->m_gImageManager),
  34.     m_GlobalObjsList (TANKS_APP->m_gGameManager.ExposeObjects())
  35. {}
  36. /*------------------------------------------------------------------------------
  37.   Function: GetMapPosition
  38.   Purpose:  Returns the objects current position on game board (map).
  39.             The object can be entirely seen (fully in map), partialy seen
  40.             (some portion of the object is out of map), and unseen.
  41.   Input:    pos - the suggested position of the object on the map.
  42.   Output:   Status of the object visiblity given the suggested position.
  43.   Remarks:  
  44. ------------------------------------------------------------------------------*/
  45. WORD CGameObject::GetMapPosition (CPoint &pos)
  46. {
  47.     WORD wRes = 0;
  48.     CRect ObjRect (pos, m_Size),
  49.           TmpRect,
  50.           MapRect (0, 0, MAP_WIDTH-1, MAP_HEIGHT-1);
  51.     CBitMask *myBitMask = m_GlobalImageManager.ExposeBitMask(GetImage());
  52.     if (NULL != myBitMask)
  53.     {
  54.         // There's a better rectangle for the object
  55.         CRect &ActualRect = myBitMask->GetActualRect();
  56.         int x1 = pos.x + ActualRect.left,
  57.             y1 = pos.y + ActualRect.top;
  58.         ObjRect.SetRect (x1, y1, x1 + ActualRect.Width(), y1 + ActualRect.Height());
  59.     }
  60.     if (ObjRect.left >= 0 && ObjRect.right < MAP_WIDTH) 
  61.         wRes |= X_FULL_IN_MAP;      // Map fully contains the object in the X axis
  62.     else if (TmpRect.IntersectRect (ObjRect, MapRect) != 0)
  63.         wRes |= X_PARTIAL_IN_MAP;   // Map partailly contains the object in the X axis
  64.     else 
  65.         wRes |= X_NOT_IN_MAP;      // Map doesn't contains the object in the X axis
  66.     if (ObjRect.top >= 0 && ObjRect.bottom < MAP_HEIGHT) 
  67.         wRes |= Y_FULL_IN_MAP;      // Map fully contains the object in the Y axis
  68.     else if (TmpRect.IntersectRect (ObjRect, MapRect) != 0)
  69.         wRes |= Y_PARTIAL_IN_MAP;   // Map partailly contains the object in the Y axis
  70.     else 
  71.         wRes |= Y_NOT_IN_MAP;      // Map doesn't contains the object in the Y axis
  72.     return wRes;
  73. }
  74. /*------------------------------------------------------------------------------
  75.   Function: CollidesWith
  76.   Purpose:  Check if our object collides with the given object.
  77.   Input:    pOtherObj - the pointer to the object to be checked against.
  78.   Output:   TRUE if objects collide.
  79.   Remarks:  Some objects contains bitmasks for more accurate collision detection
  80.             (by pixel resolution), but more time consuming. For objects w/o 
  81.             bitmasks the object rectangles are checked for intersection.
  82. ------------------------------------------------------------------------------*/
  83. BOOL CGameObject::CollidesWith (CGameObject *pOtherObj)
  84. {
  85.     CRect IntersecRect = pOtherObj->CGameObject::GetUpdateRectangle();
  86.     IntersecRect &= CGameObject::GetUpdateRectangle();
  87.     if (IntersecRect.IsRectEmpty()) 
  88.     {   // no further calculations needed - rects don't intersect:
  89.         return FALSE;
  90.     }
  91.     // check if bit masks of objects collides: (check is ignored if both bit masks are null)
  92.     CBitMask *myBitMask = m_GlobalImageManager.ExposeBitMask(GetImage());
  93.     CBitMask *otherBitMask = m_GlobalImageManager.ExposeBitMask(pOtherObj->GetImage());
  94.     if (! myBitMask && ! otherBitMask) {
  95.         return TRUE;
  96.     }
  97.     return BitMaskCollides (IntersecRect,
  98.                             m_Pos, 
  99.                             pOtherObj->GetPos(), 
  100.                             myBitMask, 
  101.                             otherBitMask);
  102. }
  103. /*------------------------------------------------------------------------------
  104.   Function: CollidesWith
  105.   Purpose:  Check if our object collides with the given object.
  106.   Input:    pOtherObj - the pointer to the object to be checked against.
  107.             MyRect - a specified rectangle on the game board object to be 
  108.             checked against.
  109.   Output:   TRUE if objects collide.
  110.   Remarks:  This method is called from game board only. 
  111.             Thus we know there is no bit mask for the other object and that 
  112.             UpdateRect is no good for us.
  113. ------------------------------------------------------------------------------*/
  114. BOOL CGameObject::CollidesWith (CGameObject* pOtherObj, CRect& MyRect)
  115. {
  116.     CRect IntersecRect = pOtherObj->CGameObject::GetUpdateRectangle();
  117.     IntersecRect &= MyRect;
  118.     if (IntersecRect.IsRectEmpty()) 
  119.     {   // no further calculations needed - rects don't intersect:
  120.         return FALSE;
  121.     }
  122.     // check if there is a bit mask:
  123.     if (m_GlobalImageManager.ExposeBitMask(pOtherObj->GetImage())) {
  124.         return BitMaskCollides (IntersecRect,
  125.                                 MyRect.TopLeft(),
  126.                                 pOtherObj->GetPos(),
  127.                                 NULL,
  128.                                 m_GlobalImageManager.ExposeBitMask(pOtherObj->GetImage()));
  129.     }
  130.     return TRUE;
  131. }
  132. /*------------------------------------------------------------------------------
  133.   Function: BitMaskCollides
  134.   Purpose:  Test if the given bitmasks collides inside the given rectangle.
  135.   Input:    IntersectRect - The intersection rectangle of the objects that 
  136.                             overlaps.
  137.             myPos - The position of one object on the map
  138.             otherPos - the position of the other object on the map
  139.             myBitMask - the bitmask of one object (may be null)
  140.             otherBitMask - the bitmask of the other object (may be null)
  141.   Output:   TRUE if the two bitmasks collides inside the region of the 
  142.             intersection rectangle.
  143.   Remarks:  At least on of the bitmask must exist (otherwise this code wasn't
  144.             inuse).
  145. ------------------------------------------------------------------------------*/
  146. BOOL 
  147. CGameObject::BitMaskCollides (CRect& IntersectRect, CPoint& myPos, CPoint& otherPos,
  148.                               CBitMask* myBitMask, CBitMask* otherBitMask)
  149. {
  150.     CPoint myOffset = IntersectRect.TopLeft() - myPos;
  151.     CPoint otherOffset = IntersectRect.TopLeft() - otherPos;
  152.     ASSERT(myBitMask || otherBitMask);  // at this stage at least one bit mask exists
  153.     if (myBitMask && otherBitMask) 
  154.     {    // both object have bitmasks:
  155.         for (int i = 0; i < IntersectRect.Width(); i++) {
  156.             for (int j = 0; j < IntersectRect.Height(); j++) {
  157.                 if (myBitMask->GetMaskAt(i + myOffset.x, j + myOffset.y) &&
  158.                     otherBitMask->GetMaskAt(i + otherOffset.x, j + otherOffset.y))
  159.                     return TRUE;
  160.             }
  161.         }
  162.         return FALSE;
  163.     }
  164.     // Only one object contains a bit mask, so we assume the missing bitmask is
  165.     // all ones:
  166.     CBitMask *BitMask;
  167.     CPoint Offset;
  168.     if (myBitMask) {
  169.         BitMask = myBitMask;
  170.         Offset = myOffset;
  171.     } else {
  172.         BitMask = otherBitMask;
  173.         Offset = otherOffset;
  174.     }
  175.     for (int i = Offset.x; i < Offset.x + IntersectRect.Width(); i++) {
  176.         for (int j = Offset.y; j < Offset.y + IntersectRect.Height(); j++) {
  177.             if (BitMask->GetMaskAt(i, j))
  178.                 return TRUE;
  179.         }
  180.     }
  181.     return FALSE;
  182. }
  183. /* ------------------------- Moving object ------------------------- */
  184. /*------------------------------------------------------------------------------
  185.   Function: CalcNewPos
  186.   Purpose:  Calculates the moving object current position depending on its speed, 
  187.             the time passed since we last updated its position, and a flag 
  188.             indicating that object must be fully inside map.
  189.   Input:    dwCurTime - Current game time
  190.             bMustBeFullyInMap - flag forcing object to be fully in map
  191.   Output:   Returns the distance passed (squared) or -1 if out of map.
  192.   Remarks:  
  193. ------------------------------------------------------------------------------*/
  194. int CMovingGameObject::CalcNewPos (DWORD dwCurTime, BOOL bMustBeFullyInMap)
  195. {
  196.     if (m_uLastTick == 0)   // Called for the first time
  197.         m_uLastTick = dwCurTime;
  198.     DWORD dwTimeGap = dwCurTime - m_uLastTick;
  199.     m_uLastTick = dwCurTime;
  200.     double dDistanceRatio = m_dVelocity * double (dwTimeGap) * m_cdThousandth,
  201.            dXDist = dDistanceRatio * m_dDirectionsArr[m_uDirectionIndex].dXDir,
  202.            dYDist = dDistanceRatio * m_dDirectionsArr[m_uDirectionIndex].dYDir;
  203.     PrecisePosType NewPrecPos;
  204.     NewPrecPos.dXPos = m_PrecPos.dXPos + dXDist;
  205.     NewPrecPos.dYPos = m_PrecPos.dYPos + dYDist;
  206.     CPoint NewIntPos (int (NewPrecPos.dXPos+0.5), int (NewPrecPos.dYPos+0.5));
  207.     if (bMustBeFullyInMap)
  208.     {   // Check if object is fully in map
  209.         if (GetMapPosition(NewIntPos) != (X_FULL_IN_MAP | Y_FULL_IN_MAP)) 
  210.         {   // Out of map situation
  211.             return -1;
  212.         }
  213.     }
  214.     else 
  215.     { // check if object is partially in map
  216.         WORD fl = GetMapPosition(NewIntPos);
  217.         if ((X_NOT_IN_MAP & fl) || (Y_NOT_IN_MAP & fl)) 
  218.         {   // Out of map situation
  219.             return -1;
  220.         }
  221.     }
  222.     // Now we know the move is legal:
  223.     m_PrevPrecPos = m_PrecPos;
  224.     m_PrecPos = NewPrecPos;
  225.     m_Pos = NewIntPos;
  226.     return int((dXDist * dXDist) + (dYDist * dYDist));
  227. }
  228. /*------------------------------------------------------------------------------
  229.   Function: CalcPosAtTime
  230.   Purpose:  Calculates the moving object new position depending on its speed, 
  231.             the time passed its previous position and the prev. pos. and a 
  232.             flag indicating that object must be fully inside map.
  233.   Input:    StartPos - the previous position
  234.             dwTimeGap - the time period the object was moving since the 
  235.                         previous position.
  236.             ResPos - the new position [OUT]
  237.             bMustBeFullyInMap - flag forcing object to be fully in map
  238.   Output:   Returns TRUE if new position is contained in map.
  239.   Remarks:  
  240. ------------------------------------------------------------------------------*/
  241. BOOL                        
  242. CMovingGameObject::CalcPosAtTime (CPoint &StartPos,
  243.                                   DWORD dwTimeGap,
  244.                                   CPoint &ResPos,
  245.                                   BOOL bMustBeFullyInMap)
  246. {
  247.     double dDistanceRatio = m_dVelocity * double (dwTimeGap) * m_cdThousandth,
  248.            dXDist = dDistanceRatio * m_dDirectionsArr[m_uDirectionIndex].dXDir,
  249.            dYDist = dDistanceRatio * m_dDirectionsArr[m_uDirectionIndex].dYDir;
  250.     ResPos.x = int (double(StartPos.x) + dXDist + 0.5);
  251.     ResPos.y = int (double(StartPos.y) + dYDist + 0.5);
  252.     if (bMustBeFullyInMap)
  253.     {   // Check if object is fully in map
  254.         if (GetMapPosition(ResPos) != (X_FULL_IN_MAP | Y_FULL_IN_MAP)) 
  255.         {   // Out of map situation
  256.             return FALSE;
  257.         }
  258.     }
  259.     else 
  260.     { // check if object is partially in map
  261.         WORD fl = GetMapPosition(ResPos);
  262.         if ((X_NOT_IN_MAP & fl) || (Y_NOT_IN_MAP & fl)) 
  263.         {   // Out of map situation
  264.             return FALSE;
  265.         }
  266.     }
  267.     return TRUE;
  268. }
  269. void                        
  270. CMovingGameObject::SetNewPos (int x, int y)
  271. {
  272.     m_PrevPrecPos = m_PrecPos;
  273.     SetPos (x, y);
  274.     m_PrecPos.dXPos = x;
  275.     m_PrecPos.dYPos = y;
  276. }
  277. const double CMovingGameObject::m_cdThousandth = double(0.001);
  278. const DirectionType CMovingGameObject::m_dDirectionsArr[MAX_DIRECTIONS] = {
  279.     { -1.0            , 0.0             },  // 0
  280.     { -0.9659258262891, 0.2588190451025 },  // 15
  281.     { -0.8660254037844, 0.5             },  // 30
  282.     { -0.7071067811865, 0.7071067811865 },  // 45
  283.     { -0.5            , 0.8660254037844 },  // 60
  284.     { -0.2588190451025, 0.9659258262891 },  // 75
  285.     {  0.0            , 1.0             },  // 90
  286.     {  0.2588190451025, 0.9659258262891 },  // 105
  287.     {  0.5            , 0.8660254037844 },  // 120
  288.     {  0.7071067811865, 0.7071067811865 },  // 135
  289.     {  0.8660254037844, 0.5             },  // 150
  290.     {  0.9659258262891, 0.2588190451025 },  // 165
  291.     {  1.0            , 0.0             },  // 180
  292.     {  0.9659258262891,-0.2588190451025 },  // 195
  293.     {  0.8660254037844,-0.5             },  // 210
  294.     {  0.7071067811865,-0.7071067811865 },  // 225
  295.     {  0.5            ,-0.8660254037844 },  // 240
  296.     {  0.2588190451025,-0.9659258262891 },  // 255
  297.     {  0.0            ,-1.0             },  // 270
  298.     { -0.2588190451025,-0.9659258262891 },  // 285
  299.     { -0.5            ,-0.8660254037844 },  // 300
  300.     { -0.7071067811865,-0.7071067811865 },  // 315
  301.     { -0.8660254037844,-0.5             },  // 330
  302.     { -0.9659258262891,-0.2588190451025 }   // 345
  303. };
  304. /* ------------------------- Exploding object ------------------------- */
  305. CExplodingGameObject::CExplodingGameObject 
  306.      (UINT uXPos, UINT uYPos, UINT uXSize, UINT uYSize,
  307.       UINT uMaxIntensity,
  308.       CImageManager::ImageType uExplosionImageIndex,
  309.       BOOL InitiallyExploding) :
  310.     m_uMaxIntensity (uMaxIntensity),
  311.     m_bIsExploding (InitiallyExploding)
  312. {
  313.     m_himgExplode = m_GlobalImageManager.GetImage (uExplosionImageIndex);
  314.     m_pCurImage = &m_himgExplode;    // override this in your ctor
  315.     SetPos (uXPos, uYPos);
  316.     SetSize (uXSize, uYSize);
  317.         
  318.     ASSERT (uMaxIntensity > 0);
  319.     for (int i=0; i<MAX_TANKS; i++)
  320.         m_bNotifiedTanks[i]=FALSE;  // No tank was notified about an explosion
  321. }
  322. /*------------------------------------------------------------------------------
  323.   Function: CalcRelativeExplosionIntensity
  324.   Purpose:  Calculates the explosion intensity depending on the distance between
  325.             our object and the given object, and the min and max radiuses of the
  326.             explosition's impact.
  327.   Input:    pOtherObject - pointer to the object we are exploding
  328.             MinRadius - the minimal explosion impact radius: below this radius
  329.                         the impact is maximal
  330.             MaxRadius - the maximal explostion imapct radius: above this radius
  331.                         there is no impact
  332.   Output:   The explosion intensity
  333.   Remarks:  If the distance between the objects is in the range {min, max}, the
  334.             intensity is calculated relative to the distance.
  335. ------------------------------------------------------------------------------*/
  336. UINT 
  337. CExplodingGameObject::CalcRelativeExplosionIntensity (CGameObject *pOtherObject, 
  338.                                                       UINT MinRadius, UINT MaxRadius)
  339. {
  340.     CPoint OtherPos  = pOtherObject->GetPos ();
  341.     CSize  OtherSize = pOtherObject->GetDimensions();
  342.     int iXDist = (m_Pos.x + m_Size.cx / 2) - (OtherPos.x + (OtherSize.cx) / 2),
  343.         iYDist = (m_Pos.y + m_Size.cy / 2) - (OtherPos.y + (OtherSize.cy) / 2),
  344.         iDist = int (sqrt (double(iXDist * iXDist) + double(iYDist * iYDist)) + 0.5);
  345.     ASSERT (MaxRadius > MinRadius);
  346.     if (iDist <= int(MinRadius))
  347.         // We're below minimum radius - return full blast power
  348.         return m_uMaxIntensity;
  349.     if (iDist >= int(MaxRadius))
  350.         // We're behind max radius - no impact
  351.         return 0;
  352.     // Otherwise , we're between min and max radiuses. Return relative impact
  353.     return UINT (double (MaxRadius - iDist) * double (m_uMaxIntensity) /
  354.                  double (MaxRadius - MinRadius)); 
  355. }