PhysicsWorld2D.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. //
  2. // Copyright (c) 2008-2014 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Context.h"
  24. #include "DebugRenderer.h"
  25. #include "PhysicsEvents2D.h"
  26. #include "PhysicsUtils2D.h"
  27. #include "PhysicsWorld2D.h"
  28. #include "Profiler.h"
  29. #include "RigidBody2D.h"
  30. #include "Scene.h"
  31. #include "SceneEvents.h"
  32. #include "DebugNew.h"
  33. namespace Urho3D
  34. {
  35. extern const char* SUBSYSTEM_CATEGORY;
  36. static const Vector2 DEFAULT_GRAVITY(0.0f, -9.81f);
  37. PhysicsWorld2D::PhysicsWorld2D(Context* context) : Component(context),
  38. world_(0),
  39. gravity_(DEFAULT_GRAVITY),
  40. velocityIterations_(8),
  41. positionIterations_(3),
  42. debugRenderer_(0),
  43. applyingTransforms_(false)
  44. {
  45. // Set default debug draw flags
  46. m_drawFlags = e_shapeBit;
  47. // Create Box2D world
  48. world_ = new b2World(ToB2Vec2(gravity_));
  49. // Set contact listener
  50. world_->SetContactListener(this);
  51. // Set debug draw
  52. world_->SetDebugDraw(this);
  53. world_->SetContinuousPhysics(true);
  54. world_->SetSubStepping(true);
  55. }
  56. PhysicsWorld2D::~PhysicsWorld2D()
  57. {
  58. for (unsigned i = 0; i < rigidBodies_.Size(); ++i)
  59. if (rigidBodies_[i])
  60. rigidBodies_[i]->ReleaseBody();
  61. delete world_;
  62. world_ = 0;
  63. }
  64. void PhysicsWorld2D::RegisterObject(Context* context)
  65. {
  66. context->RegisterFactory<PhysicsWorld2D>(SUBSYSTEM_CATEGORY);
  67. ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Draw Shape", GetDrawShape, SetDrawShape, bool, false, AM_DEFAULT);
  68. ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Draw Joint", GetDrawJoint, SetDrawJoint, bool, false, AM_DEFAULT);
  69. ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Draw Aabb", GetDrawAabb, SetDrawAabb, bool, false, AM_DEFAULT);
  70. ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Draw Pair", GetDrawPair, SetDrawPair, bool, false, AM_DEFAULT);
  71. ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Draw CenterOfMass", GetDrawCenterOfMass, SetDrawCenterOfMass, bool, false, AM_DEFAULT);
  72. ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Allow Sleeping", GetAllowSleeping, SetAllowSleeping, bool, false, AM_DEFAULT);
  73. ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Warm Starting", GetWarmStarting, SetWarmStarting, bool, false, AM_DEFAULT);
  74. ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Continuous Physics", GetContinuousPhysics, SetContinuousPhysics, bool, false, AM_DEFAULT);
  75. ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Sub Stepping", GetSubStepping, SetSubStepping, bool, false, AM_DEFAULT);
  76. REF_ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_VECTOR2, "Gravity", GetGravity, SetGravity, Vector2, DEFAULT_GRAVITY, AM_DEFAULT);
  77. ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_BOOL, "Auto Clear Forces", GetAutoClearForces, SetAutoClearForces, bool, false, AM_DEFAULT);
  78. ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_INT, "Velocity Iterations", GetVelocityIterations, SetVelocityIterations, int, false, AM_DEFAULT);
  79. ACCESSOR_ATTRIBUTE(PhysicsWorld2D, VAR_INT, "Position Iterations", GetPositionIterations, SetPositionIterations, int, false, AM_DEFAULT);
  80. COPY_BASE_ATTRIBUTES(PhysicsWorld2D, Component);
  81. }
  82. void PhysicsWorld2D::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
  83. {
  84. if (debug)
  85. {
  86. PROFILE(Physics2DDrawDebug);
  87. debugRenderer_ = debug;
  88. debugDepthTest_ = depthTest;
  89. world_->DrawDebugData();
  90. debugRenderer_ = 0;
  91. }
  92. }
  93. void PhysicsWorld2D::BeginContact(b2Contact* contact)
  94. {
  95. b2Fixture* fixtureA = contact->GetFixtureA();
  96. b2Fixture* fixtureB = contact->GetFixtureB();
  97. if (!fixtureA || !fixtureB)
  98. return;
  99. using namespace PhysicsBeginContact2D;
  100. VariantMap& eventData = GetEventDataMap();
  101. eventData[P_WORLD] = this;
  102. RigidBody2D* rigidBodyA = (RigidBody2D*)(fixtureA->GetBody()->GetUserData());
  103. RigidBody2D* rigidBodyB = (RigidBody2D*)(fixtureB->GetBody()->GetUserData());
  104. eventData[P_BODYA] = rigidBodyA;
  105. eventData[P_BODYB] = rigidBodyB;
  106. eventData[P_NODEA] = rigidBodyA->GetNode();
  107. eventData[P_NODEB] = rigidBodyB->GetNode();
  108. SendEvent(E_PHYSICSBEGINCONTACT2D, eventData);
  109. }
  110. void PhysicsWorld2D::EndContact(b2Contact* contact)
  111. {
  112. b2Fixture* fixtureA = contact->GetFixtureA();
  113. b2Fixture* fixtureB = contact->GetFixtureB();
  114. if (!fixtureA || !fixtureB)
  115. return;
  116. using namespace PhysicsEndContact2D;
  117. VariantMap& eventData = GetEventDataMap();
  118. eventData[P_WORLD] = this;
  119. RigidBody2D* rigidBodyA = (RigidBody2D*)(fixtureA->GetBody()->GetUserData());
  120. RigidBody2D* rigidBodyB = (RigidBody2D*)(fixtureB->GetBody()->GetUserData());
  121. eventData[P_BODYA] = rigidBodyA;
  122. eventData[P_BODYB] = rigidBodyB;
  123. eventData[P_NODEA] = rigidBodyA->GetNode();
  124. eventData[P_NODEB] = rigidBodyB->GetNode();
  125. SendEvent(E_PHYSICSENDCOLLISION2D, eventData);
  126. }
  127. void PhysicsWorld2D::DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color)
  128. {
  129. if (!debugRenderer_)
  130. return;
  131. Color c = ToColor(color);
  132. for (int i = 0; i < vertexCount - 1; ++i)
  133. debugRenderer_->AddLine(ToVector3(vertices[i]), ToVector3(vertices[i + 1]), c, debugDepthTest_);
  134. debugRenderer_->AddLine(ToVector3(vertices[vertexCount - 1]), ToVector3(vertices[0]), c, debugDepthTest_);
  135. }
  136. void PhysicsWorld2D::DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color)
  137. {
  138. if (!debugRenderer_)
  139. return;
  140. Vector3 v = ToVector3(vertices[0]);
  141. Color c(color.r, color.g, color.b, 0.5f);
  142. for (int i = 1; i < vertexCount - 1; ++i)
  143. debugRenderer_->AddTriangle(v, ToVector3(vertices[i]), ToVector3(vertices[i + 1]), c, debugDepthTest_);
  144. }
  145. void PhysicsWorld2D::DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color)
  146. {
  147. if (!debugRenderer_)
  148. return;
  149. Vector3 p = ToVector3(center);
  150. Color c = ToColor(color);
  151. for (unsigned i = 0; i < 360; i += 30)
  152. {
  153. unsigned j = i + 30;
  154. float x1 = radius * Cos((float)i);
  155. float y1 = radius * Sin((float)i);
  156. float x2 = radius * Cos((float)j);
  157. float y2 = radius * Sin((float)j);
  158. debugRenderer_->AddLine(p + Vector3(x1, y1, 0.0f), p + Vector3(x2, y2, 0.0f), c, debugDepthTest_);
  159. }
  160. }
  161. void PhysicsWorld2D::DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color)
  162. {
  163. if (!debugRenderer_)
  164. return;
  165. Vector3 p = ToVector3(center);
  166. Color c(color.r, color.g, color.b, 0.5f);
  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_->AddTriangle(p, p + Vector3(x1, y1, 0.0f), p + Vector3(x2, y2, 0.0f), c, debugDepthTest_);
  175. }
  176. }
  177. void PhysicsWorld2D::DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color)
  178. {
  179. if (debugRenderer_)
  180. debugRenderer_->AddLine(ToVector3(p1), ToVector3(p2), ToColor(color), debugDepthTest_);
  181. }
  182. void PhysicsWorld2D::DrawTransform(const b2Transform& xf)
  183. {
  184. if (!debugRenderer_)
  185. return;
  186. const float32 axisScale = 0.4f;
  187. b2Vec2 p1 = xf.p, p2;
  188. p2 = p1 + axisScale * xf.q.GetXAxis();
  189. debugRenderer_->AddLine(Vector3(p1.x, p1.y, 0.0f), Vector3(p2.x, p2.y, 0.0f), Color::RED, debugDepthTest_);
  190. p2 = p1 + axisScale * xf.q.GetYAxis();
  191. debugRenderer_->AddLine(Vector3(p1.x, p1.y, 0.0f), Vector3(p2.x, p2.y, 0.0f), Color::GREEN, debugDepthTest_);
  192. }
  193. void PhysicsWorld2D::SetDrawShape(bool drawShape)
  194. {
  195. if (drawShape)
  196. m_drawFlags |= e_shapeBit;
  197. else
  198. m_drawFlags &= ~e_shapeBit;
  199. }
  200. void PhysicsWorld2D::SetDrawJoint(bool drawJoint)
  201. {
  202. if (drawJoint)
  203. m_drawFlags |= e_jointBit;
  204. else
  205. m_drawFlags &= ~e_jointBit;
  206. }
  207. void PhysicsWorld2D::SetDrawAabb(bool drawAabb)
  208. {
  209. if (drawAabb)
  210. m_drawFlags |= e_aabbBit;
  211. else
  212. m_drawFlags &= ~e_aabbBit;
  213. }
  214. void PhysicsWorld2D::SetDrawPair(bool drawPair)
  215. {
  216. if (drawPair)
  217. m_drawFlags |= e_pairBit;
  218. else
  219. m_drawFlags &= ~e_pairBit;
  220. }
  221. void PhysicsWorld2D::SetDrawCenterOfMass(bool drawCenterOfMass)
  222. {
  223. if (drawCenterOfMass)
  224. m_drawFlags |= e_centerOfMassBit;
  225. else
  226. m_drawFlags &= ~e_centerOfMassBit;
  227. }
  228. void PhysicsWorld2D::SetAllowSleeping(bool enable)
  229. {
  230. world_->SetAllowSleeping(enable);
  231. }
  232. void PhysicsWorld2D::SetWarmStarting(bool enable)
  233. {
  234. world_->SetWarmStarting(enable);
  235. }
  236. void PhysicsWorld2D::SetContinuousPhysics(bool enable)
  237. {
  238. world_->SetContinuousPhysics(enable);
  239. }
  240. void PhysicsWorld2D::SetSubStepping(bool enable)
  241. {
  242. world_->SetSubStepping(enable);
  243. }
  244. void PhysicsWorld2D::SetGravity(const Vector2& gravity)
  245. {
  246. gravity_ = gravity;
  247. world_->SetGravity(ToB2Vec2(gravity_));
  248. }
  249. void PhysicsWorld2D::SetAutoClearForces(bool enable)
  250. {
  251. world_->SetAutoClearForces(enable);
  252. }
  253. void PhysicsWorld2D::SetVelocityIterations(int velocityIterations)
  254. {
  255. velocityIterations_ = velocityIterations;
  256. }
  257. void PhysicsWorld2D::SetPositionIterations(int positionIterations)
  258. {
  259. positionIterations_ = positionIterations;
  260. }
  261. void PhysicsWorld2D::AddRigidBody(RigidBody2D* rigidBody)
  262. {
  263. if (!rigidBody)
  264. return;
  265. WeakPtr<RigidBody2D> rigidBodyPtr(rigidBody);
  266. if (rigidBodies_.Contains(rigidBodyPtr))
  267. return;
  268. rigidBodies_.Push(rigidBodyPtr);
  269. }
  270. void PhysicsWorld2D::RemoveRigidBody(RigidBody2D* rigidBody)
  271. {
  272. if (!rigidBody)
  273. return;
  274. WeakPtr<RigidBody2D> rigidBodyPtr(rigidBody);
  275. rigidBodies_.Remove(rigidBodyPtr);
  276. }
  277. void PhysicsWorld2D::Update(float timeStep)
  278. {
  279. using namespace Physics2DPreStep2D;
  280. VariantMap& eventData = GetEventDataMap();
  281. eventData[P_WORLD] = this;
  282. eventData[P_TIMESTEP] = timeStep;
  283. SendEvent(E_PHYSICSPRESTEP2D, eventData);
  284. world_->Step(timeStep, velocityIterations_, positionIterations_);
  285. for (unsigned i = 0; i < rigidBodies_.Size(); ++i)
  286. rigidBodies_[i]->ApplyWorldTransform();
  287. using namespace PhysicsPostStep2D;
  288. SendEvent(E_PHYSICSPOSTSTEP2D, eventData);
  289. }
  290. void PhysicsWorld2D::DrawDebugGeometry()
  291. {
  292. DebugRenderer* debug = GetComponent<DebugRenderer>();
  293. if (debug)
  294. DrawDebugGeometry(debug, false);
  295. }
  296. void PhysicsWorld2D::SetDebugRenderer(DebugRenderer* debug)
  297. {
  298. debugRenderer_ = debug;
  299. }
  300. void PhysicsWorld2D::SetDebugDepthTest(bool enable)
  301. {
  302. debugDepthTest_ = enable;
  303. }
  304. bool PhysicsWorld2D::GetAllowSleeping() const
  305. {
  306. return world_->GetAllowSleeping();
  307. }
  308. bool PhysicsWorld2D::GetWarmStarting() const
  309. {
  310. return world_->GetWarmStarting();
  311. }
  312. bool PhysicsWorld2D::GetContinuousPhysics() const
  313. {
  314. return world_->GetContinuousPhysics();
  315. }
  316. bool PhysicsWorld2D::GetSubStepping() const
  317. {
  318. return world_->GetSubStepping();
  319. }
  320. bool PhysicsWorld2D::GetAutoClearForces() const
  321. {
  322. return world_->GetAutoClearForces();
  323. }
  324. void PhysicsWorld2D::OnNodeSet(Node* node)
  325. {
  326. // Subscribe to the scene subsystem update, which will trigger the physics simulation step
  327. if (node)
  328. {
  329. scene_ = GetScene();
  330. SubscribeToEvent(node, E_SCENESUBSYSTEMUPDATE, HANDLER(PhysicsWorld2D, HandleSceneSubsystemUpdate));
  331. }
  332. }
  333. void PhysicsWorld2D::HandleSceneSubsystemUpdate(StringHash eventType, VariantMap& eventData)
  334. {
  335. using namespace SceneSubsystemUpdate;
  336. Update(eventData[P_TIMESTEP].GetFloat());
  337. }
  338. }