PhysicsWorld2D.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. #include "../Precompiled.h"
  4. #include "../Core/Context.h"
  5. #include "../Core/Profiler.h"
  6. #include "../Graphics/DebugRenderer.h"
  7. #include "../Graphics/Graphics.h"
  8. #include "../Graphics/Renderer.h"
  9. #include "../IO/Log.h"
  10. #include "../Physics2D/CollisionShape2D.h"
  11. #include "../Physics2D/PhysicsEvents2D.h"
  12. #include "../Physics2D/PhysicsUtils2D.h"
  13. #include "../Physics2D/PhysicsWorld2D.h"
  14. #include "../Physics2D/RigidBody2D.h"
  15. #include "../Scene/Scene.h"
  16. #include "../Scene/SceneEvents.h"
  17. #include "../DebugNew.h"
  18. using namespace std;
  19. namespace Urho3D
  20. {
  21. extern const char* SUBSYSTEM_CATEGORY;
  22. static const Vector2 DEFAULT_GRAVITY(0.0f, -9.81f);
  23. static const int DEFAULT_VELOCITY_ITERATIONS = 8;
  24. static const int DEFAULT_POSITION_ITERATIONS = 3;
  25. PhysicsWorld2D::PhysicsWorld2D(Context* context) :
  26. Component(context),
  27. gravity_(DEFAULT_GRAVITY),
  28. velocityIterations_(DEFAULT_VELOCITY_ITERATIONS),
  29. positionIterations_(DEFAULT_POSITION_ITERATIONS)
  30. {
  31. // Set default debug draw flags
  32. m_drawFlags = e_shapeBit;
  33. // Create Box2D world
  34. world_ = make_unique<b2World>(ToB2Vec2(gravity_));
  35. // Set contact listener
  36. world_->SetContactListener(this);
  37. // Set debug draw
  38. world_->SetDebugDraw(this);
  39. }
  40. PhysicsWorld2D::~PhysicsWorld2D()
  41. {
  42. for (const WeakPtr<RigidBody2D>& rigidBody : rigidBodies_)
  43. {
  44. if (rigidBody)
  45. rigidBody->ReleaseBody();
  46. }
  47. }
  48. void PhysicsWorld2D::RegisterObject(Context* context)
  49. {
  50. context->RegisterFactory<PhysicsWorld2D>(SUBSYSTEM_CATEGORY);
  51. URHO3D_ACCESSOR_ATTRIBUTE("Draw Shape", GetDrawShape, SetDrawShape, false, AM_DEFAULT);
  52. URHO3D_ACCESSOR_ATTRIBUTE("Draw Joint", GetDrawJoint, SetDrawJoint, false, AM_DEFAULT);
  53. URHO3D_ACCESSOR_ATTRIBUTE("Draw Aabb", GetDrawAabb, SetDrawAabb, false, AM_DEFAULT);
  54. URHO3D_ACCESSOR_ATTRIBUTE("Draw Pair", GetDrawPair, SetDrawPair, false, AM_DEFAULT);
  55. URHO3D_ACCESSOR_ATTRIBUTE("Draw CenterOfMass", GetDrawCenterOfMass, SetDrawCenterOfMass, false, AM_DEFAULT);
  56. URHO3D_ACCESSOR_ATTRIBUTE("Allow Sleeping", GetAllowSleeping, SetAllowSleeping, false, AM_DEFAULT);
  57. URHO3D_ACCESSOR_ATTRIBUTE("Warm Starting", GetWarmStarting, SetWarmStarting, false, AM_DEFAULT);
  58. URHO3D_ACCESSOR_ATTRIBUTE("Continuous Physics", GetContinuousPhysics, SetContinuousPhysics, true, AM_DEFAULT);
  59. URHO3D_ACCESSOR_ATTRIBUTE("Sub Stepping", GetSubStepping, SetSubStepping, false, AM_DEFAULT);
  60. URHO3D_ACCESSOR_ATTRIBUTE("Gravity", GetGravity, SetGravity, DEFAULT_GRAVITY, AM_DEFAULT);
  61. URHO3D_ACCESSOR_ATTRIBUTE("Auto Clear Forces", GetAutoClearForces, SetAutoClearForces, false, AM_DEFAULT);
  62. URHO3D_ACCESSOR_ATTRIBUTE("Velocity Iterations", GetVelocityIterations, SetVelocityIterations, DEFAULT_VELOCITY_ITERATIONS,
  63. AM_DEFAULT);
  64. URHO3D_ACCESSOR_ATTRIBUTE("Position Iterations", GetPositionIterations, SetPositionIterations, DEFAULT_POSITION_ITERATIONS,
  65. AM_DEFAULT);
  66. }
  67. void PhysicsWorld2D::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
  68. {
  69. if (debug)
  70. {
  71. URHO3D_PROFILE(Physics2DDrawDebug);
  72. debugRenderer_ = debug;
  73. debugDepthTest_ = depthTest;
  74. world_->DebugDraw();
  75. debugRenderer_ = nullptr;
  76. }
  77. }
  78. void PhysicsWorld2D::BeginContact(b2Contact* contact)
  79. {
  80. // Only handle contact event while stepping the physics simulation
  81. if (!physicsStepping_)
  82. return;
  83. b2Fixture* fixtureA = contact->GetFixtureA();
  84. b2Fixture* fixtureB = contact->GetFixtureB();
  85. if (!fixtureA || !fixtureB)
  86. return;
  87. beginContactInfos_.Push(ContactInfo(contact));
  88. }
  89. void PhysicsWorld2D::EndContact(b2Contact* contact)
  90. {
  91. if (!physicsStepping_)
  92. return;
  93. b2Fixture* fixtureA = contact->GetFixtureA();
  94. b2Fixture* fixtureB = contact->GetFixtureB();
  95. if (!fixtureA || !fixtureB)
  96. return;
  97. endContactInfos_.Push(ContactInfo(contact));
  98. }
  99. void PhysicsWorld2D::PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
  100. {
  101. b2Fixture* fixtureA = contact->GetFixtureA();
  102. b2Fixture* fixtureB = contact->GetFixtureB();
  103. if (!fixtureA || !fixtureB)
  104. return;
  105. ContactInfo contactInfo(contact);
  106. // Send global event
  107. VariantMap& eventData = GetEventDataMap();
  108. eventData[PhysicsUpdateContact2D::P_WORLD] = this;
  109. eventData[PhysicsUpdateContact2D::P_ENABLED] = contact->IsEnabled();
  110. eventData[PhysicsUpdateContact2D::P_BODYA] = contactInfo.bodyA_.Get();
  111. eventData[PhysicsUpdateContact2D::P_BODYB] = contactInfo.bodyB_.Get();
  112. eventData[PhysicsUpdateContact2D::P_NODEA] = contactInfo.nodeA_.Get();
  113. eventData[PhysicsUpdateContact2D::P_NODEB] = contactInfo.nodeB_.Get();
  114. eventData[PhysicsUpdateContact2D::P_CONTACTS] = contactInfo.Serialize(contacts_);
  115. eventData[PhysicsUpdateContact2D::P_SHAPEA] = contactInfo.shapeA_.Get();
  116. eventData[PhysicsUpdateContact2D::P_SHAPEB] = contactInfo.shapeB_.Get();
  117. SendEvent(E_PHYSICSUPDATECONTACT2D, eventData);
  118. contact->SetEnabled(eventData[PhysicsUpdateContact2D::P_ENABLED].GetBool());
  119. eventData.Clear();
  120. // Send node event
  121. eventData[NodeUpdateContact2D::P_ENABLED] = contact->IsEnabled();
  122. eventData[NodeUpdateContact2D::P_CONTACTS] = contactInfo.Serialize(contacts_);
  123. if (contactInfo.nodeA_)
  124. {
  125. eventData[NodeUpdateContact2D::P_BODY] = contactInfo.bodyA_.Get();
  126. eventData[NodeUpdateContact2D::P_OTHERNODE] = contactInfo.nodeB_.Get();
  127. eventData[NodeUpdateContact2D::P_OTHERBODY] = contactInfo.bodyB_.Get();
  128. eventData[NodeUpdateContact2D::P_SHAPE] = contactInfo.shapeA_.Get();
  129. eventData[NodeUpdateContact2D::P_OTHERSHAPE] = contactInfo.shapeB_.Get();
  130. contactInfo.nodeA_->SendEvent(E_NODEUPDATECONTACT2D, eventData);
  131. }
  132. if (contactInfo.nodeB_)
  133. {
  134. eventData[NodeUpdateContact2D::P_BODY] = contactInfo.bodyB_.Get();
  135. eventData[NodeUpdateContact2D::P_OTHERNODE] = contactInfo.nodeA_.Get();
  136. eventData[NodeUpdateContact2D::P_OTHERBODY] = contactInfo.bodyA_.Get();
  137. eventData[NodeUpdateContact2D::P_SHAPE] = contactInfo.shapeB_.Get();
  138. eventData[NodeUpdateContact2D::P_OTHERSHAPE] = contactInfo.shapeA_.Get();
  139. contactInfo.nodeB_->SendEvent(E_NODEUPDATECONTACT2D, eventData);
  140. }
  141. contact->SetEnabled(eventData[NodeUpdateContact2D::P_ENABLED].GetBool());
  142. }
  143. void PhysicsWorld2D::DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color)
  144. {
  145. if (!debugRenderer_)
  146. return;
  147. Color c = ToColor(color);
  148. for (int i = 0; i < vertexCount - 1; ++i)
  149. debugRenderer_->AddLine(ToVector3(vertices[i]), ToVector3(vertices[i + 1]), c, debugDepthTest_);
  150. debugRenderer_->AddLine(ToVector3(vertices[vertexCount - 1]), ToVector3(vertices[0]), c, debugDepthTest_);
  151. }
  152. void PhysicsWorld2D::DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color)
  153. {
  154. if (!debugRenderer_)
  155. return;
  156. Vector3 v = ToVector3(vertices[0]);
  157. Color c(color.r, color.g, color.b, 0.5f);
  158. for (int i = 1; i < vertexCount - 1; ++i)
  159. debugRenderer_->AddTriangle(v, ToVector3(vertices[i]), ToVector3(vertices[i + 1]), c, debugDepthTest_);
  160. }
  161. void PhysicsWorld2D::DrawCircle(const b2Vec2& center, float radius, const b2Color& color)
  162. {
  163. if (!debugRenderer_)
  164. return;
  165. Vector3 p = ToVector3(center);
  166. Color c = ToColor(color);
  167. for (unsigned i = 0; i < 360; i += 30)
  168. {
  169. unsigned j = i + 30;
  170. float x1 = radius * Cos((float)i);
  171. float y1 = radius * Sin((float)i);
  172. float x2 = radius * Cos((float)j);
  173. float y2 = radius * Sin((float)j);
  174. debugRenderer_->AddLine(p + Vector3(x1, y1, 0.0f), p + Vector3(x2, y2, 0.0f), c, debugDepthTest_);
  175. }
  176. }
  177. void PhysicsWorld2D::DrawPoint(const b2Vec2& p, float size, const b2Color& color)
  178. {
  179. const float PIXEL_SIZE = 0.01f; // Urho2D can be disabled, so duplicate constant here
  180. DrawSolidCircle(p, size * 0.5f * PIXEL_SIZE, b2Vec2(), color);
  181. }
  182. void PhysicsWorld2D::DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color)
  183. {
  184. if (!debugRenderer_)
  185. return;
  186. Vector3 p = ToVector3(center);
  187. Color c(color.r, color.g, color.b, 0.5f);
  188. for (unsigned i = 0; i < 360; i += 30)
  189. {
  190. unsigned j = i + 30;
  191. float x1 = radius * Cos((float)i);
  192. float y1 = radius * Sin((float)i);
  193. float x2 = radius * Cos((float)j);
  194. float y2 = radius * Sin((float)j);
  195. debugRenderer_->AddTriangle(p, p + Vector3(x1, y1, 0.0f), p + Vector3(x2, y2, 0.0f), c, debugDepthTest_);
  196. }
  197. }
  198. void PhysicsWorld2D::DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color)
  199. {
  200. if (debugRenderer_)
  201. debugRenderer_->AddLine(ToVector3(p1), ToVector3(p2), ToColor(color), debugDepthTest_);
  202. }
  203. void PhysicsWorld2D::DrawTransform(const b2Transform& xf)
  204. {
  205. if (!debugRenderer_)
  206. return;
  207. const float axisScale = 0.4f;
  208. b2Vec2 p1 = xf.p, p2;
  209. p2 = p1 + axisScale * xf.q.GetXAxis();
  210. debugRenderer_->AddLine(Vector3(p1.x, p1.y, 0.0f), Vector3(p2.x, p2.y, 0.0f), Color::RED, debugDepthTest_);
  211. p2 = p1 + axisScale * xf.q.GetYAxis();
  212. debugRenderer_->AddLine(Vector3(p1.x, p1.y, 0.0f), Vector3(p2.x, p2.y, 0.0f), Color::GREEN, debugDepthTest_);
  213. }
  214. void PhysicsWorld2D::Update(float timeStep)
  215. {
  216. URHO3D_PROFILE(UpdatePhysics2D);
  217. using namespace PhysicsPreStep;
  218. VariantMap& eventData = GetEventDataMap();
  219. eventData[P_WORLD] = this;
  220. eventData[P_TIMESTEP] = timeStep;
  221. SendEvent(E_PHYSICSPRESTEP, eventData);
  222. physicsStepping_ = true;
  223. world_->Step(timeStep, velocityIterations_, positionIterations_);
  224. physicsStepping_ = false;
  225. // Apply world transforms. Unparented transforms first
  226. for (i32 i = 0; i < rigidBodies_.Size();)
  227. {
  228. if (rigidBodies_[i])
  229. {
  230. rigidBodies_[i]->ApplyWorldTransform();
  231. ++i;
  232. }
  233. else
  234. {
  235. // Erase possible stale weak pointer
  236. rigidBodies_.Erase(i);
  237. }
  238. }
  239. // Apply delayed (parented) world transforms now, if any
  240. while (!delayedWorldTransforms_.Empty())
  241. {
  242. for (HashMap<RigidBody2D*, DelayedWorldTransform2D>::Iterator i = delayedWorldTransforms_.Begin();
  243. i != delayedWorldTransforms_.End();)
  244. {
  245. const DelayedWorldTransform2D& transform = i->second_;
  246. // If parent's transform has already been assigned, can proceed
  247. if (!delayedWorldTransforms_.Contains(transform.parentRigidBody_))
  248. {
  249. transform.rigidBody_->ApplyWorldTransform(transform.worldPosition_, transform.worldRotation_);
  250. i = delayedWorldTransforms_.Erase(i);
  251. }
  252. else
  253. ++i;
  254. }
  255. }
  256. SendBeginContactEvents();
  257. SendEndContactEvents();
  258. using namespace PhysicsPostStep;
  259. SendEvent(E_PHYSICSPOSTSTEP, eventData);
  260. }
  261. void PhysicsWorld2D::DrawDebugGeometry()
  262. {
  263. auto* debug = GetComponent<DebugRenderer>();
  264. if (debug)
  265. DrawDebugGeometry(debug, false);
  266. }
  267. void PhysicsWorld2D::SetUpdateEnabled(bool enable)
  268. {
  269. updateEnabled_ = enable;
  270. }
  271. void PhysicsWorld2D::SetDrawShape(bool drawShape)
  272. {
  273. if (drawShape)
  274. m_drawFlags |= e_shapeBit;
  275. else
  276. m_drawFlags &= ~e_shapeBit;
  277. }
  278. void PhysicsWorld2D::SetDrawJoint(bool drawJoint)
  279. {
  280. if (drawJoint)
  281. m_drawFlags |= e_jointBit;
  282. else
  283. m_drawFlags &= ~e_jointBit;
  284. }
  285. void PhysicsWorld2D::SetDrawAabb(bool drawAabb)
  286. {
  287. if (drawAabb)
  288. m_drawFlags |= e_aabbBit;
  289. else
  290. m_drawFlags &= ~e_aabbBit;
  291. }
  292. void PhysicsWorld2D::SetDrawPair(bool drawPair)
  293. {
  294. if (drawPair)
  295. m_drawFlags |= e_pairBit;
  296. else
  297. m_drawFlags &= ~e_pairBit;
  298. }
  299. void PhysicsWorld2D::SetDrawCenterOfMass(bool drawCenterOfMass)
  300. {
  301. if (drawCenterOfMass)
  302. m_drawFlags |= e_centerOfMassBit;
  303. else
  304. m_drawFlags &= ~e_centerOfMassBit;
  305. }
  306. void PhysicsWorld2D::SetAllowSleeping(bool enable)
  307. {
  308. world_->SetAllowSleeping(enable);
  309. }
  310. void PhysicsWorld2D::SetWarmStarting(bool enable)
  311. {
  312. world_->SetWarmStarting(enable);
  313. }
  314. void PhysicsWorld2D::SetContinuousPhysics(bool enable)
  315. {
  316. world_->SetContinuousPhysics(enable);
  317. }
  318. void PhysicsWorld2D::SetSubStepping(bool enable)
  319. {
  320. world_->SetSubStepping(enable);
  321. }
  322. void PhysicsWorld2D::SetGravity(const Vector2& gravity)
  323. {
  324. gravity_ = gravity;
  325. world_->SetGravity(ToB2Vec2(gravity_));
  326. }
  327. void PhysicsWorld2D::SetAutoClearForces(bool enable)
  328. {
  329. world_->SetAutoClearForces(enable);
  330. }
  331. void PhysicsWorld2D::SetVelocityIterations(int velocityIterations)
  332. {
  333. velocityIterations_ = velocityIterations;
  334. }
  335. void PhysicsWorld2D::SetPositionIterations(int positionIterations)
  336. {
  337. positionIterations_ = positionIterations;
  338. }
  339. void PhysicsWorld2D::AddRigidBody(RigidBody2D* rigidBody)
  340. {
  341. if (!rigidBody)
  342. return;
  343. WeakPtr<RigidBody2D> rigidBodyPtr(rigidBody);
  344. if (rigidBodies_.Contains(rigidBodyPtr))
  345. return;
  346. rigidBodies_.Push(rigidBodyPtr);
  347. }
  348. void PhysicsWorld2D::RemoveRigidBody(RigidBody2D* rigidBody)
  349. {
  350. if (!rigidBody)
  351. return;
  352. WeakPtr<RigidBody2D> rigidBodyPtr(rigidBody);
  353. rigidBodies_.Remove(rigidBodyPtr);
  354. }
  355. void PhysicsWorld2D::AddDelayedWorldTransform(const DelayedWorldTransform2D& transform)
  356. {
  357. delayedWorldTransforms_[transform.rigidBody_] = transform;
  358. }
  359. // Ray cast call back class.
  360. class RayCastCallback : public b2RayCastCallback
  361. {
  362. public:
  363. // Construct.
  364. RayCastCallback(Vector<PhysicsRaycastResult2D>& results, const Vector2& startPoint, u16 collisionMask) :
  365. results_(results),
  366. startPoint_(startPoint),
  367. collisionMask_(collisionMask)
  368. {
  369. }
  370. // Called for each fixture found in the query.
  371. float ReportFixture(b2Fixture* fixture, const b2Vec2& point, const b2Vec2& normal, float fraction) override
  372. {
  373. // Ignore sensor
  374. if (fixture->IsSensor())
  375. return true;
  376. if ((fixture->GetFilterData().maskBits & collisionMask_) == 0)
  377. return true;
  378. PhysicsRaycastResult2D result;
  379. result.position_ = ToVector2(point);
  380. result.normal_ = ToVector2(normal);
  381. result.distance_ = (result.position_ - startPoint_).Length();
  382. result.body_ = (RigidBody2D*)(fixture->GetBody()->GetUserData().pointer);
  383. results_.Push(result);
  384. return true;
  385. }
  386. protected:
  387. // Physics raycast results.
  388. Vector<PhysicsRaycastResult2D>& results_;
  389. // Start point.
  390. Vector2 startPoint_;
  391. // Collision mask.
  392. u16 collisionMask_;
  393. };
  394. void PhysicsWorld2D::Raycast(Vector<PhysicsRaycastResult2D>& results, const Vector2& startPoint, const Vector2& endPoint,
  395. u16 collisionMask/* = M_U16_MASK_ALL_BITS*/)
  396. {
  397. results.Clear();
  398. RayCastCallback callback(results, startPoint, collisionMask);
  399. world_->RayCast(&callback, ToB2Vec2(startPoint), ToB2Vec2(endPoint));
  400. }
  401. // Single ray cast call back class.
  402. class SingleRayCastCallback : public b2RayCastCallback
  403. {
  404. public:
  405. // Construct.
  406. SingleRayCastCallback(PhysicsRaycastResult2D& result, const Vector2& startPoint, u16 collisionMask) :
  407. result_(result),
  408. startPoint_(startPoint),
  409. collisionMask_(collisionMask),
  410. minDistance_(M_INFINITY)
  411. {
  412. }
  413. // Called for each fixture found in the query.
  414. float ReportFixture(b2Fixture* fixture, const b2Vec2& point, const b2Vec2& normal, float fraction) override
  415. {
  416. // Ignore sensor
  417. if (fixture->IsSensor())
  418. return true;
  419. if ((fixture->GetFilterData().maskBits & collisionMask_) == 0)
  420. return true;
  421. float distance = (ToVector2(point) - startPoint_).Length();
  422. if (distance < minDistance_)
  423. {
  424. minDistance_ = distance;
  425. result_.position_ = ToVector2(point);
  426. result_.normal_ = ToVector2(normal);
  427. result_.distance_ = distance;
  428. result_.body_ = (RigidBody2D*)(fixture->GetBody()->GetUserData().pointer);
  429. }
  430. return true;
  431. }
  432. private:
  433. // Physics raycast result.
  434. PhysicsRaycastResult2D& result_;
  435. // Start point.
  436. Vector2 startPoint_;
  437. // Collision mask.
  438. u16 collisionMask_;
  439. // Minimum distance.
  440. float minDistance_;
  441. };
  442. void PhysicsWorld2D::RaycastSingle(PhysicsRaycastResult2D& result, const Vector2& startPoint, const Vector2& endPoint,
  443. u16 collisionMask/* = M_U16_MASK_ALL_BITS*/)
  444. {
  445. result.body_ = nullptr;
  446. SingleRayCastCallback callback(result, startPoint, collisionMask);
  447. world_->RayCast(&callback, ToB2Vec2(startPoint), ToB2Vec2(endPoint));
  448. }
  449. // Point query callback class.
  450. class PointQueryCallback : public b2QueryCallback
  451. {
  452. public:
  453. // Construct.
  454. PointQueryCallback(const b2Vec2& point, u16 collisionMask) : // NOLINT(modernize-pass-by-value)
  455. point_(point),
  456. collisionMask_(collisionMask),
  457. rigidBody_(nullptr)
  458. {
  459. }
  460. // Called for each fixture found in the query AABB.
  461. bool ReportFixture(b2Fixture* fixture) override
  462. {
  463. // Ignore sensor
  464. if (fixture->IsSensor())
  465. return true;
  466. if ((fixture->GetFilterData().maskBits & collisionMask_) == 0)
  467. return true;
  468. if (fixture->TestPoint(point_))
  469. {
  470. rigidBody_ = (RigidBody2D*)(fixture->GetBody()->GetUserData().pointer);
  471. return false;
  472. }
  473. return true;
  474. }
  475. // Return rigid body.
  476. RigidBody2D* GetRigidBody() const { return rigidBody_; }
  477. private:
  478. // Point.
  479. b2Vec2 point_;
  480. // Collision mask.
  481. u16 collisionMask_;
  482. // Rigid body.
  483. RigidBody2D* rigidBody_;
  484. };
  485. RigidBody2D* PhysicsWorld2D::GetRigidBody(const Vector2& point, u16 collisionMask/* = M_U16_MASK_ALL_BITS*/)
  486. {
  487. PointQueryCallback callback(ToB2Vec2(point), collisionMask);
  488. b2AABB b2Aabb;
  489. Vector2 delta(M_EPSILON, M_EPSILON);
  490. b2Aabb.lowerBound = ToB2Vec2(point - delta);
  491. b2Aabb.upperBound = ToB2Vec2(point + delta);
  492. world_->QueryAABB(&callback, b2Aabb);
  493. return callback.GetRigidBody();
  494. }
  495. RigidBody2D* PhysicsWorld2D::GetRigidBody(int screenX, int screenY, u16 collisionMask/* = M_U16_MASK_ALL_BITS*/)
  496. {
  497. auto* renderer = GetSubsystem<Renderer>();
  498. for (unsigned i = 0; i < renderer->GetNumViewports(); ++i)
  499. {
  500. Viewport* viewport = renderer->GetViewport(i);
  501. // Find a viewport with same scene
  502. if (viewport && viewport->GetScene() == GetScene())
  503. {
  504. Vector3 worldPoint = viewport->ScreenToWorldPoint(screenX, screenY, 0.0f);
  505. return GetRigidBody(Vector2(worldPoint.x_, worldPoint.y_), collisionMask);
  506. }
  507. }
  508. return nullptr;
  509. }
  510. // Aabb query callback class.
  511. class AabbQueryCallback : public b2QueryCallback
  512. {
  513. public:
  514. // Construct.
  515. AabbQueryCallback(Vector<RigidBody2D*>& results, u16 collisionMask) :
  516. results_(results),
  517. collisionMask_(collisionMask)
  518. {
  519. }
  520. // Called for each fixture found in the query AABB.
  521. bool ReportFixture(b2Fixture* fixture) override
  522. {
  523. // Ignore sensor
  524. if (fixture->IsSensor())
  525. return true;
  526. if ((fixture->GetFilterData().maskBits & collisionMask_) == 0)
  527. return true;
  528. results_.Push((RigidBody2D*)(fixture->GetBody()->GetUserData().pointer));
  529. return true;
  530. }
  531. private:
  532. // Results.
  533. Vector<RigidBody2D*>& results_;
  534. // Collision mask.
  535. u16 collisionMask_;
  536. };
  537. void PhysicsWorld2D::GetRigidBodies(Vector<RigidBody2D*>& results, const Rect& aabb, u16 collisionMask/* = M_U16_MASK_ALL_BITS*/)
  538. {
  539. AabbQueryCallback callback(results, collisionMask);
  540. b2AABB b2Aabb;
  541. Vector2 delta(M_EPSILON, M_EPSILON);
  542. b2Aabb.lowerBound = ToB2Vec2(aabb.min_ - delta);
  543. b2Aabb.upperBound = ToB2Vec2(aabb.max_ + delta);
  544. world_->QueryAABB(&callback, b2Aabb);
  545. }
  546. bool PhysicsWorld2D::GetAllowSleeping() const
  547. {
  548. return world_->GetAllowSleeping();
  549. }
  550. bool PhysicsWorld2D::GetWarmStarting() const
  551. {
  552. return world_->GetWarmStarting();
  553. }
  554. bool PhysicsWorld2D::GetContinuousPhysics() const
  555. {
  556. return world_->GetContinuousPhysics();
  557. }
  558. bool PhysicsWorld2D::GetSubStepping() const
  559. {
  560. return world_->GetSubStepping();
  561. }
  562. bool PhysicsWorld2D::GetAutoClearForces() const
  563. {
  564. return world_->GetAutoClearForces();
  565. }
  566. void PhysicsWorld2D::OnSceneSet(Scene* scene)
  567. {
  568. // Subscribe to the scene subsystem update, which will trigger the physics simulation step
  569. if (scene)
  570. SubscribeToEvent(scene, E_SCENESUBSYSTEMUPDATE, URHO3D_HANDLER(PhysicsWorld2D, HandleSceneSubsystemUpdate));
  571. else
  572. UnsubscribeFromEvent(E_SCENESUBSYSTEMUPDATE);
  573. }
  574. void PhysicsWorld2D::HandleSceneSubsystemUpdate(StringHash eventType, VariantMap& eventData)
  575. {
  576. if (!updateEnabled_)
  577. return;
  578. using namespace SceneSubsystemUpdate;
  579. Update(eventData[P_TIMESTEP].GetFloat());
  580. }
  581. void PhysicsWorld2D::SendBeginContactEvents()
  582. {
  583. if (beginContactInfos_.Empty())
  584. return;
  585. using namespace PhysicsBeginContact2D;
  586. VariantMap& eventData = GetEventDataMap();
  587. VariantMap nodeEventData;
  588. eventData[P_WORLD] = this;
  589. for (const ContactInfo& contactInfo : beginContactInfos_)
  590. {
  591. eventData[P_BODYA] = contactInfo.bodyA_.Get();
  592. eventData[P_BODYB] = contactInfo.bodyB_.Get();
  593. eventData[P_NODEA] = contactInfo.nodeA_.Get();
  594. eventData[P_NODEB] = contactInfo.nodeB_.Get();
  595. eventData[P_CONTACTS] = contactInfo.Serialize(contacts_);
  596. eventData[P_SHAPEA] = contactInfo.shapeA_.Get();
  597. eventData[P_SHAPEB] = contactInfo.shapeB_.Get();
  598. SendEvent(E_PHYSICSBEGINCONTACT2D, eventData);
  599. nodeEventData[NodeBeginContact2D::P_CONTACTS] = contactInfo.Serialize(contacts_);
  600. if (contactInfo.nodeA_)
  601. {
  602. nodeEventData[NodeBeginContact2D::P_BODY] = contactInfo.bodyA_.Get();
  603. nodeEventData[NodeBeginContact2D::P_OTHERNODE] = contactInfo.nodeB_.Get();
  604. nodeEventData[NodeBeginContact2D::P_OTHERBODY] = contactInfo.bodyB_.Get();
  605. nodeEventData[NodeBeginContact2D::P_SHAPE] = contactInfo.shapeA_.Get();
  606. nodeEventData[NodeBeginContact2D::P_OTHERSHAPE] = contactInfo.shapeB_.Get();
  607. contactInfo.nodeA_->SendEvent(E_NODEBEGINCONTACT2D, nodeEventData);
  608. }
  609. if (contactInfo.nodeB_)
  610. {
  611. nodeEventData[NodeBeginContact2D::P_BODY] = contactInfo.bodyB_.Get();
  612. nodeEventData[NodeBeginContact2D::P_OTHERNODE] = contactInfo.nodeA_.Get();
  613. nodeEventData[NodeBeginContact2D::P_OTHERBODY] = contactInfo.bodyA_.Get();
  614. nodeEventData[NodeBeginContact2D::P_SHAPE] = contactInfo.shapeB_.Get();
  615. nodeEventData[NodeBeginContact2D::P_OTHERSHAPE] = contactInfo.shapeA_.Get();
  616. contactInfo.nodeB_->SendEvent(E_NODEBEGINCONTACT2D, nodeEventData);
  617. }
  618. }
  619. beginContactInfos_.Clear();
  620. }
  621. void PhysicsWorld2D::SendEndContactEvents()
  622. {
  623. if (endContactInfos_.Empty())
  624. return;
  625. using namespace PhysicsEndContact2D;
  626. VariantMap& eventData = GetEventDataMap();
  627. VariantMap nodeEventData;
  628. eventData[P_WORLD] = this;
  629. for (const ContactInfo& contactInfo : endContactInfos_)
  630. {
  631. eventData[P_BODYA] = contactInfo.bodyA_.Get();
  632. eventData[P_BODYB] = contactInfo.bodyB_.Get();
  633. eventData[P_NODEA] = contactInfo.nodeA_.Get();
  634. eventData[P_NODEB] = contactInfo.nodeB_.Get();
  635. eventData[P_CONTACTS] = contactInfo.Serialize(contacts_);
  636. eventData[P_SHAPEA] = contactInfo.shapeA_.Get();
  637. eventData[P_SHAPEB] = contactInfo.shapeB_.Get();
  638. SendEvent(E_PHYSICSENDCONTACT2D, eventData);
  639. nodeEventData[NodeEndContact2D::P_CONTACTS] = contactInfo.Serialize(contacts_);
  640. if (contactInfo.nodeA_)
  641. {
  642. nodeEventData[NodeEndContact2D::P_BODY] = contactInfo.bodyA_.Get();
  643. nodeEventData[NodeEndContact2D::P_OTHERNODE] = contactInfo.nodeB_.Get();
  644. nodeEventData[NodeEndContact2D::P_OTHERBODY] = contactInfo.bodyB_.Get();
  645. nodeEventData[NodeEndContact2D::P_SHAPE] = contactInfo.shapeA_.Get();
  646. nodeEventData[NodeEndContact2D::P_OTHERSHAPE] = contactInfo.shapeB_.Get();
  647. contactInfo.nodeA_->SendEvent(E_NODEENDCONTACT2D, nodeEventData);
  648. }
  649. if (contactInfo.nodeB_)
  650. {
  651. nodeEventData[NodeEndContact2D::P_BODY] = contactInfo.bodyB_.Get();
  652. nodeEventData[NodeEndContact2D::P_OTHERNODE] = contactInfo.nodeA_.Get();
  653. nodeEventData[NodeEndContact2D::P_OTHERBODY] = contactInfo.bodyA_.Get();
  654. nodeEventData[NodeEndContact2D::P_SHAPE] = contactInfo.shapeB_.Get();
  655. nodeEventData[NodeEndContact2D::P_OTHERSHAPE] = contactInfo.shapeA_.Get();
  656. contactInfo.nodeB_->SendEvent(E_NODEENDCONTACT2D, nodeEventData);
  657. }
  658. }
  659. endContactInfos_.Clear();
  660. }
  661. PhysicsWorld2D::ContactInfo::ContactInfo() = default;
  662. PhysicsWorld2D::ContactInfo::ContactInfo(b2Contact* contact)
  663. {
  664. b2Fixture* fixtureA = contact->GetFixtureA();
  665. b2Fixture* fixtureB = contact->GetFixtureB();
  666. bodyA_ = (RigidBody2D*)(fixtureA->GetBody()->GetUserData().pointer);
  667. bodyB_ = (RigidBody2D*)(fixtureB->GetBody()->GetUserData().pointer);
  668. nodeA_ = bodyA_->GetNode();
  669. nodeB_ = bodyB_->GetNode();
  670. shapeA_ = (CollisionShape2D*)(fixtureA->GetUserData().pointer);
  671. shapeB_ = (CollisionShape2D*)(fixtureB->GetUserData().pointer);
  672. b2WorldManifold worldManifold;
  673. contact->GetWorldManifold(&worldManifold);
  674. numPoints_ = contact->GetManifold()->pointCount;
  675. worldNormal_ = Vector2(worldManifold.normal.x, worldManifold.normal.y);
  676. for (int i = 0; i < numPoints_; ++i)
  677. {
  678. worldPositions_[i] = Vector2(worldManifold.points[i].x, worldManifold.points[i].y);
  679. separations_[i] = worldManifold.separations[i];
  680. }
  681. }
  682. const Urho3D::Vector<byte>& PhysicsWorld2D::ContactInfo::Serialize(VectorBuffer& buffer) const
  683. {
  684. buffer.Clear();
  685. for (int i = 0; i < numPoints_; ++i)
  686. {
  687. buffer.WriteVector2(worldPositions_[i]);
  688. buffer.WriteVector2(worldNormal_);
  689. buffer.WriteFloat(separations_[i]);
  690. }
  691. return buffer.GetBuffer();
  692. }
  693. }