RigidBody2D.cpp 13 KB

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