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.

238 lines
5.6 KiB

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