PhysWorld.cpp 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // ----------------------------------------------------------------
  2. // From Game Programming in C++ by Sanjay Madhav
  3. // Copyright (C) 2017 Sanjay Madhav. All rights reserved.
  4. //
  5. // Released under the BSD License
  6. // See LICENSE in root directory for full details.
  7. // ----------------------------------------------------------------
  8. #include "PhysWorld.h"
  9. #include <algorithm>
  10. #include "BoxComponent.h"
  11. #include <SDL/SDL.h>
  12. PhysWorld::PhysWorld(Game* game)
  13. :mGame(game)
  14. {
  15. }
  16. bool PhysWorld::SegmentCast(const LineSegment& l, CollisionInfo& outColl)
  17. {
  18. bool collided = false;
  19. // Initialize closestT to infinity, so first
  20. // intersection will always update closestT
  21. float closestT = Math::Infinity;
  22. Vector3 norm;
  23. // Test against all boxes
  24. for (auto box : mBoxes)
  25. {
  26. float t;
  27. // Does the segment intersect with the box?
  28. if (Intersect(l, box->GetWorldBox(), t, norm))
  29. {
  30. // Is this closer than previous intersection?
  31. if (t < closestT)
  32. {
  33. outColl.mPoint = l.PointOnSegment(t);
  34. outColl.mNormal = norm;
  35. outColl.mBox = box;
  36. outColl.mActor = box->GetOwner();
  37. collided = true;
  38. }
  39. }
  40. }
  41. return collided;
  42. }
  43. void PhysWorld::TestPairwise(std::function<void(Actor*, Actor*)> f)
  44. {
  45. // Naive implementation O(n^2)
  46. for (size_t i = 0; i < mBoxes.size(); i++)
  47. {
  48. // Don't need to test vs itself and any previous i values
  49. for (size_t j = i + 1; j < mBoxes.size(); j++)
  50. {
  51. BoxComponent* a = mBoxes[i];
  52. BoxComponent* b = mBoxes[j];
  53. if (Intersect(a->GetWorldBox(), b->GetWorldBox()))
  54. {
  55. // Call supplied function to handle intersection
  56. f(a->GetOwner(), b->GetOwner());
  57. }
  58. }
  59. }
  60. }
  61. void PhysWorld::TestSweepAndPrune(std::function<void(Actor*, Actor*)> f)
  62. {
  63. // Sort by min.x
  64. std::sort(mBoxes.begin(), mBoxes.end(),
  65. [](BoxComponent* a, BoxComponent* b) {
  66. return a->GetWorldBox().mMin.x <
  67. b->GetWorldBox().mMin.x;
  68. });
  69. for (size_t i = 0; i < mBoxes.size(); i++)
  70. {
  71. // Get max.x for current box
  72. BoxComponent* a = mBoxes[i];
  73. float max = a->GetWorldBox().mMax.x;
  74. for (size_t j = i + 1; j < mBoxes.size(); j++)
  75. {
  76. BoxComponent* b = mBoxes[j];
  77. // If AABB[j] min is past the max bounds of AABB[i],
  78. // then there aren't any other possible intersections
  79. // against AABB[i]
  80. if (b->GetWorldBox().mMin.x > max)
  81. {
  82. break;
  83. }
  84. else if (Intersect(a->GetWorldBox(), b->GetWorldBox()))
  85. {
  86. f(a->GetOwner(), b->GetOwner());
  87. }
  88. }
  89. }
  90. }
  91. void PhysWorld::AddBox(BoxComponent* box)
  92. {
  93. mBoxes.emplace_back(box);
  94. }
  95. void PhysWorld::RemoveBox(BoxComponent* box)
  96. {
  97. auto iter = std::find(mBoxes.begin(), mBoxes.end(), box);
  98. if (iter != mBoxes.end())
  99. {
  100. // Swap to end of vector and pop off (avoid erase copies)
  101. std::iter_swap(iter, mBoxes.end() - 1);
  102. mBoxes.pop_back();
  103. }
  104. }