RigidBody2D.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. //
  2. // Copyright (c) 2008-2016 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 "../Core/Context.h"
  24. #include "../IO/Log.h"
  25. #include "../Scene/Scene.h"
  26. #include "../Atomic2D/CollisionShape2D.h"
  27. #include "../Atomic2D/Constraint2D.h"
  28. #include "../Atomic2D/PhysicsUtils2D.h"
  29. #include "../Atomic2D/PhysicsWorld2D.h"
  30. #include "../Atomic2D/RigidBody2D.h"
  31. #include "../DebugNew.h"
  32. namespace Atomic
  33. {
  34. extern const char* ATOMIC2D_CATEGORY;
  35. static const BodyType2D DEFAULT_BODYTYPE = BT_STATIC;
  36. static const char* bodyTypeNames[] =
  37. {
  38. "Static",
  39. "Kinematic",
  40. "Dynamic",
  41. 0
  42. };
  43. RigidBody2D::RigidBody2D(Context* context) :
  44. Component(context),
  45. useFixtureMass_(true),
  46. body_(0),
  47. // ATOMIC BEGIN
  48. castShadows_(true)
  49. // ATOMIC END
  50. {
  51. // Make sure the massData members are zero-initialized.
  52. massData_.mass = 0.0f;
  53. massData_.I = 0.0f;
  54. massData_.center.SetZero();
  55. }
  56. RigidBody2D::~RigidBody2D()
  57. {
  58. if (physicsWorld_)
  59. {
  60. ReleaseBody();
  61. physicsWorld_->RemoveRigidBody(this);
  62. }
  63. }
  64. void RigidBody2D::RegisterObject(Context* context)
  65. {
  66. context->RegisterFactory<RigidBody2D>(ATOMIC2D_CATEGORY);
  67. ATOMIC_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
  68. ATOMIC_ENUM_ACCESSOR_ATTRIBUTE("Body Type", GetBodyType, SetBodyType, BodyType2D, bodyTypeNames, DEFAULT_BODYTYPE, AM_DEFAULT);
  69. ATOMIC_ACCESSOR_ATTRIBUTE("Mass", GetMass, SetMass, float, 0.0f, AM_DEFAULT);
  70. ATOMIC_ACCESSOR_ATTRIBUTE("Inertia", GetInertia, SetInertia, float, 0.0f, AM_DEFAULT);
  71. ATOMIC_MIXED_ACCESSOR_ATTRIBUTE("Mass Center", GetMassCenter, SetMassCenter, Vector2, Vector2::ZERO, AM_DEFAULT);
  72. ATOMIC_ACCESSOR_ATTRIBUTE("Use Fixture Mass", GetUseFixtureMass, SetUseFixtureMass, bool, true, AM_DEFAULT);
  73. ATOMIC_ACCESSOR_ATTRIBUTE("Linear Damping", GetLinearDamping, SetLinearDamping, float, 0.0f, AM_DEFAULT);
  74. ATOMIC_ACCESSOR_ATTRIBUTE("Angular Damping", GetAngularDamping, SetAngularDamping, float, 0.0f, AM_DEFAULT);
  75. ATOMIC_ACCESSOR_ATTRIBUTE("Allow Sleep", IsAllowSleep, SetAllowSleep, bool, true, AM_DEFAULT);
  76. ATOMIC_ACCESSOR_ATTRIBUTE("Fixed Rotation", IsFixedRotation, SetFixedRotation, bool, false, AM_DEFAULT);
  77. ATOMIC_ACCESSOR_ATTRIBUTE("Bullet", IsBullet, SetBullet, bool, false, AM_DEFAULT);
  78. ATOMIC_ACCESSOR_ATTRIBUTE("Gravity Scale", GetGravityScale, SetGravityScale, float, 1.0f, AM_DEFAULT);
  79. ATOMIC_ACCESSOR_ATTRIBUTE("Awake", IsAwake, SetAwake, bool, true, AM_DEFAULT);
  80. ATOMIC_MIXED_ACCESSOR_ATTRIBUTE("Linear Velocity", GetLinearVelocity, SetLinearVelocity, Vector2, Vector2::ZERO, AM_DEFAULT);
  81. ATOMIC_ACCESSOR_ATTRIBUTE("Angular Velocity", GetAngularVelocity, SetAngularVelocity, float, 0.0f, AM_DEFAULT);
  82. // ATOMIC BEGIN
  83. ATOMIC_ACCESSOR_ATTRIBUTE("CastShadows", GetCastShadows, SetCastShadows, bool, true, AM_DEFAULT);
  84. // ATOMIC END
  85. }
  86. void RigidBody2D::OnSetEnabled()
  87. {
  88. bool enabled = IsEnabledEffective();
  89. bodyDef_.active = enabled;
  90. if (body_)
  91. body_->SetActive(enabled);
  92. MarkNetworkUpdate();
  93. }
  94. void RigidBody2D::SetBodyType(BodyType2D type)
  95. {
  96. b2BodyType bodyType = (b2BodyType)type;
  97. if (body_)
  98. {
  99. body_->SetType(bodyType);
  100. // Mass data was reset to keep it legal (e.g. static body should have mass 0.)
  101. // If not using fixture mass, reassign our mass data now
  102. if (!useFixtureMass_)
  103. body_->SetMassData(&massData_);
  104. }
  105. else
  106. {
  107. if (bodyDef_.type == bodyType)
  108. return;
  109. bodyDef_.type = bodyType;
  110. }
  111. MarkNetworkUpdate();
  112. }
  113. void RigidBody2D::SetMass(float mass)
  114. {
  115. mass = Max(mass, 0.0f);
  116. if (massData_.mass == mass)
  117. return;
  118. massData_.mass = mass;
  119. if (!useFixtureMass_ && body_)
  120. body_->SetMassData(&massData_);
  121. MarkNetworkUpdate();
  122. }
  123. void RigidBody2D::SetInertia(float inertia)
  124. {
  125. inertia = Max(inertia, 0.0f);
  126. if (massData_.I == inertia)
  127. return;
  128. massData_.I = inertia;
  129. if (!useFixtureMass_ && body_)
  130. body_->SetMassData(&massData_);
  131. MarkNetworkUpdate();
  132. }
  133. void RigidBody2D::SetMassCenter(const Vector2& center)
  134. {
  135. b2Vec2 b2Center = ToB2Vec2(center);
  136. if (massData_.center == b2Center)
  137. return;
  138. massData_.center = b2Center;
  139. if (!useFixtureMass_ && body_)
  140. body_->SetMassData(&massData_);
  141. MarkNetworkUpdate();
  142. }
  143. void RigidBody2D::SetUseFixtureMass(bool useFixtureMass)
  144. {
  145. if (useFixtureMass_ == useFixtureMass)
  146. return;
  147. useFixtureMass_ = useFixtureMass;
  148. if (body_)
  149. {
  150. body_->m_useFixtureMass = useFixtureMass;
  151. if (useFixtureMass_)
  152. body_->ResetMassData();
  153. else
  154. body_->SetMassData(&massData_);
  155. }
  156. MarkNetworkUpdate();
  157. }
  158. void RigidBody2D::SetLinearDamping(float linearDamping)
  159. {
  160. if (body_)
  161. body_->SetLinearDamping(linearDamping);
  162. else
  163. {
  164. if (bodyDef_.linearDamping == linearDamping)
  165. return;
  166. bodyDef_.linearDamping = linearDamping;
  167. }
  168. MarkNetworkUpdate();
  169. }
  170. void RigidBody2D::SetAngularDamping(float angularDamping)
  171. {
  172. if (body_)
  173. body_->SetAngularDamping(angularDamping);
  174. else
  175. {
  176. if (bodyDef_.angularDamping == angularDamping)
  177. return;
  178. bodyDef_.angularDamping = angularDamping;
  179. }
  180. MarkNetworkUpdate();
  181. }
  182. void RigidBody2D::SetAllowSleep(bool allowSleep)
  183. {
  184. if (body_)
  185. body_->SetSleepingAllowed(allowSleep);
  186. else
  187. {
  188. if (bodyDef_.allowSleep == allowSleep)
  189. return;
  190. bodyDef_.allowSleep = allowSleep;
  191. }
  192. MarkNetworkUpdate();
  193. }
  194. void RigidBody2D::SetFixedRotation(bool fixedRotation)
  195. {
  196. if (body_)
  197. {
  198. body_->SetFixedRotation(fixedRotation);
  199. // Mass data was reset to keep it legal (e.g. non-rotating body should have inertia 0.)
  200. // If not using fixture mass, reassign our mass data now
  201. if (!useFixtureMass_)
  202. body_->SetMassData(&massData_);
  203. }
  204. else
  205. {
  206. if (bodyDef_.fixedRotation == fixedRotation)
  207. return;
  208. bodyDef_.fixedRotation = fixedRotation;
  209. }
  210. MarkNetworkUpdate();
  211. }
  212. void RigidBody2D::SetBullet(bool bullet)
  213. {
  214. if (body_)
  215. body_->SetBullet(bullet);
  216. else
  217. {
  218. if (bodyDef_.bullet == bullet)
  219. return;
  220. bodyDef_.bullet = bullet;
  221. }
  222. MarkNetworkUpdate();
  223. }
  224. void RigidBody2D::SetGravityScale(float gravityScale)
  225. {
  226. if (body_)
  227. body_->SetGravityScale(gravityScale);
  228. else
  229. {
  230. if (bodyDef_.gravityScale == gravityScale)
  231. return;
  232. bodyDef_.gravityScale = gravityScale;
  233. }
  234. MarkNetworkUpdate();
  235. }
  236. void RigidBody2D::SetAwake(bool awake)
  237. {
  238. if (body_)
  239. body_->SetAwake(awake);
  240. else
  241. {
  242. if (bodyDef_.awake == awake)
  243. return;
  244. bodyDef_.awake = awake;
  245. }
  246. MarkNetworkUpdate();
  247. }
  248. void RigidBody2D::SetLinearVelocity(const Vector2& linearVelocity)
  249. {
  250. b2Vec2 b2linearVelocity = ToB2Vec2(linearVelocity);
  251. if (body_)
  252. body_->SetLinearVelocity(b2linearVelocity);
  253. else
  254. {
  255. if (bodyDef_.linearVelocity == b2linearVelocity)
  256. return;
  257. bodyDef_.linearVelocity = b2linearVelocity;
  258. }
  259. MarkNetworkUpdate();
  260. }
  261. void RigidBody2D::SetAngularVelocity(float angularVelocity)
  262. {
  263. if (body_)
  264. body_->SetAngularVelocity(angularVelocity);
  265. else
  266. {
  267. if (bodyDef_.angularVelocity == angularVelocity)
  268. return;
  269. bodyDef_.angularVelocity = angularVelocity;
  270. }
  271. MarkNetworkUpdate();
  272. }
  273. void RigidBody2D::ApplyForce(const Vector2& force, const Vector2& point, bool wake)
  274. {
  275. if (body_ && force != Vector2::ZERO)
  276. body_->ApplyForce(ToB2Vec2(force), ToB2Vec2(point), wake);
  277. }
  278. void RigidBody2D::ApplyForceToCenter(const Vector2& force, bool wake)
  279. {
  280. if (body_ && force != Vector2::ZERO)
  281. body_->ApplyForceToCenter(ToB2Vec2(force), wake);
  282. }
  283. void RigidBody2D::ApplyTorque(float torque, bool wake)
  284. {
  285. if (body_ && torque != 0)
  286. body_->ApplyTorque(torque, wake);
  287. }
  288. void RigidBody2D::ApplyLinearImpulse(const Vector2& impulse, const Vector2& point, bool wake)
  289. {
  290. if (body_ && impulse != Vector2::ZERO)
  291. body_->ApplyLinearImpulse(ToB2Vec2(impulse), ToB2Vec2(point), wake);
  292. }
  293. void RigidBody2D::ApplyAngularImpulse(float impulse, bool wake)
  294. {
  295. if (body_)
  296. body_->ApplyAngularImpulse(impulse, wake);
  297. }
  298. void RigidBody2D::CreateBody()
  299. {
  300. if (body_)
  301. return;
  302. if (!physicsWorld_ || !physicsWorld_->GetWorld())
  303. return;
  304. bodyDef_.position = ToB2Vec2(node_->GetWorldPosition());;
  305. bodyDef_.angle = node_->GetWorldRotation().RollAngle() * M_DEGTORAD;
  306. body_ = physicsWorld_->GetWorld()->CreateBody(&bodyDef_);
  307. body_->SetUserData(this);
  308. for (unsigned i = 0; i < collisionShapes_.Size(); ++i)
  309. {
  310. if (collisionShapes_[i])
  311. collisionShapes_[i]->CreateFixture();
  312. }
  313. if (!useFixtureMass_)
  314. body_->SetMassData(&massData_);
  315. for (unsigned i = 0; i < constraints_.Size(); ++i)
  316. {
  317. if (constraints_[i])
  318. constraints_[i]->CreateJoint();
  319. }
  320. }
  321. void RigidBody2D::ReleaseBody()
  322. {
  323. if (!body_)
  324. return;
  325. if (!physicsWorld_ || !physicsWorld_->GetWorld())
  326. return;
  327. // Make a copy for iteration
  328. Vector<WeakPtr<Constraint2D> > constraints = constraints_;
  329. for (unsigned i = 0; i < constraints.Size(); ++i)
  330. {
  331. if (constraints[i])
  332. constraints[i]->ReleaseJoint();
  333. }
  334. for (unsigned i = 0; i < collisionShapes_.Size(); ++i)
  335. {
  336. if (collisionShapes_[i])
  337. collisionShapes_[i]->ReleaseFixture();
  338. }
  339. physicsWorld_->GetWorld()->DestroyBody(body_);
  340. body_ = 0;
  341. }
  342. void RigidBody2D::ApplyWorldTransform()
  343. {
  344. if (!body_ || !node_)
  345. return;
  346. // If the rigid body is parented to another rigid body, can not set the transform immediately.
  347. // In that case store it to PhysicsWorld2D for delayed assignment
  348. RigidBody2D* parentRigidBody = 0;
  349. Node* parent = node_->GetParent();
  350. if (parent != GetScene() && parent)
  351. parentRigidBody = parent->GetComponent<RigidBody2D>();
  352. // If body is not parented and is static or sleeping, no need to update
  353. if (!parentRigidBody && (!body_->IsActive() || body_->GetType() == b2_staticBody || !body_->IsAwake()))
  354. return;
  355. const b2Transform& transform = body_->GetTransform();
  356. Vector3 newWorldPosition = node_->GetWorldPosition();
  357. newWorldPosition.x_ = transform.p.x;
  358. newWorldPosition.y_ = transform.p.y;
  359. Quaternion newWorldRotation(transform.q.GetAngle() * M_RADTODEG, Vector3::FORWARD);
  360. if (parentRigidBody)
  361. {
  362. DelayedWorldTransform2D delayed;
  363. delayed.rigidBody_ = this;
  364. delayed.parentRigidBody_ = parentRigidBody;
  365. delayed.worldPosition_ = newWorldPosition;
  366. delayed.worldRotation_ = newWorldRotation;
  367. physicsWorld_->AddDelayedWorldTransform(delayed);
  368. }
  369. else
  370. ApplyWorldTransform(newWorldPosition, newWorldRotation);
  371. }
  372. void RigidBody2D::ApplyWorldTransform(const Vector3& newWorldPosition, const Quaternion& newWorldRotation)
  373. {
  374. if (newWorldPosition != node_->GetWorldPosition() || newWorldRotation != node_->GetWorldRotation())
  375. {
  376. // Do not feed changed position back to simulation now
  377. physicsWorld_->SetApplyingTransforms(true);
  378. node_->SetWorldPosition(newWorldPosition);
  379. node_->SetWorldRotation(newWorldRotation);
  380. physicsWorld_->SetApplyingTransforms(false);
  381. }
  382. }
  383. void RigidBody2D::AddCollisionShape2D(CollisionShape2D* collisionShape)
  384. {
  385. if (!collisionShape)
  386. return;
  387. WeakPtr<CollisionShape2D> collisionShapePtr(collisionShape);
  388. if (collisionShapes_.Contains(collisionShapePtr))
  389. return;
  390. collisionShapes_.Push(collisionShapePtr);
  391. }
  392. void RigidBody2D::RemoveCollisionShape2D(CollisionShape2D* collisionShape)
  393. {
  394. if (!collisionShape)
  395. return;
  396. WeakPtr<CollisionShape2D> collisionShapePtr(collisionShape);
  397. collisionShapes_.Remove(collisionShapePtr);
  398. }
  399. void RigidBody2D::AddConstraint2D(Constraint2D* constraint)
  400. {
  401. if (!constraint)
  402. return;
  403. WeakPtr<Constraint2D> constraintPtr(constraint);
  404. if (constraints_.Contains(constraintPtr))
  405. return;
  406. constraints_.Push(constraintPtr);
  407. }
  408. void RigidBody2D::RemoveConstraint2D(Constraint2D* constraint)
  409. {
  410. if (!constraint)
  411. return;
  412. WeakPtr<Constraint2D> constraintPtr(constraint);
  413. constraints_.Remove(constraintPtr);
  414. }
  415. float RigidBody2D::GetMass() const
  416. {
  417. if (!useFixtureMass_)
  418. return massData_.mass;
  419. else
  420. return body_ ? body_->GetMass() : 0.0f;
  421. }
  422. float RigidBody2D::GetInertia() const
  423. {
  424. if (!useFixtureMass_)
  425. return massData_.I;
  426. else
  427. return body_ ? body_->GetInertia() : 0.0f;
  428. }
  429. Vector2 RigidBody2D::GetMassCenter() const
  430. {
  431. if (!useFixtureMass_)
  432. return ToVector2(massData_.center);
  433. else
  434. return body_ ? ToVector2(body_->GetLocalCenter()) : Vector2::ZERO;
  435. }
  436. bool RigidBody2D::IsAwake() const
  437. {
  438. return body_ ? body_->IsAwake() : bodyDef_.awake;
  439. }
  440. Vector2 RigidBody2D::GetLinearVelocity() const
  441. {
  442. return ToVector2(body_ ? body_->GetLinearVelocity() : bodyDef_.linearVelocity);
  443. }
  444. float RigidBody2D::GetAngularVelocity() const
  445. {
  446. return body_ ? body_->GetAngularVelocity() : bodyDef_.angularVelocity;
  447. }
  448. void RigidBody2D::OnNodeSet(Node* node)
  449. {
  450. if (node)
  451. {
  452. node->AddListener(this);
  453. PODVector<CollisionShape2D*> shapes;
  454. node_->GetDerivedComponents<CollisionShape2D>(shapes);
  455. for (PODVector<CollisionShape2D*>::Iterator i = shapes.Begin(); i != shapes.End(); ++i)
  456. {
  457. (*i)->CreateFixture();
  458. AddCollisionShape2D(*i);
  459. }
  460. }
  461. }
  462. void RigidBody2D::OnSceneSet(Scene* scene)
  463. {
  464. if (scene)
  465. {
  466. physicsWorld_ = scene->GetOrCreateComponent<PhysicsWorld2D>();
  467. CreateBody();
  468. physicsWorld_->AddRigidBody(this);
  469. }
  470. else
  471. {
  472. if (physicsWorld_)
  473. {
  474. ReleaseBody();
  475. physicsWorld_->RemoveRigidBody(this);
  476. physicsWorld_.Reset();
  477. }
  478. }
  479. }
  480. void RigidBody2D::OnMarkedDirty(Node* node)
  481. {
  482. if (physicsWorld_ && physicsWorld_->IsApplyingTransforms())
  483. return;
  484. // Physics operations are not safe from worker threads
  485. Scene* scene = GetScene();
  486. if (scene && scene->IsThreadedUpdate())
  487. {
  488. scene->DelayedMarkedDirty(this);
  489. return;
  490. }
  491. // Check if transform has changed from the last one set in ApplyWorldTransform()
  492. b2Vec2 newPosition = ToB2Vec2(node_->GetWorldPosition());
  493. float newAngle = node_->GetWorldRotation().RollAngle() * M_DEGTORAD;
  494. if (newPosition != bodyDef_.position || newAngle != bodyDef_.angle)
  495. {
  496. if (body_)
  497. body_->SetTransform(newPosition, newAngle);
  498. else
  499. {
  500. bodyDef_.position = newPosition;
  501. bodyDef_.angle = newAngle;
  502. }
  503. }
  504. }
  505. }