File indexing completed on 2025-08-03 03:50:00
0001 /* 0002 * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 0003 * 0004 * This software is provided 'as-is', without any express or implied 0005 * warranty. In no event will the authors be held liable for any damages 0006 * arising from the use of this software. 0007 * Permission is granted to anyone to use this software for any purpose, 0008 * including commercial applications, and to alter it and redistribute it 0009 * freely, subject to the following restrictions: 0010 * 1. The origin of this software must not be misrepresented; you must not 0011 * claim that you wrote the original software. If you use this software 0012 * in a product, an acknowledgment in the product documentation would be 0013 * appreciated but is not required. 0014 * 2. Altered source versions must be plainly marked as such, and must not be 0015 * misrepresented as being the original software. 0016 * 3. This notice may not be removed or altered from any source distribution. 0017 */ 0018 0019 #include <Box2D/Dynamics/b2Body.h> 0020 #include <Box2D/Dynamics/b2Fixture.h> 0021 #include <Box2D/Dynamics/b2World.h> 0022 #include <Box2D/Dynamics/Contacts/b2Contact.h> 0023 #include <Box2D/Dynamics/Joints/b2Joint.h> 0024 0025 b2Body::b2Body(const b2BodyDef* bd, b2World* world) 0026 { 0027 b2Assert(bd->position.IsValid()); 0028 b2Assert(bd->linearVelocity.IsValid()); 0029 b2Assert(b2IsValid(bd->angle)); 0030 b2Assert(b2IsValid(bd->angularVelocity)); 0031 b2Assert(b2IsValid(bd->inertiaScale) && bd->inertiaScale >= 0.0f); 0032 b2Assert(b2IsValid(bd->angularDamping) && bd->angularDamping >= 0.0f); 0033 b2Assert(b2IsValid(bd->linearDamping) && bd->linearDamping >= 0.0f); 0034 0035 m_flags = 0; 0036 0037 if (bd->bullet) 0038 { 0039 m_flags |= e_bulletFlag; 0040 } 0041 if (bd->fixedRotation) 0042 { 0043 m_flags |= e_fixedRotationFlag; 0044 } 0045 if (bd->allowSleep) 0046 { 0047 m_flags |= e_autoSleepFlag; 0048 } 0049 if (bd->awake) 0050 { 0051 m_flags |= e_awakeFlag; 0052 } 0053 if (bd->active) 0054 { 0055 m_flags |= e_activeFlag; 0056 } 0057 0058 m_world = world; 0059 0060 m_xf.position = bd->position; 0061 m_xf.R.Set(bd->angle); 0062 0063 m_sweep.localCenter.SetZero(); 0064 m_sweep.a0 = m_sweep.a = bd->angle; 0065 m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); 0066 0067 m_jointList = NULL; 0068 m_contactList = NULL; 0069 m_prev = NULL; 0070 m_next = NULL; 0071 0072 m_linearVelocity = bd->linearVelocity; 0073 m_angularVelocity = bd->angularVelocity; 0074 0075 m_linearDamping = bd->linearDamping; 0076 m_angularDamping = bd->angularDamping; 0077 0078 m_force.SetZero(); 0079 m_torque = 0.0f; 0080 0081 m_sleepTime = 0.0f; 0082 0083 m_type = bd->type; 0084 0085 if (m_type == b2_dynamicBody) 0086 { 0087 m_mass = 1.0f; 0088 m_invMass = 1.0f; 0089 } 0090 else 0091 { 0092 m_mass = 0.0f; 0093 m_invMass = 0.0f; 0094 } 0095 0096 m_I = 0.0f; 0097 m_invI = 0.0f; 0098 0099 m_userData = bd->userData; 0100 0101 m_fixtureList = NULL; 0102 m_fixtureCount = 0; 0103 } 0104 0105 b2Body::~b2Body() 0106 { 0107 // shapes and joints are destroyed in b2World::Destroy 0108 } 0109 0110 void b2Body::SetType(b2BodyType type) 0111 { 0112 if (m_type == type) 0113 { 0114 return; 0115 } 0116 0117 m_type = type; 0118 0119 ResetMassData(); 0120 0121 if (m_type == b2_staticBody) 0122 { 0123 m_linearVelocity.SetZero(); 0124 m_angularVelocity = 0.0f; 0125 } 0126 0127 SetAwake(true); 0128 0129 m_force.SetZero(); 0130 m_torque = 0.0f; 0131 0132 // Since the body type changed, we need to flag contacts for filtering. 0133 for (b2ContactEdge* ce = m_contactList; ce; ce = ce->next) 0134 { 0135 ce->contact->FlagForFiltering(); 0136 } 0137 } 0138 0139 b2Fixture* b2Body::CreateFixture(const b2FixtureDef* def) 0140 { 0141 b2Assert(m_world->IsLocked() == false); 0142 if (m_world->IsLocked() == true) 0143 { 0144 return NULL; 0145 } 0146 0147 b2BlockAllocator* allocator = &m_world->m_blockAllocator; 0148 0149 void* memory = allocator->Allocate(sizeof(b2Fixture)); 0150 b2Fixture* fixture = new (memory) b2Fixture; 0151 fixture->Create(allocator, this, def); 0152 0153 if (m_flags & e_activeFlag) 0154 { 0155 b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; 0156 fixture->CreateProxies(broadPhase, m_xf); 0157 } 0158 0159 fixture->m_next = m_fixtureList; 0160 m_fixtureList = fixture; 0161 ++m_fixtureCount; 0162 0163 fixture->m_body = this; 0164 0165 // Adjust mass properties if needed. 0166 if (fixture->m_density > 0.0f) 0167 { 0168 ResetMassData(); 0169 } 0170 0171 // Let the world know we have a new fixture. This will cause new contacts 0172 // to be created at the beginning of the next time step. 0173 m_world->m_flags |= b2World::e_newFixture; 0174 0175 return fixture; 0176 } 0177 0178 b2Fixture* b2Body::CreateFixture(const b2Shape* shape, qreal density) 0179 { 0180 b2FixtureDef def; 0181 def.shape = shape; 0182 def.density = density; 0183 0184 return CreateFixture(&def); 0185 } 0186 0187 void b2Body::DestroyFixture(b2Fixture* fixture) 0188 { 0189 b2Assert(m_world->IsLocked() == false); 0190 if (m_world->IsLocked() == true) 0191 { 0192 return; 0193 } 0194 0195 b2Assert(fixture->m_body == this); 0196 0197 // Remove the fixture from this body's singly linked list. 0198 b2Assert(m_fixtureCount > 0); 0199 b2Fixture** node = &m_fixtureList; 0200 bool found = false; 0201 while (*node != NULL) 0202 { 0203 if (*node == fixture) 0204 { 0205 *node = fixture->m_next; 0206 found = true; 0207 break; 0208 } 0209 0210 node = &(*node)->m_next; 0211 } 0212 0213 // You tried to remove a shape that is not attached to this body. 0214 b2Assert(found); 0215 0216 // Destroy any contacts associated with the fixture. 0217 b2ContactEdge* edge = m_contactList; 0218 while (edge) 0219 { 0220 b2Contact* c = edge->contact; 0221 edge = edge->next; 0222 0223 b2Fixture* fixtureA = c->GetFixtureA(); 0224 b2Fixture* fixtureB = c->GetFixtureB(); 0225 0226 if (fixture == fixtureA || fixture == fixtureB) 0227 { 0228 // This destroys the contact and removes it from 0229 // this body's contact list. 0230 m_world->m_contactManager.Destroy(c); 0231 } 0232 } 0233 0234 b2BlockAllocator* allocator = &m_world->m_blockAllocator; 0235 0236 if (m_flags & e_activeFlag) 0237 { 0238 b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; 0239 fixture->DestroyProxies(broadPhase); 0240 } 0241 0242 fixture->Destroy(allocator); 0243 fixture->m_body = NULL; 0244 fixture->m_next = NULL; 0245 fixture->~b2Fixture(); 0246 allocator->Free(fixture, sizeof(b2Fixture)); 0247 0248 --m_fixtureCount; 0249 0250 // Reset the mass data. 0251 ResetMassData(); 0252 } 0253 0254 void b2Body::ResetMassData() 0255 { 0256 // Compute mass data from shapes. Each shape has its own density. 0257 m_mass = 0.0f; 0258 m_invMass = 0.0f; 0259 m_I = 0.0f; 0260 m_invI = 0.0f; 0261 m_sweep.localCenter.SetZero(); 0262 0263 // Static and kinematic bodies have zero mass. 0264 if (m_type == b2_staticBody || m_type == b2_kinematicBody) 0265 { 0266 m_sweep.c0 = m_sweep.c = m_xf.position; 0267 return; 0268 } 0269 0270 b2Assert(m_type == b2_dynamicBody); 0271 0272 // Accumulate mass over all fixtures. 0273 b2Vec2 center = b2Vec2_zero; 0274 for (b2Fixture* f = m_fixtureList; f; f = f->m_next) 0275 { 0276 if (f->m_density == 0.0f) 0277 { 0278 continue; 0279 } 0280 0281 b2MassData massData; 0282 f->GetMassData(&massData); 0283 m_mass += massData.mass; 0284 center += massData.mass * massData.center; 0285 m_I += massData.I; 0286 } 0287 0288 // Compute center of mass. 0289 if (m_mass > 0.0f) 0290 { 0291 m_invMass = 1.0f / m_mass; 0292 center *= m_invMass; 0293 } 0294 else 0295 { 0296 // Force all dynamic bodies to have a positive mass. 0297 m_mass = 1.0f; 0298 m_invMass = 1.0f; 0299 } 0300 0301 if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0) 0302 { 0303 // Center the inertia about the center of mass. 0304 m_I -= m_mass * b2Dot(center, center); 0305 b2Assert(m_I > 0.0f); 0306 m_invI = 1.0f / m_I; 0307 0308 } 0309 else 0310 { 0311 m_I = 0.0f; 0312 m_invI = 0.0f; 0313 } 0314 0315 // Move center of mass. 0316 b2Vec2 oldCenter = m_sweep.c; 0317 m_sweep.localCenter = center; 0318 m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); 0319 0320 // Update center of mass velocity. 0321 m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter); 0322 } 0323 0324 void b2Body::SetMassData(const b2MassData* massData) 0325 { 0326 b2Assert(m_world->IsLocked() == false); 0327 if (m_world->IsLocked() == true) 0328 { 0329 return; 0330 } 0331 0332 if (m_type != b2_dynamicBody) 0333 { 0334 return; 0335 } 0336 0337 m_invMass = 0.0f; 0338 m_I = 0.0f; 0339 m_invI = 0.0f; 0340 0341 m_mass = massData->mass; 0342 if (m_mass <= 0.0f) 0343 { 0344 m_mass = 1.0f; 0345 } 0346 0347 m_invMass = 1.0f / m_mass; 0348 0349 if (massData->I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0) 0350 { 0351 m_I = massData->I - m_mass * b2Dot(massData->center, massData->center); 0352 b2Assert(m_I > 0.0f); 0353 m_invI = 1.0f / m_I; 0354 } 0355 0356 // Move center of mass. 0357 b2Vec2 oldCenter = m_sweep.c; 0358 m_sweep.localCenter = massData->center; 0359 m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); 0360 0361 // Update center of mass velocity. 0362 m_linearVelocity += b2Cross(m_angularVelocity, m_sweep.c - oldCenter); 0363 } 0364 0365 bool b2Body::ShouldCollide(const b2Body* other) const 0366 { 0367 // At least one body should be dynamic. 0368 if (m_type != b2_dynamicBody && other->m_type != b2_dynamicBody) 0369 { 0370 return false; 0371 } 0372 0373 // Does a joint prevent collision? 0374 for (b2JointEdge* jn = m_jointList; jn; jn = jn->next) 0375 { 0376 if (jn->other == other) 0377 { 0378 if (jn->joint->m_collideConnected == false) 0379 { 0380 return false; 0381 } 0382 } 0383 } 0384 0385 return true; 0386 } 0387 0388 void b2Body::SetTransform(const b2Vec2& position, qreal angle) 0389 { 0390 b2Assert(m_world->IsLocked() == false); 0391 if (m_world->IsLocked() == true) 0392 { 0393 return; 0394 } 0395 0396 m_xf.R.Set(angle); 0397 m_xf.position = position; 0398 0399 m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); 0400 m_sweep.a0 = m_sweep.a = angle; 0401 0402 b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; 0403 for (b2Fixture* f = m_fixtureList; f; f = f->m_next) 0404 { 0405 f->Synchronize(broadPhase, m_xf, m_xf); 0406 } 0407 0408 m_world->m_contactManager.FindNewContacts(); 0409 } 0410 0411 void b2Body::SynchronizeFixtures() 0412 { 0413 b2Transform xf1; 0414 xf1.R.Set(m_sweep.a0); 0415 xf1.position = m_sweep.c0 - b2Mul(xf1.R, m_sweep.localCenter); 0416 0417 b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; 0418 for (b2Fixture* f = m_fixtureList; f; f = f->m_next) 0419 { 0420 f->Synchronize(broadPhase, xf1, m_xf); 0421 } 0422 } 0423 0424 void b2Body::SetActive(bool flag) 0425 { 0426 b2Assert(m_world->IsLocked() == false); 0427 0428 if (flag == IsActive()) 0429 { 0430 return; 0431 } 0432 0433 if (flag) 0434 { 0435 m_flags |= e_activeFlag; 0436 0437 // Create all proxies. 0438 b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; 0439 for (b2Fixture* f = m_fixtureList; f; f = f->m_next) 0440 { 0441 f->CreateProxies(broadPhase, m_xf); 0442 } 0443 0444 // Contacts are created the next time step. 0445 } 0446 else 0447 { 0448 m_flags &= ~e_activeFlag; 0449 0450 // Destroy all proxies. 0451 b2BroadPhase* broadPhase = &m_world->m_contactManager.m_broadPhase; 0452 for (b2Fixture* f = m_fixtureList; f; f = f->m_next) 0453 { 0454 f->DestroyProxies(broadPhase); 0455 } 0456 0457 // Destroy the attached contacts. 0458 b2ContactEdge* ce = m_contactList; 0459 while (ce) 0460 { 0461 b2ContactEdge* ce0 = ce; 0462 ce = ce->next; 0463 m_world->m_contactManager.Destroy(ce0->contact); 0464 } 0465 m_contactList = NULL; 0466 } 0467 } 0468