RigidBody2D.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. //
  2. // Copyright (c) 2008-2015 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. // ATOMIC: Make sure these match box2d order
  37. static const char* bodyTypeNames[] =
  38. {
  39. "Static",
  40. "Kinematic",
  41. "Dynamic",
  42. 0
  43. };
  44. RigidBody2D::RigidBody2D(Context* context) :
  45. Component(context),
  46. massData_(), // b2MassData structure does not have a constructor so need to zero-initialize all its members
  47. useFixtureMass_(true),
  48. body_(0),
  49. castShadows_(true)
  50. {
  51. // Make sure the massData's center is zero-initialized as well
  52. massData_.center.SetZero();
  53. }
  54. RigidBody2D::~RigidBody2D()
  55. {
  56. if (physicsWorld_)
  57. {
  58. ReleaseBody();
  59. physicsWorld_->RemoveRigidBody(this);
  60. }
  61. }
  62. void RigidBody2D::RegisterObject(Context* context)
  63. {
  64. context->RegisterFactory<RigidBody2D>(ATOMIC2D_CATEGORY);
  65. ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
  66. ENUM_ACCESSOR_ATTRIBUTE("Body Type", GetBodyType, SetBodyType, BodyType2D, bodyTypeNames, DEFAULT_BODYTYPE, AM_DEFAULT);
  67. ACCESSOR_ATTRIBUTE("Mass", GetMass, SetMass, float, 0.0f, AM_DEFAULT);
  68. ACCESSOR_ATTRIBUTE("Inertia", GetInertia, SetInertia, float, 0.0f, AM_DEFAULT);
  69. MIXED_ACCESSOR_ATTRIBUTE("Mass Center", GetMassCenter, SetMassCenter, Vector2, Vector2::ZERO, AM_DEFAULT);
  70. ACCESSOR_ATTRIBUTE("Use Fixture Mass", GetUseFixtureMass, SetUseFixtureMass, bool, true, AM_DEFAULT);
  71. ACCESSOR_ATTRIBUTE("Linear Damping", GetLinearDamping, SetLinearDamping, float, 0.0f, AM_DEFAULT);
  72. ACCESSOR_ATTRIBUTE("Angular Damping", GetAngularDamping, SetAngularDamping, float, 0.0f, AM_DEFAULT);
  73. ACCESSOR_ATTRIBUTE("Allow Sleep", IsAllowSleep, SetAllowSleep, bool, true, AM_DEFAULT);
  74. ACCESSOR_ATTRIBUTE("Fixed Rotation", IsFixedRotation, SetFixedRotation, bool, false, AM_DEFAULT);
  75. ACCESSOR_ATTRIBUTE("Bullet", IsBullet, SetBullet, bool, false, AM_DEFAULT);
  76. ACCESSOR_ATTRIBUTE("Gravity Scale", GetGravityScale, SetGravityScale, float, 1.0f, AM_DEFAULT);
  77. ACCESSOR_ATTRIBUTE("Awake", IsAwake, SetAwake, bool, true, AM_DEFAULT);
  78. MIXED_ACCESSOR_ATTRIBUTE("Linear Velocity", GetLinearVelocity, SetLinearVelocity, Vector2, Vector2::ZERO, AM_DEFAULT);
  79. ACCESSOR_ATTRIBUTE("Angular Velocity", GetAngularVelocity, SetAngularVelocity, float, 0.0f, AM_DEFAULT);
  80. ACCESSOR_ATTRIBUTE("CastShadows", GetCastShadows, SetCastShadows, bool, true, AM_DEFAULT);
  81. }
  82. void RigidBody2D::OnSetEnabled()
  83. {
  84. bool enabled = IsEnabledEffective();
  85. bodyDef_.active = enabled;
  86. if (body_)
  87. body_->SetActive(enabled);
  88. MarkNetworkUpdate();
  89. }
  90. void RigidBody2D::SetBodyType(BodyType2D type)
  91. {
  92. b2BodyType bodyType = (b2BodyType)type;
  93. if (bodyDef_.type == bodyType)
  94. return;
  95. bodyDef_.type = bodyType;
  96. if (body_)
  97. body_->SetType(bodyType);
  98. MarkNetworkUpdate();
  99. }
  100. void RigidBody2D::SetMass(float mass)
  101. {
  102. mass = Max(mass, 0.0f);
  103. if (massData_.mass == mass)
  104. return;
  105. massData_.mass = mass;
  106. if (useFixtureMass_ && body_)
  107. body_->SetMassData(&massData_);
  108. MarkNetworkUpdate();
  109. }
  110. void RigidBody2D::SetInertia(float inertia)
  111. {
  112. inertia = Max(inertia, 0.0f);
  113. if (massData_.I == inertia)
  114. return;
  115. massData_.I = inertia;
  116. if (useFixtureMass_ && body_)
  117. body_->SetMassData(&massData_);
  118. MarkNetworkUpdate();
  119. }
  120. void RigidBody2D::SetMassCenter(const Vector2& center)
  121. {
  122. b2Vec2 b2Center = ToB2Vec2(center);
  123. if (massData_.center == b2Center)
  124. return;
  125. massData_.center = b2Center;
  126. if (useFixtureMass_ && body_)
  127. body_->SetMassData(&massData_);
  128. MarkNetworkUpdate();
  129. }
  130. void RigidBody2D::SetUseFixtureMass(bool useFixtureMass)
  131. {
  132. if (useFixtureMass_ == useFixtureMass)
  133. return;
  134. useFixtureMass_ = useFixtureMass;
  135. if (body_)
  136. {
  137. if (useFixtureMass_)
  138. body_->ResetMassData();
  139. else
  140. body_->SetMassData(&massData_);
  141. }
  142. MarkNetworkUpdate();
  143. }
  144. void RigidBody2D::SetLinearDamping(float linearDamping)
  145. {
  146. if (bodyDef_.linearDamping == linearDamping)
  147. return;
  148. bodyDef_.linearDamping = linearDamping;
  149. if (body_)
  150. body_->SetLinearDamping(linearDamping);
  151. MarkNetworkUpdate();
  152. }
  153. void RigidBody2D::SetAngularDamping(float angularDamping)
  154. {
  155. if (bodyDef_.angularDamping == angularDamping)
  156. return;
  157. bodyDef_.angularDamping = angularDamping;
  158. if (body_)
  159. body_->SetAngularDamping(angularDamping);
  160. MarkNetworkUpdate();
  161. }
  162. void RigidBody2D::SetAllowSleep(bool allowSleep)
  163. {
  164. if (bodyDef_.allowSleep == allowSleep)
  165. return;
  166. bodyDef_.allowSleep = allowSleep;
  167. if (body_)
  168. body_->SetSleepingAllowed(allowSleep);
  169. MarkNetworkUpdate();
  170. }
  171. void RigidBody2D::SetFixedRotation(bool fixedRotation)
  172. {
  173. if (bodyDef_.fixedRotation == fixedRotation)
  174. return;
  175. bodyDef_.fixedRotation = fixedRotation;
  176. if (body_)
  177. body_->SetFixedRotation(fixedRotation);
  178. MarkNetworkUpdate();
  179. }
  180. void RigidBody2D::SetBullet(bool bullet)
  181. {
  182. if (bodyDef_.bullet == bullet)
  183. return;
  184. bodyDef_.bullet = bullet;
  185. if (body_)
  186. body_->SetBullet(bullet);
  187. MarkNetworkUpdate();
  188. }
  189. void RigidBody2D::SetGravityScale(float gravityScale)
  190. {
  191. if (bodyDef_.gravityScale == gravityScale)
  192. return;
  193. bodyDef_.gravityScale = gravityScale;
  194. if (body_)
  195. body_->SetGravityScale(gravityScale);
  196. MarkNetworkUpdate();
  197. }
  198. void RigidBody2D::SetAwake(bool awake)
  199. {
  200. if (bodyDef_.awake == awake)
  201. return;
  202. bodyDef_.awake = awake;
  203. if (body_)
  204. body_->SetAwake(awake);
  205. MarkNetworkUpdate();
  206. }
  207. void RigidBody2D::SetLinearVelocity(const Vector2& linearVelocity)
  208. {
  209. b2Vec2 b2linearVelocity = ToB2Vec2(linearVelocity);
  210. if (bodyDef_.linearVelocity == b2linearVelocity)
  211. return;
  212. bodyDef_.linearVelocity = b2linearVelocity;
  213. if (body_)
  214. body_->SetLinearVelocity(b2linearVelocity);
  215. MarkNetworkUpdate();
  216. }
  217. void RigidBody2D::SetAngularVelocity(float angularVelocity)
  218. {
  219. if (bodyDef_.angularVelocity == angularVelocity)
  220. return;
  221. bodyDef_.angularVelocity = angularVelocity;
  222. if (body_)
  223. body_->SetAngularVelocity(angularVelocity);
  224. MarkNetworkUpdate();
  225. }
  226. void RigidBody2D::ApplyForce(const Vector2& force, const Vector2& point, bool wake)
  227. {
  228. if (body_ && force != Vector2::ZERO)
  229. body_->ApplyForce(ToB2Vec2(force), ToB2Vec2(point), wake);
  230. }
  231. void RigidBody2D::ApplyForceToCenter(const Vector2& force, bool wake)
  232. {
  233. if (body_ && force != Vector2::ZERO)
  234. body_->ApplyForceToCenter(ToB2Vec2(force), wake);
  235. }
  236. void RigidBody2D::ApplyTorque(float torque, bool wake)
  237. {
  238. if (body_ && torque != 0)
  239. body_->ApplyTorque(torque, wake);
  240. }
  241. void RigidBody2D::ApplyLinearImpulse(const Vector2& impulse, const Vector2& point, bool wake)
  242. {
  243. if (body_ && impulse != Vector2::ZERO)
  244. body_->ApplyLinearImpulse(ToB2Vec2(impulse), ToB2Vec2(point), wake);
  245. }
  246. void RigidBody2D::ApplyAngularImpulse(float impulse, bool wake)
  247. {
  248. if (body_)
  249. body_->ApplyAngularImpulse(impulse, wake);
  250. }
  251. void RigidBody2D::CreateBody()
  252. {
  253. if (body_)
  254. return;
  255. if (!physicsWorld_ || !physicsWorld_->GetWorld())
  256. return;
  257. bodyDef_.position = ToB2Vec2(node_->GetWorldPosition());;
  258. bodyDef_.angle = node_->GetWorldRotation().RollAngle() * M_DEGTORAD;
  259. body_ = physicsWorld_->GetWorld()->CreateBody(&bodyDef_);
  260. body_->SetUserData(this);
  261. for (unsigned i = 0; i < collisionShapes_.Size(); ++i)
  262. {
  263. if (collisionShapes_[i])
  264. collisionShapes_[i]->CreateFixture();
  265. }
  266. if (!useFixtureMass_)
  267. body_->SetMassData(&massData_);
  268. for (unsigned i = 0; i < constraints_.Size(); ++i)
  269. {
  270. if (constraints_[i])
  271. constraints_[i]->CreateJoint();
  272. }
  273. }
  274. void RigidBody2D::ReleaseBody()
  275. {
  276. if (!body_)
  277. return;
  278. if (!physicsWorld_ || !physicsWorld_->GetWorld())
  279. return;
  280. for (unsigned i = 0; i < constraints_.Size(); ++i)
  281. {
  282. if (constraints_[i])
  283. constraints_[i]->ReleaseJoint();
  284. }
  285. for (unsigned i = 0; i < collisionShapes_.Size(); ++i)
  286. {
  287. if (collisionShapes_[i])
  288. collisionShapes_[i]->ReleaseFixture();
  289. }
  290. physicsWorld_->GetWorld()->DestroyBody(body_);
  291. body_ = 0;
  292. }
  293. void RigidBody2D::ApplyWorldTransform()
  294. {
  295. if (!body_)
  296. return;
  297. physicsWorld_->SetApplyingTransforms(true);
  298. Node* node = GetNode();
  299. const b2Transform& transform = body_->GetTransform();
  300. node->SetWorldPosition(ToVector3(transform.p));
  301. node->SetWorldRotation(Quaternion(transform.q.GetAngle() * M_RADTODEG, Vector3::FORWARD));
  302. physicsWorld_->SetApplyingTransforms(false);
  303. }
  304. void RigidBody2D::AddCollisionShape2D(CollisionShape2D* collisionShape)
  305. {
  306. if (!collisionShape)
  307. return;
  308. WeakPtr<CollisionShape2D> collisionShapePtr(collisionShape);
  309. if (collisionShapes_.Contains(collisionShapePtr))
  310. return;
  311. collisionShapes_.Push(collisionShapePtr);
  312. }
  313. void RigidBody2D::RemoveCollisionShape2D(CollisionShape2D* collisionShape)
  314. {
  315. if (!collisionShape)
  316. return;
  317. WeakPtr<CollisionShape2D> collisionShapePtr(collisionShape);
  318. collisionShapes_.Remove(collisionShapePtr);
  319. }
  320. void RigidBody2D::AddConstraint2D(Constraint2D* constraint)
  321. {
  322. if (!constraint)
  323. return;
  324. WeakPtr<Constraint2D> constraintPtr(constraint);
  325. if (constraints_.Contains(constraintPtr))
  326. return;
  327. constraints_.Push(constraintPtr);
  328. }
  329. void RigidBody2D::RemoveConstraint2D(Constraint2D* constraint)
  330. {
  331. if (!constraint)
  332. return;
  333. WeakPtr<Constraint2D> constraintPtr(constraint);
  334. constraints_.Remove(constraintPtr);
  335. }
  336. float RigidBody2D::GetMass() const
  337. {
  338. if (!useFixtureMass_)
  339. return massData_.mass;
  340. return body_ ? body_->GetMass() : 0.0f;
  341. }
  342. float RigidBody2D::GetInertia() const
  343. {
  344. if (!useFixtureMass_)
  345. return massData_.I;
  346. return body_ ? body_->GetInertia() : 0.0f;
  347. }
  348. Vector2 RigidBody2D::GetMassCenter() const
  349. {
  350. if (!useFixtureMass_)
  351. return ToVector2(massData_.center);
  352. return body_ ? ToVector2(body_->GetLocalCenter()) : Vector2::ZERO;
  353. }
  354. bool RigidBody2D::IsAwake() const
  355. {
  356. return body_ ? body_->IsAwake() : bodyDef_.awake;
  357. }
  358. Vector2 RigidBody2D::GetLinearVelocity() const
  359. {
  360. return ToVector2(body_ ? body_->GetLinearVelocity() : bodyDef_.linearVelocity);
  361. }
  362. float RigidBody2D::GetAngularVelocity() const
  363. {
  364. return body_ ? body_->GetAngularVelocity() : bodyDef_.angularVelocity;
  365. }
  366. void RigidBody2D::OnNodeSet(Node* node)
  367. {
  368. if (node)
  369. node->AddListener(this);
  370. }
  371. void RigidBody2D::OnSceneSet(Scene* scene)
  372. {
  373. if (scene)
  374. {
  375. physicsWorld_ = scene->GetOrCreateComponent<PhysicsWorld2D>();
  376. CreateBody();
  377. physicsWorld_->AddRigidBody(this);
  378. }
  379. else
  380. {
  381. if (physicsWorld_)
  382. {
  383. ReleaseBody();
  384. physicsWorld_->RemoveRigidBody(this);
  385. physicsWorld_.Reset();
  386. }
  387. }
  388. }
  389. void RigidBody2D::OnMarkedDirty(Node* node)
  390. {
  391. if (physicsWorld_ && physicsWorld_->IsApplyingTransforms())
  392. return;
  393. // Physics operations are not safe from worker threads
  394. Scene* scene = GetScene();
  395. if (scene && scene->IsThreadedUpdate())
  396. {
  397. scene->DelayedMarkedDirty(this);
  398. return;
  399. }
  400. // Check if transform has changed from the last one set in ApplyWorldTransform()
  401. b2Vec2 newPosition = ToB2Vec2(node_->GetWorldPosition());
  402. float newAngle = node_->GetWorldRotation().RollAngle() * M_DEGTORAD;
  403. if (newPosition != bodyDef_.position || newAngle != bodyDef_.angle)
  404. {
  405. bodyDef_.position = newPosition;
  406. bodyDef_.angle = newAngle;
  407. if (body_)
  408. body_->SetTransform(newPosition, newAngle);
  409. }
  410. }
  411. }