CollisionSample.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. //-----------------------------------------------------------------------------
  2. // CollisionSample.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. using Microsoft.Xna.Framework;
  11. using Microsoft.Xna.Framework.Audio;
  12. using Microsoft.Xna.Framework.Graphics;
  13. using Microsoft.Xna.Framework.Input;
  14. using Microsoft.Xna.Framework.Input.Touch;
  15. using Microsoft.Xna.Framework.Media;
  16. namespace CollisionSample
  17. {
  18. /// <summary>
  19. /// This sample demonstrates various forms of collision detection for primitives
  20. /// supplied in the framework, plus oriented bounding boxes and triangles.
  21. /// </summary>
  22. public class CollisionGame : Game
  23. {
  24. public const int FrustumGroupIndex = 0;
  25. public const int AABoxGroupIndex = 1;
  26. public const int OBoxGroupIndex = 2;
  27. public const int SphereGroupIndex = 3;
  28. public const int RayGroupIndex = 4;
  29. public const int NumGroups = 5;
  30. public const int TriIndex = 0;
  31. public const int SphereIndex = 1;
  32. public const int AABoxIndex = 2;
  33. public const int OBoxIndex = 3;
  34. public const int NumSecondaryShapes = 4;
  35. public const float CAMERA_SPACING = 50.0F;
  36. public const float YAW_RATE = 1; // radians per second for keyboard controls
  37. public const float PITCH_RATE = 0.75f; // radians per second for keyboard controls
  38. public const float YAW_DRAG_RATE = .01f; // radians per pixel for drag control
  39. public const float PITCH_DRAG_RATE = .01f; // radians per pixel for drag control
  40. public const float PINCH_ZOOM_RATE = .01f; // scale factor for pinch-zoom rate
  41. public const float DISTANCE_RATE = 10;
  42. // Rendering helpers
  43. GraphicsDeviceManager graphics;
  44. DebugDraw debugDraw;
  45. // Primary shapes
  46. BoundingFrustum primaryFrustum;
  47. BoundingBox primaryAABox;
  48. BoundingOrientedBox primaryOBox;
  49. BoundingSphere primarySphere;
  50. Ray primaryRay;
  51. // Secondary shapes.
  52. Triangle[] secondaryTris = new Triangle[NumGroups];
  53. BoundingSphere[] secondarySpheres = new BoundingSphere[NumGroups];
  54. BoundingBox[] secondaryAABoxes = new BoundingBox[NumGroups];
  55. BoundingOrientedBox[] secondaryOBoxes = new BoundingOrientedBox[NumGroups];
  56. // Collision results
  57. ContainmentType[,] collideResults = new ContainmentType[NumGroups, NumSecondaryShapes];
  58. Vector3? rayHitResult;
  59. // Camera state
  60. Vector3[] cameraOrigins = new Vector3[NumGroups];
  61. int currentCamera;
  62. bool cameraOrtho;
  63. float cameraYaw;
  64. float cameraPitch;
  65. float cameraDistance;
  66. Vector3 cameraTarget;
  67. KeyboardState currentKeyboardState = new KeyboardState();
  68. GamePadState currentGamePadState = new GamePadState();
  69. List<GestureSample> currentGestures = new List<GestureSample>();
  70. KeyboardState previousKeyboardState = new KeyboardState();
  71. GamePadState previousGamePadState = new GamePadState();
  72. TimeSpan unpausedClock = new TimeSpan();
  73. bool paused;
  74. public CollisionGame()
  75. {
  76. graphics = new GraphicsDeviceManager(this);
  77. Content.RootDirectory = "Content";
  78. TouchPanel.EnabledGestures = GestureType.Tap | GestureType.Pinch | GestureType.FreeDrag;
  79. graphics.PreferredBackBufferWidth = 480;
  80. graphics.PreferredBackBufferHeight = 640;
  81. IsMouseVisible = true;
  82. #if ____MOBILE___
  83. graphics.IsFullScreen = true;
  84. #endif
  85. }
  86. // Set up initial bounding shapes for the primary (static) and secondary (moving)
  87. // bounding shapes along with relevant camera position information.
  88. protected override void Initialize()
  89. {
  90. Console.WriteLine("DEBUG - Game Initialize!");
  91. debugDraw = new DebugDraw(GraphicsDevice);
  92. Components.Add(new FrameRateCounter(this));
  93. // Primary frustum
  94. Matrix m1 = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 1.77778F, 0.5f, 10.0f);
  95. Matrix m2 = Matrix.CreateTranslation(new Vector3(0, 0, -7));
  96. primaryFrustum = new BoundingFrustum(Matrix.Multiply(m2, m1));
  97. cameraOrigins[FrustumGroupIndex] = Vector3.Zero;
  98. // Primary axis-aligned box
  99. primaryAABox.Min = new Vector3(CAMERA_SPACING - 3, -4, -5);
  100. primaryAABox.Max = new Vector3(CAMERA_SPACING + 3, 4, 5);
  101. cameraOrigins[AABoxGroupIndex] = new Vector3(CAMERA_SPACING, 0, 0);
  102. // Primary oriented box
  103. primaryOBox.Center = new Vector3(-CAMERA_SPACING, 0, 0);
  104. primaryOBox.HalfExtent = new Vector3(3, 4, 5);
  105. primaryOBox.Orientation = Quaternion.CreateFromYawPitchRoll(0.8f, 0.7f, 0);
  106. cameraOrigins[OBoxGroupIndex] = primaryOBox.Center;
  107. // Primary sphere
  108. primarySphere.Center = new Vector3(0, 0, -CAMERA_SPACING);
  109. primarySphere.Radius = 5;
  110. cameraOrigins[SphereGroupIndex] = primarySphere.Center;
  111. // Primary ray
  112. primaryRay.Position = new Vector3(0, 0, CAMERA_SPACING);
  113. primaryRay.Direction = Vector3.UnitZ;
  114. cameraOrigins[RayGroupIndex] = primaryRay.Position;
  115. // Initialize all of the secondary objects with default values
  116. Vector3 half = new Vector3(0.5F, 0.5F, 0.5F);
  117. for (int i = 0; i < NumGroups; i++)
  118. {
  119. secondarySpheres[i] = new BoundingSphere(Vector3.Zero, 1.0f);
  120. secondaryOBoxes[i] = new BoundingOrientedBox(Vector3.Zero, half, Quaternion.Identity);
  121. secondaryAABoxes[i] = new BoundingBox(-half, half);
  122. secondaryTris[i] = new Triangle();
  123. }
  124. rayHitResult = null;
  125. currentCamera = 3;
  126. cameraOrtho = false;
  127. cameraYaw = (float)Math.PI * 0.75F;
  128. cameraPitch = MathHelper.PiOver4;
  129. cameraDistance = 20;
  130. cameraTarget = cameraOrigins[0];
  131. paused = false;
  132. base.Initialize();
  133. }
  134. protected override void Update(GameTime gameTime)
  135. {
  136. ReadInputDevices();
  137. if (currentKeyboardState.IsKeyDown(Keys.Escape) || currentGamePadState.IsButtonDown(Buttons.Back))
  138. this.Exit();
  139. if (!paused)
  140. {
  141. unpausedClock += gameTime.ElapsedGameTime;
  142. }
  143. // Run collision even when paused, for timing and debugging, and so the step
  144. // forward/backward keys work.
  145. Animate();
  146. Collide();
  147. HandleInput(gameTime);
  148. base.Update(gameTime);
  149. }
  150. private void ReadInputDevices()
  151. {
  152. previousKeyboardState = currentKeyboardState;
  153. previousGamePadState = currentGamePadState;
  154. currentKeyboardState = Keyboard.GetState();
  155. currentGamePadState = GamePad.GetState(PlayerIndex.One);
  156. currentGestures.Clear();
  157. while (TouchPanel.IsGestureAvailable)
  158. {
  159. currentGestures.Add(TouchPanel.ReadGesture());
  160. }
  161. }
  162. /// <summary>
  163. /// Move all the secondary shapes around, and move the ray so it
  164. /// sweeps back and forth across its secondry shapes.
  165. /// </summary>
  166. private void Animate()
  167. {
  168. float t = (float)unpausedClock.TotalSeconds / 2.0F;
  169. // Rates at which x,y,z cycle
  170. const float xRate = 1.1f;
  171. const float yRate = 3.6f;
  172. const float zRate = 1.9f;
  173. const float pathSize = 6;
  174. // how far apart following shapes are, in seconds
  175. const float gap = 0.25f;
  176. // orientation for rotatable shapes
  177. Quaternion orientation = Quaternion.CreateFromYawPitchRoll(t * 0.2f, t * 1.4f, t);
  178. for (int g = 0; g < NumGroups; g++)
  179. {
  180. // Animate spheres
  181. secondarySpheres[g].Center = cameraOrigins[g];
  182. secondarySpheres[g].Center.X += pathSize * (float)Math.Sin(xRate * t);
  183. secondarySpheres[g].Center.Y += pathSize * (float)Math.Sin(yRate * t);
  184. secondarySpheres[g].Center.Z += pathSize * (float)Math.Sin(zRate * t);
  185. // Animate oriented boxes
  186. secondaryOBoxes[g].Center = cameraOrigins[g];
  187. secondaryOBoxes[g].Orientation = orientation;
  188. secondaryOBoxes[g].Center.X += pathSize * (float)Math.Sin(xRate * (t - gap));
  189. secondaryOBoxes[g].Center.Y += pathSize * (float)Math.Sin(yRate * (t - gap));
  190. secondaryOBoxes[g].Center.Z += pathSize * (float)Math.Sin(zRate * (t - gap));
  191. // Animate axis-aligned boxes
  192. Vector3 boxsize = new Vector3(1.0f, 1.3f, 1.9f);
  193. secondaryAABoxes[g].Min = cameraOrigins[g] - boxsize * 0.5f;
  194. secondaryAABoxes[g].Min.X += pathSize * (float)Math.Sin(xRate * (t - 2 * gap));
  195. secondaryAABoxes[g].Min.Y += pathSize * (float)Math.Sin(yRate * (t - 2 * gap));
  196. secondaryAABoxes[g].Min.Z += pathSize * (float)Math.Sin(zRate * (t - 2 * gap));
  197. secondaryAABoxes[g].Max = secondaryAABoxes[g].Min + boxsize;
  198. // Animate triangles
  199. Vector3 trianglePos = cameraOrigins[g];
  200. trianglePos.X += pathSize * (float)Math.Sin(xRate * (t - 3 * gap));
  201. trianglePos.Y += pathSize * (float)Math.Sin(yRate * (t - 3 * gap));
  202. trianglePos.Z += pathSize * (float)Math.Sin(zRate * (t - 3 * gap));
  203. // triangle points in local space - equilateral triangle with radius of 2
  204. secondaryTris[g].V0 = trianglePos + Vector3.Transform(new Vector3(0, 2, 0), orientation);
  205. secondaryTris[g].V1 = trianglePos + Vector3.Transform(new Vector3(1.73f, -1, 0), orientation);
  206. secondaryTris[g].V2 = trianglePos + Vector3.Transform(new Vector3(-1.73f, -1, 0), orientation);
  207. }
  208. //int index = (int)(t*5);
  209. //secondaryOBoxes[OBoxGroupIndex] = BoundingOrientedBox.iboxes[index % BoundingOrientedBox.iboxes.Length];
  210. // Animate primary ray (this is the only animated primary object)
  211. // It sweeps back and forth across the secondary objects
  212. const float sweepTime = 3.1f;
  213. float rayDt = (-Math.Abs((t / sweepTime) % 2.0f - 1.0f) * NumSecondaryShapes + 0.5f) * gap;
  214. primaryRay.Direction.X = (float)Math.Sin(xRate * (t + rayDt));
  215. primaryRay.Direction.Y = (float)Math.Sin(yRate * (t + rayDt));
  216. primaryRay.Direction.Z = (float)Math.Sin(zRate * (t + rayDt));
  217. primaryRay.Direction.Normalize();
  218. }
  219. /// <summary>
  220. /// Check each pair of objects for collision/containment and store the results for
  221. /// coloring them at render time.
  222. /// </summary>
  223. private void Collide()
  224. {
  225. // test collisions between objects and frustum
  226. collideResults[FrustumGroupIndex, SphereIndex] = primaryFrustum.Contains(secondarySpheres[FrustumGroupIndex]);
  227. collideResults[FrustumGroupIndex, OBoxIndex] = BoundingOrientedBox.Contains(primaryFrustum, ref secondaryOBoxes[FrustumGroupIndex]);
  228. collideResults[FrustumGroupIndex, AABoxIndex] = primaryFrustum.Contains(secondaryAABoxes[FrustumGroupIndex]);
  229. collideResults[FrustumGroupIndex, TriIndex] = TriangleTest.Contains(primaryFrustum, ref secondaryTris[FrustumGroupIndex]);
  230. // test collisions between objects and aligned box
  231. collideResults[AABoxGroupIndex, SphereIndex] = primaryAABox.Contains(secondarySpheres[AABoxGroupIndex]);
  232. collideResults[AABoxGroupIndex, OBoxIndex] = BoundingOrientedBox.Contains(ref primaryAABox, ref secondaryOBoxes[AABoxGroupIndex]);
  233. collideResults[AABoxGroupIndex, AABoxIndex] = primaryAABox.Contains(secondaryAABoxes[AABoxGroupIndex]);
  234. collideResults[AABoxGroupIndex, TriIndex] = TriangleTest.Contains(ref primaryAABox, ref secondaryTris[AABoxGroupIndex]);
  235. // test collisions between objects and oriented box
  236. collideResults[OBoxGroupIndex, SphereIndex] = primaryOBox.Contains(ref secondarySpheres[OBoxGroupIndex]);
  237. collideResults[OBoxGroupIndex, OBoxIndex] = primaryOBox.Contains(ref secondaryOBoxes[OBoxGroupIndex]);
  238. collideResults[OBoxGroupIndex, AABoxIndex] = primaryOBox.Contains(ref secondaryAABoxes[OBoxGroupIndex]);
  239. collideResults[OBoxGroupIndex, TriIndex] = TriangleTest.Contains(ref primaryOBox, ref secondaryTris[OBoxGroupIndex]);
  240. // test collisions between objects and sphere
  241. collideResults[SphereGroupIndex, SphereIndex] = primarySphere.Contains(secondarySpheres[SphereGroupIndex]);
  242. collideResults[SphereGroupIndex, OBoxIndex] = BoundingOrientedBox.Contains(ref primarySphere, ref secondaryOBoxes[SphereGroupIndex]);
  243. collideResults[SphereGroupIndex, AABoxIndex] = primarySphere.Contains(secondaryAABoxes[SphereGroupIndex]);
  244. collideResults[SphereGroupIndex, TriIndex] = TriangleTest.Contains(ref primarySphere, ref secondaryTris[SphereGroupIndex]);
  245. // test collisions between objects and ray
  246. float dist = -1;
  247. collideResults[RayGroupIndex, SphereIndex] =
  248. collideResults[RayGroupIndex, OBoxIndex] =
  249. collideResults[RayGroupIndex, AABoxIndex] =
  250. collideResults[RayGroupIndex, TriIndex] = ContainmentType.Disjoint;
  251. rayHitResult = null;
  252. float? r = primaryRay.Intersects(secondarySpheres[RayGroupIndex]);
  253. if (r.HasValue)
  254. {
  255. collideResults[RayGroupIndex, SphereIndex] = ContainmentType.Intersects;
  256. dist = r.Value;
  257. }
  258. r = secondaryOBoxes[RayGroupIndex].Intersects(ref primaryRay);
  259. if (r.HasValue)
  260. {
  261. collideResults[RayGroupIndex, OBoxIndex] = ContainmentType.Intersects;
  262. dist = r.Value;
  263. }
  264. r = primaryRay.Intersects(secondaryAABoxes[RayGroupIndex]);
  265. if (r.HasValue)
  266. {
  267. collideResults[RayGroupIndex, AABoxIndex] = ContainmentType.Intersects;
  268. dist = r.Value;
  269. }
  270. r = TriangleTest.Intersects(ref primaryRay, ref secondaryTris[RayGroupIndex]);
  271. if (r.HasValue)
  272. {
  273. collideResults[RayGroupIndex, TriIndex] = ContainmentType.Intersects;
  274. dist = r.Value;
  275. }
  276. // If one of the ray intersection tests was successful, fDistance will be positive.
  277. // If so, compute the intersection location and store it in g_RayHitResultBox.
  278. if (dist > 0)
  279. {
  280. rayHitResult = primaryRay.Position + primaryRay.Direction * dist;
  281. }
  282. }
  283. private void HandleInput(GameTime gameTime)
  284. {
  285. // Rely on the fact that we are using fixed time-step update
  286. float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
  287. // Allow single-stepping through time
  288. if (paused)
  289. {
  290. if (currentKeyboardState.IsKeyDown(Keys.OemOpenBrackets))
  291. unpausedClock -= TimeSpan.FromSeconds(dt);
  292. if (currentKeyboardState.IsKeyDown(Keys.OemCloseBrackets))
  293. unpausedClock += TimeSpan.FromSeconds(dt);
  294. }
  295. // Change yaw/pitch based on right thumbstickb
  296. cameraYaw += currentGamePadState.ThumbSticks.Right.X * dt * YAW_RATE;
  297. cameraPitch += currentGamePadState.ThumbSticks.Right.Y * dt * PITCH_RATE;
  298. if (currentKeyboardState.IsKeyDown(Keys.Right))
  299. cameraYaw += dt * YAW_RATE;
  300. if (currentKeyboardState.IsKeyDown(Keys.Left))
  301. cameraYaw -= dt * YAW_RATE;
  302. if (currentKeyboardState.IsKeyDown(Keys.Up))
  303. cameraPitch += dt * PITCH_RATE;
  304. if (currentKeyboardState.IsKeyDown(Keys.Down))
  305. cameraPitch -= dt * PITCH_RATE;
  306. // Change distance based on right/left trigger
  307. if (currentGamePadState.IsButtonDown(Buttons.LeftTrigger)
  308. || currentKeyboardState.IsKeyDown(Keys.Subtract)
  309. || currentKeyboardState.IsKeyDown(Keys.OemMinus))
  310. {
  311. cameraDistance += dt * DISTANCE_RATE;
  312. }
  313. if (currentGamePadState.IsButtonDown(Buttons.RightTrigger)
  314. || currentKeyboardState.IsKeyDown(Keys.Add)
  315. || currentKeyboardState.IsKeyDown(Keys.OemPlus))
  316. {
  317. cameraDistance -= dt * DISTANCE_RATE;
  318. }
  319. // Group cycle
  320. if ((currentKeyboardState.IsKeyDown(Keys.G) && previousKeyboardState.IsKeyUp(Keys.G)) ||
  321. (currentGamePadState.IsButtonDown(Buttons.A) && previousGamePadState.IsButtonUp(Buttons.A)))
  322. {
  323. currentCamera = (currentCamera + 1) % NumGroups;
  324. }
  325. // Camera reset
  326. if ((currentKeyboardState.IsKeyDown(Keys.Home) && previousKeyboardState.IsKeyUp(Keys.Home))
  327. || (currentGamePadState.IsButtonDown(Buttons.Y) && previousGamePadState.IsButtonUp(Buttons.Y)))
  328. {
  329. cameraYaw = (float)Math.PI * 0.75F;
  330. cameraPitch = MathHelper.PiOver4;
  331. cameraDistance = 40;
  332. }
  333. // Orthographic vs. perpsective projection toggle
  334. if ((currentKeyboardState.IsKeyDown(Keys.B) && previousKeyboardState.IsKeyUp(Keys.B))
  335. || (currentGamePadState.IsButtonDown(Buttons.B) && previousGamePadState.IsButtonUp(Buttons.B)))
  336. {
  337. cameraOrtho = !cameraOrtho;
  338. }
  339. if (currentKeyboardState.IsKeyDown(Keys.O))
  340. {
  341. cameraOrtho = true;
  342. }
  343. if (currentKeyboardState.IsKeyDown(Keys.P))
  344. {
  345. cameraOrtho = false;
  346. }
  347. // Pause animation
  348. if ((currentKeyboardState.IsKeyDown(Keys.Space) && previousKeyboardState.IsKeyUp(Keys.Space))
  349. || (currentGamePadState.IsButtonDown(Buttons.X) && previousGamePadState.IsButtonUp(Buttons.X)))
  350. {
  351. paused = !paused;
  352. }
  353. // Handle tap, drag, and pinch gestures
  354. foreach (GestureSample sample in currentGestures)
  355. {
  356. switch (sample.GestureType)
  357. {
  358. case GestureType.Tap:
  359. currentCamera = (currentCamera + 1) % NumGroups;
  360. break;
  361. case GestureType.FreeDrag:
  362. cameraYaw += sample.Delta.X * -YAW_DRAG_RATE;
  363. cameraPitch += sample.Delta.Y * PITCH_DRAG_RATE;
  364. break;
  365. case GestureType.Pinch:
  366. float dOld = Vector2.Distance(sample.Position - sample.Delta, sample.Position2 - sample.Delta2);
  367. float dNew = Vector2.Distance(sample.Position, sample.Position2);
  368. cameraDistance *= (float)Math.Exp((dOld - dNew) * PINCH_ZOOM_RATE);
  369. break;
  370. }
  371. }
  372. // Clamp camera to safe values
  373. cameraYaw = MathHelper.WrapAngle(cameraYaw);
  374. cameraPitch = MathHelper.Clamp(cameraPitch, -MathHelper.PiOver2, MathHelper.PiOver2);
  375. cameraDistance = MathHelper.Clamp(cameraDistance, 2, 80);
  376. // Handle time-based lerp for group transition
  377. float lerp = Math.Min(4.0F * dt, 1.0F);
  378. cameraTarget = (lerp * cameraOrigins[currentCamera]) + ((1.0F - lerp) * cameraTarget);
  379. }
  380. /// <summary>
  381. /// This draws the bounding shapes and HUD for the sample.
  382. /// </summary>
  383. /// <param name="gameTime">Provides a snapshot of timing values.</param>
  384. protected override void Draw(GameTime gameTime)
  385. {
  386. GraphicsDevice.Clear(Color.MonoGameOrange);
  387. float aspect = GraphicsDevice.Viewport.AspectRatio;
  388. float yawCos = (float)Math.Cos(cameraYaw);
  389. float yawSin = (float)Math.Sin(cameraYaw);
  390. float pitchCos = (float)Math.Cos(cameraPitch);
  391. float pitchSin = (float)Math.Sin(cameraPitch);
  392. Vector3 eye = new Vector3(cameraDistance * pitchCos * yawSin + cameraTarget.X,
  393. cameraDistance * pitchSin + cameraTarget.Y,
  394. cameraDistance * pitchCos * yawCos + cameraTarget.Z);
  395. Matrix view = Matrix.CreateLookAt(eye, cameraTarget, Vector3.Up);
  396. Matrix projection = (cameraOrtho)
  397. ? Matrix.CreateOrthographic(aspect * cameraDistance, cameraDistance, 1.0F, 1000.0F)
  398. : Matrix.CreatePerspectiveFieldOfView((float)(System.Math.PI) / 4.0F, aspect, 1.0F, 1000.0F);
  399. debugDraw.Begin(view, projection);
  400. // Draw ground planes
  401. for (int g = 0; g < NumGroups; ++g)
  402. {
  403. Vector3 origin = new Vector3(cameraOrigins[g].X - 20, cameraOrigins[g].Y - 10, cameraOrigins[g].Z - 20);
  404. debugDraw.DrawWireGrid(Vector3.UnitX * 40, Vector3.UnitZ * 40, origin, 20, 20, Color.Black);
  405. }
  406. DrawPrimaryShapes();
  407. // Draw secondary shapes
  408. for (int g = 0; g < NumGroups; g++)
  409. {
  410. debugDraw.DrawWireSphere(secondarySpheres[g], GetCollideColor(g, SphereIndex));
  411. debugDraw.DrawWireBox(secondaryAABoxes[g], GetCollideColor(g, AABoxIndex));
  412. debugDraw.DrawWireBox(secondaryOBoxes[g], GetCollideColor(g, OBoxIndex));
  413. debugDraw.DrawWireTriangle(secondaryTris[g], GetCollideColor(g, TriIndex));
  414. }
  415. // Draw results of ray-object intersection, if there was a hit this frame
  416. if (rayHitResult.HasValue)
  417. {
  418. Vector3 size = new Vector3(0.05f, 0.05f, 0.05f);
  419. BoundingBox weeBox = new BoundingBox(rayHitResult.Value - size, rayHitResult.Value + size);
  420. debugDraw.DrawWireBox(weeBox, Color.Yellow);
  421. }
  422. debugDraw.End();
  423. // Draw overlay text.
  424. // string text = "A = (G)roup\nY = Reset (Home)\nB = (O)rtho/(P)erspective\nX = Pause (Space)";
  425. // spriteBatch.Begin();
  426. // spriteBatch.DrawString(spriteFont, text, new Vector2(86, 48), Color.White);
  427. // spriteBatch.End();
  428. base.Draw(gameTime);
  429. }
  430. void DrawPrimaryShapes()
  431. {
  432. debugDraw.DrawWireBox(primaryAABox, Color.White);
  433. debugDraw.DrawWireBox(primaryOBox, Color.White);
  434. debugDraw.DrawWireFrustum(primaryFrustum, Color.White);
  435. debugDraw.DrawWireSphere(primarySphere, Color.White);
  436. debugDraw.DrawRay(primaryRay, Color.Red, 10.0f);
  437. }
  438. private Color GetCollideColor(int group, int shape)
  439. {
  440. ContainmentType cr = collideResults[group, shape];
  441. switch (cr)
  442. {
  443. case ContainmentType.Contains:
  444. return Color.Blue;
  445. case ContainmentType.Disjoint:
  446. return Color.LightGray;
  447. case ContainmentType.Intersects:
  448. return Color.Yellow;
  449. default:
  450. return Color.Black;
  451. }
  452. }
  453. }
  454. }