b2Body.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. /*
  2. * Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. * Permission is granted to anyone to use this software for any purpose,
  8. * including commercial applications, and to alter it and redistribute it
  9. * freely, subject to the following restrictions:
  10. * 1. The origin of this software must not be misrepresented; you must not
  11. * claim that you wrote the original software. If you use this software
  12. * in a product, an acknowledgment in the product documentation would be
  13. * appreciated but is not required.
  14. * 2. Altered source versions must be plainly marked as such, and must not be
  15. * misrepresented as being the original software.
  16. * 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include <Box2D/Dynamics/b2Body.h>
  19. #include <Box2D/Dynamics/b2Fixture.h>
  20. #include <Box2D/Dynamics/b2World.h>
  21. #include <Box2D/Dynamics/Contacts/b2Contact.h>
  22. #include <Box2D/Dynamics/Joints/b2Joint.h>
  23. b2Body::b2Body(const b2BodyDef* bd, b2World* world)
  24. {
  25. b2Assert(bd->position.IsValid());
  26. b2Assert(bd->linearVelocity.IsValid());
  27. b2Assert(b2IsValid(bd->angle));
  28. b2Assert(b2IsValid(bd->angularVelocity));
  29. b2Assert(b2IsValid(bd->angularDamping) && bd->angularDamping >= 0.0f);
  30. b2Assert(b2IsValid(bd->linearDamping) && bd->linearDamping >= 0.0f);
  31. m_flags = 0;
  32. if (bd->bullet)
  33. {
  34. m_flags |= e_bulletFlag;
  35. }
  36. if (bd->fixedRotation)
  37. {
  38. m_flags |= e_fixedRotationFlag;
  39. }
  40. if (bd->allowSleep)
  41. {
  42. m_flags |= e_autoSleepFlag;
  43. }
  44. if (bd->awake)
  45. {
  46. m_flags |= e_awakeFlag;
  47. }
  48. if (bd->active)
  49. {
  50. m_flags |= e_activeFlag;
  51. }
  52. m_world = world;
  53. m_xf.p = bd->position;
  54. m_xf.q.Set(bd->angle);
  55. m_sweep.localCenter.SetZero();
  56. m_sweep.c0 = m_xf.p;
  57. m_sweep.c = m_xf.p;
  58. m_sweep.a0 = bd->angle;
  59. m_sweep.a = bd->angle;
  60. m_sweep.alpha0 = 0.0f;
  61. m_jointList = NULL;
  62. m_contactList = NULL;
  63. m_prev = NULL;
  64. m_next = NULL;
  65. m_linearVelocity = bd->linearVelocity;
  66. m_angularVelocity = bd->angularVelocity;
  67. m_linearDamping = bd->linearDamping;
  68. m_angularDamping = bd->angularDamping;
  69. m_gravityScale = bd->gravityScale;
  70. m_force.SetZero();
  71. m_torque = 0.0f;
  72. m_sleepTime = 0.0f;
  73. m_type = bd->type;
  74. if (m_type == b2_dynamicBody)
  75. {
  76. m_mass = 1.0f;
  77. m_invMass = 1.0f;
  78. }
  79. else
  80. {
  81. m_mass = 0.0f;
  82. m_invMass = 0.0f;
  83. }
  84. m_I = 0.0f;
  85. m_invI = 0.0f;
  86. m_userData = bd->userData;
  87. m_fixtureList = NULL;
  88. m_fixtureCount = 0;
  89. }
  90. b2Body::~b2Body()
  91. {
  92. // shapes and joints are destroyed in b2World::Destroy
  93. }
  94. void b2Body::SetType(b2BodyType type)
  95. {
  96. if (m_type == type)
  97. {
  98. return;
  99. }
  100. m_type = type;
  101. ResetMassData();
  102. if (m_type == b2_staticBody)
  103. {
  104. m_linearVelocity.SetZero();
  105. m_angularVelocity = 0.0f;
  106. m_sweep.a0 = m_sweep.a;
  107. m_sweep.c0 = m_sweep.c;
  108. SynchronizeFixtures();
  109. }
  110. SetAwake(true);
  111. m_force.SetZero();
  112. m_torque = 0.0f;
  113. // Since the body type changed, we need to flag contacts for filtering.
  114. for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
  115. {
  116. f->Refilter();
  117. }
  118. }
  119. b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def)
  120. {
  121. b2Assert(m_world->IsLocked() == false);
  122. if (m_world->IsLocked() == true)
  123. {
  124. return NULL;
  125. }
  126. b2BlockAllocator* allocator = &m_world->m_blockAllocator;
  127. void* memory = allocator->Allocate(sizeof(b2Fixture));
  128. b2Fixture* fixture = new (memory) b2Fixture;
  129. fixture->Create(allocator, this, def);
  130. if (m_flags & e_activeFlag)
  131. {
  132. b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
  133. fixture->CreateProxies(broadPhase, m_xf);
  134. }
  135. fixture->m_next = m_fixtureList;
  136. m_fixtureList = fixture;
  137. ++m_fixtureCount;
  138. fixture->m_body = this;
  139. // Adjust mass properties if needed.
  140. if (fixture->m_density > 0.0f)
  141. {
  142. ResetMassData();
  143. }
  144. // Let the world know we have a new fixture. This will cause new contacts
  145. // to be created at the beginning of the next time step.
  146. m_world->m_flags |= b2World::e_newFixture;
  147. return fixture;
  148. }
  149. b2Fixture* b2Body::CreateFixture(const b2Shape* shape, float32 density)
  150. {
  151. b2FixtureDef def;
  152. def.shape = shape;
  153. def.density = density;
  154. return CreateFixture(&def);
  155. }
  156. void b2Body::DestroyFixture(b2Fixture* fixture)
  157. {
  158. b2Assert(m_world->IsLocked() == false);
  159. if (m_world->IsLocked() == true)
  160. {
  161. return;
  162. }
  163. b2Assert(fixture->m_body == this);
  164. // Remove the fixture from this body's singly linked list.
  165. b2Assert(m_fixtureCount > 0);
  166. b2Fixture** node = &m_fixtureList;
  167. bool found = false;
  168. while (*node != NULL)
  169. {
  170. if (*node == fixture)
  171. {
  172. *node = fixture->m_next;
  173. found = true;
  174. break;
  175. }
  176. node = &(*node)->m_next;
  177. }
  178. // You tried to remove a shape that is not attached to this body.
  179. b2Assert(found);
  180. // Destroy any contacts associated with the fixture.
  181. b2ContactEdge* edge = m_contactList;
  182. while (edge)
  183. {
  184. b2Contact* c = edge->contact;
  185. edge = edge->next;
  186. b2Fixture* fixtureA = c->GetFixtureA();
  187. b2Fixture* fixtureB = c->GetFixtureB();
  188. if (fixture == fixtureA || fixture == fixtureB)
  189. {
  190. // This destroys the contact and removes it from
  191. // this body's contact list.
  192. m_world->m_contactManager.Destroy(c);
  193. }
  194. }
  195. b2BlockAllocator* allocator = &m_world->m_blockAllocator;
  196. if (m_flags & e_activeFlag)
  197. {
  198. b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
  199. fixture->DestroyProxies(broadPhase);
  200. }
  201. fixture->Destroy(allocator);
  202. fixture->m_body = NULL;
  203. fixture->m_next = NULL;
  204. fixture->~b2Fixture();
  205. allocator->Free(fixture, sizeof(b2Fixture));
  206. --m_fixtureCount;
  207. // Reset the mass data.
  208. ResetMassData();
  209. }
  210. void b2Body::ResetMassData()
  211. {
  212. // Compute mass data from shapes. Each shape has its own density.
  213. m_mass = 0.0f;
  214. m_invMass = 0.0f;
  215. m_I = 0.0f;
  216. m_invI = 0.0f;
  217. m_sweep.localCenter.SetZero();
  218. // Static and kinematic bodies have zero mass.
  219. if (m_type == b2_staticBody || m_type == b2_kinematicBody)
  220. {
  221. m_sweep.c0 = m_xf.p;
  222. m_sweep.c = m_xf.p;
  223. m_sweep.a0 = m_sweep.a;
  224. return;
  225. }
  226. b2Assert(m_type == b2_dynamicBody);
  227. // Accumulate mass over all fixtures.
  228. b2Vec2 localCenter = b2Vec2_zero;
  229. for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
  230. {
  231. if (f->m_density == 0.0f)
  232. {
  233. continue;
  234. }
  235. b2MassData massData;
  236. f->GetMassData(&massData);
  237. m_mass += massData.mass;
  238. localCenter += massData.mass * massData.center;
  239. m_I += massData.I;
  240. }
  241. // Compute center of mass.
  242. if (m_mass > 0.0f)
  243. {
  244. m_invMass = 1.0f / m_mass;
  245. localCenter *= m_invMass;
  246. }
  247. else
  248. {
  249. // Force all dynamic bodies to have a positive mass.
  250. m_mass = 1.0f;
  251. m_invMass = 1.0f;
  252. }
  253. if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0)
  254. {
  255. // Center the inertia about the center of mass.
  256. m_I -= m_mass * b2Dot(localCenter, localCenter);
  257. b2Assert(m_I > 0.0f);
  258. m_invI = 1.0f / m_I;
  259. }
  260. else
  261. {
  262. m_I = 0.0f;
  263. m_invI = 0.0f;
  264. }
  265. // Move center of mass.
  266. b2Vec2 oldCenter = m_sweep.c;
  267. m_sweep.localCenter = localCenter;
  268. m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
  269. // Update center of mass velocity.
  270. m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter);
  271. }
  272. void b2Body::SetMassData(const b2MassData* massData)
  273. {
  274. b2Assert(m_world->IsLocked() == false);
  275. if (m_world->IsLocked() == true)
  276. {
  277. return;
  278. }
  279. if (m_type != b2_dynamicBody)
  280. {
  281. return;
  282. }
  283. m_invMass = 0.0f;
  284. m_I = 0.0f;
  285. m_invI = 0.0f;
  286. m_mass = massData->mass;
  287. if (m_mass <= 0.0f)
  288. {
  289. m_mass = 1.0f;
  290. }
  291. m_invMass = 1.0f / m_mass;
  292. if (massData->I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0)
  293. {
  294. m_I = massData->I - m_mass * b2Dot(massData->center, massData->center);
  295. b2Assert(m_I > 0.0f);
  296. m_invI = 1.0f / m_I;
  297. }
  298. // Move center of mass.
  299. b2Vec2 oldCenter = m_sweep.c;
  300. m_sweep.localCenter = massData->center;
  301. m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
  302. // Update center of mass velocity.
  303. m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter);
  304. }
  305. bool b2Body::ShouldCollide(const b2Body* other) const
  306. {
  307. // At least one body should be dynamic.
  308. if (m_type != b2_dynamicBody && other->m_type != b2_dynamicBody)
  309. {
  310. return false;
  311. }
  312. // Does a joint prevent collision?
  313. for (b2JointEdge* jn = m_jointList; jn; jn = jn->next)
  314. {
  315. if (jn->other == other)
  316. {
  317. if (jn->joint->m_collideConnected == false)
  318. {
  319. return false;
  320. }
  321. }
  322. }
  323. return true;
  324. }
  325. void b2Body::SetTransform(const b2Vec2& position, float32 angle)
  326. {
  327. b2Assert(m_world->IsLocked() == false);
  328. if (m_world->IsLocked() == true)
  329. {
  330. return;
  331. }
  332. m_xf.q.Set(angle);
  333. m_xf.p = position;
  334. m_sweep.c = b2Mul(m_xf, m_sweep.localCenter);
  335. m_sweep.a = angle;
  336. m_sweep.c0 = m_sweep.c;
  337. m_sweep.a0 = angle;
  338. b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
  339. for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
  340. {
  341. f->Synchronize(broadPhase, m_xf, m_xf);
  342. }
  343. m_world->m_contactManager.FindNewContacts();
  344. }
  345. void b2Body::SynchronizeFixtures()
  346. {
  347. b2Transform xf1;
  348. xf1.q.Set(m_sweep.a0);
  349. xf1.p = m_sweep.c0 - b2Mul(xf1.q, m_sweep.localCenter);
  350. b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
  351. for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
  352. {
  353. f->Synchronize(broadPhase, xf1, m_xf);
  354. }
  355. }
  356. void b2Body::SetActive(bool flag)
  357. {
  358. b2Assert(m_world->IsLocked() == false);
  359. if (flag == IsActive())
  360. {
  361. return;
  362. }
  363. if (flag)
  364. {
  365. m_flags |= e_activeFlag;
  366. // Create all proxies.
  367. b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
  368. for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
  369. {
  370. f->CreateProxies(broadPhase, m_xf);
  371. }
  372. // Contacts are created the next time step.
  373. }
  374. else
  375. {
  376. m_flags &= ~e_activeFlag;
  377. // Destroy all proxies.
  378. b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase;
  379. for (b2Fixture* f = m_fixtureList; f; f = f->m_next)
  380. {
  381. f->DestroyProxies(broadPhase);
  382. }
  383. // Destroy the attached contacts.
  384. b2ContactEdge* ce = m_contactList;
  385. while (ce)
  386. {
  387. b2ContactEdge* ce0 = ce;
  388. ce = ce->next;
  389. m_world->m_contactManager.Destroy(ce0->contact);
  390. }
  391. m_contactList = NULL;
  392. }
  393. }