PhysWorld.cpp 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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. closestT = t;
  34. outColl.mPoint = l.PointOnSegment(t);
  35. outColl.mNormal = norm;
  36. outColl.mBox = box;
  37. outColl.mActor = box->GetOwner();
  38. collided = true;
  39. }
  40. }
  41. }
  42. return collided;
  43. }
  44. void PhysWorld::TestPairwise(std::function<void(Actor*, Actor*)> f)
  45. {
  46. // Naive implementation O(n^2)
  47. for (size_t i = 0; i < mBoxes.size(); i++)
  48. {
  49. // Don't need to test vs itself and any previous i values
  50. for (size_t j = i + 1; j < mBoxes.size(); j++)
  51. {
  52. BoxComponent* a = mBoxes[i];
  53. BoxComponent* b = mBoxes[j];
  54. if (Intersect(a->GetWorldBox(), b->GetWorldBox()))
  55. {
  56. // Call supplied function to handle intersection
  57. f(a->GetOwner(), b->GetOwner());
  58. }
  59. }
  60. }
  61. }
  62. void PhysWorld::TestSweepAndPrune(std::function<void(Actor*, Actor*)> f)
  63. {
  64. // Sort by min.x
  65. std::sort(mBoxes.begin(), mBoxes.end(),
  66. [](BoxComponent* a, BoxComponent* b) {
  67. return a->GetWorldBox().mMin.x <
  68. b->GetWorldBox().mMin.x;
  69. });
  70. for (size_t i = 0; i < mBoxes.size(); i++)
  71. {
  72. // Get max.x for current box
  73. BoxComponent* a = mBoxes[i];
  74. float max = a->GetWorldBox().mMax.x;
  75. for (size_t j = i + 1; j < mBoxes.size(); j++)
  76. {
  77. BoxComponent* b = mBoxes[j];
  78. // If AABB[j] min is past the max bounds of AABB[i],
  79. // then there aren't any other possible intersections
  80. // against AABB[i]
  81. if (b->GetWorldBox().mMin.x > max)
  82. {
  83. break;
  84. }
  85. else if (Intersect(a->GetWorldBox(), b->GetWorldBox()))
  86. {
  87. f(a->GetOwner(), b->GetOwner());
  88. }
  89. }
  90. }
  91. }
  92. void PhysWorld::AddBox(BoxComponent* box)
  93. {
  94. mBoxes.emplace_back(box);
  95. }
  96. void PhysWorld::RemoveBox(BoxComponent* box)
  97. {
  98. auto iter = std::find(mBoxes.begin(), mBoxes.end(), box);
  99. if (iter != mBoxes.end())
  100. {
  101. // Swap to end of vector and pop off (avoid erase copies)
  102. std::iter_swap(iter, mBoxes.end() - 1);
  103. mBoxes.pop_back();
  104. }
  105. }