Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

239 lines
5.6 KiB

  1. /*************************************************
  2. * mysprite.cpp *
  3. * *
  4. * Copyright (C) 1995-1999 Microsoft Inc. *
  5. * *
  6. *************************************************/
  7. // mysprite.cpp : implementation file
  8. //
  9. #include "stdafx.h"
  10. #include "dib.h"
  11. #include "spriteno.h"
  12. #include "sprite.h"
  13. #include "phsprite.h"
  14. #include "mysprite.h"
  15. #include "mciobj.h"
  16. #include "splstno.h"
  17. #include "spritlst.h"
  18. #include "animdoc.h"
  19. #include "math.h"
  20. #ifdef _DEBUG
  21. #undef THIS_FILE
  22. static char BASED_CODE THIS_FILE[] = __FILE__;
  23. #endif
  24. /////////////////////////////////////////////////////////////////////////////
  25. // CBlock
  26. IMPLEMENT_SERIAL(CBlock, CPhasedSprite, 0 /* schema number*/ )
  27. CBlock::CBlock()
  28. {
  29. m_mass = 0;
  30. m_vx = 0;
  31. m_vy = 0;
  32. m_dx = 0;
  33. m_dy = 0;
  34. }
  35. CBlock::~CBlock()
  36. {
  37. }
  38. /////////////////////////////////////////////////////////////////////////////
  39. // CBlock serialization
  40. void CBlock::Serialize(CArchive& ar)
  41. {
  42. CSprite::Serialize(ar);
  43. if (ar.IsStoring())
  44. {
  45. // ar << (DWORD) m_...;
  46. }
  47. else
  48. {
  49. // DWORD dw;
  50. // ar >> dw;
  51. // ....(dw);
  52. }
  53. }
  54. /////////////////////////////////////////////////////////////////////////////
  55. // CBlock commands
  56. void CBlock::SetMass(int iMass)
  57. {
  58. m_mass = iMass;
  59. }
  60. void CBlock::SetVelocity(int iVX, int iVY)
  61. {
  62. m_vx = iVX;
  63. m_vy = iVY;
  64. }
  65. // Update the position
  66. int CBlock::UpdatePosition(CBlockDoc *pDoc)
  67. {
  68. int d, x, y;
  69. x = m_x;
  70. y = m_y;
  71. CRect rcDoc;
  72. pDoc->GetSceneRect(&rcDoc);
  73. BOOL bChanged = FALSE;
  74. if (m_vx != 0) {
  75. m_dx += m_vx;
  76. d = m_dx / 100;
  77. if (d != 0) {
  78. x = m_x + d;
  79. m_dx = m_dx % 100;
  80. bChanged = TRUE;
  81. if (m_vx > 0) {
  82. if (x > rcDoc.right) x = -GetWidth();
  83. } else {
  84. if (x < -GetWidth()) x = rcDoc.right;
  85. }
  86. }
  87. }
  88. if (m_vy != 0) {
  89. m_dy += m_vy;
  90. d = m_dy / 100;
  91. if (d != 0) {
  92. y = m_y + d;
  93. m_dy = m_dy % 100;
  94. bChanged = TRUE;
  95. if (m_vy > 0) {
  96. if (y > rcDoc.bottom) y = -GetHeight();
  97. } else {
  98. if (y < -(GetHeight() <<1) ) y = rcDoc.bottom;
  99. }
  100. }
  101. }
  102. if (bChanged) {
  103. SetPosition(x, y);
  104. return 1;
  105. }
  106. return 0;
  107. }
  108. // test for sprite collision
  109. int CBlock::CollideTest(CBlock* pSprite)
  110. {
  111. // Do simple rectangle test first
  112. CRect rcThis, rcOther;
  113. GetRect(&rcThis);
  114. pSprite->GetRect(&rcOther);
  115. if (!rcThis.IntersectRect(&rcThis, &rcOther)) {
  116. // rectangles don't everlap
  117. return 0;
  118. }
  119. // The rectangles overlap
  120. // Compute the coordinates of the centers of the objects
  121. CRect rc1, rc2;
  122. GetRect(&rc1);
  123. pSprite->GetRect(&rc2);
  124. int x1 = rc1.left + (rc1.right - rc1.left) / 2;
  125. int y1 = rc1.top + (rc1.bottom - rc1.top) / 2;
  126. int x2 = rc2.left + (rc2.right - rc2.left) / 2;
  127. int y2 = rc2.top + (rc2.bottom - rc2.top) / 2;
  128. // compute the distance apart
  129. int dx = x1 - x2;
  130. int dy = y1 - y2;
  131. double d = sqrt(dx * dx + dy * dy);
  132. // see if they overlap
  133. if (d < (rc1.right - rc1.left) / 2 + (rc2.right - rc2.left) / 2) {
  134. return 1;
  135. }
  136. return 0;
  137. }
  138. // Collision handler
  139. int CBlock::OnCollide(CBlock* pSprite, CBlockDoc* pDoc)
  140. {
  141. // Do some physics
  142. if ((m_vx == 0) && (m_vy == 0)
  143. && (pSprite->GetX() == 0) && (pSprite->GetY() == 0)) {
  144. return 0;
  145. }
  146. // Compute the coordinates of the centers of the objects
  147. CRect rc1, rc2;
  148. GetRect(&rc1);
  149. pSprite->GetRect(&rc2);
  150. int x1 = rc1.left + (rc1.right - rc1.left) / 2;
  151. int y1 = rc1.top + (rc1.bottom - rc1.top) / 2;
  152. int x2 = rc2.left + (rc2.right - rc2.left) / 2;
  153. int y2 = rc2.top + (rc2.bottom - rc2.top) / 2;
  154. // compute the angle of the line joining the centers
  155. double a = atan2(y2 - y1, x2 - x1);
  156. double cos_a = cos(a);
  157. double sin_a = sin(a);
  158. // compute the velocities normal and perp
  159. // to the center line
  160. double vn1 = m_vx * cos_a + m_vy * sin_a;
  161. double vp1 = m_vy * cos_a - m_vx * sin_a;
  162. int vx2, vy2;
  163. pSprite->GetVelocity(&vx2, &vy2);
  164. double vn2 = vx2 * cos_a + vy2 * sin_a;
  165. double vp2 = vy2 * cos_a - vx2 * sin_a;
  166. // compute the momentum along the center line
  167. double m1 = m_mass;
  168. double m2 = pSprite->GetMass();
  169. double k = m1 * vn1 + m2 * vn2;
  170. // compute the energy
  171. double e = 0.5 * m1 * vn1 * vn1 + 0.5 * m2 * vn2 * vn2;
  172. // there are two possible solutions to the equations.
  173. // compute both and choose
  174. double temp1 = sqrt(k*k - ((m1/m2)+1)*(-2*e*m1 + k*k));
  175. double vn2p1 = (k + temp1) / (m1+m2);
  176. double vn2p2 = (k - temp1) / (m1+m2);
  177. // choose the soln. which is not the current state
  178. if (vn2p1 == vn2) {
  179. vn2 = vn2p2;
  180. } else {
  181. vn2 = vn2p1;
  182. }
  183. // compute the new vn1 value
  184. vn1 = (k - m2*vn2) / m1;
  185. // compute the new x and y velocities
  186. int vx1 = (int)(vn1 * cos_a - vp1 * sin_a);
  187. int vy1 = (int)(vn1 * sin_a + vp1 * cos_a);
  188. vx2 = (int)(vn2 * cos_a - vp2 * sin_a);
  189. vy2 = (int)(vn2 * sin_a + vp2 * cos_a);
  190. m_vx = vx1;
  191. m_vy = vy1;
  192. pSprite->SetVelocity(vx2, vy2);
  193. // move the sprites until they are no longer in collision
  194. if ((m_vx != 0) || (m_vy != 0) || (vx2 != 0) || (vy2 != 0)) {
  195. while(CollideTest(pSprite)) {
  196. UpdatePosition(pDoc);
  197. pSprite->UpdatePosition(pDoc);
  198. }
  199. }
  200. return 1; // say something changed
  201. }
  202. void CBlock::Stop()
  203. {
  204. SetVelocity(0,0);
  205. }