Browse Source

Physics entities should now be able to have mulitple fixtures

This fixes bug #79. Physics entities should now be able to have multiple
fixtues each with it's own polygon shape. Each polygon is still limited
to 8 verticies as Box2D suggests. The commenting is so you can see
what's going, obviously it needs editing.
Paul Smith 13 years ago
parent
commit
2b0c8d237b

+ 10 - 7
Modules/Contents/2DPhysics/Include/PolyPhysicsScreenEntity.h

@@ -58,10 +58,14 @@ namespace Polycode {
 			
 			
 			void setVelocity(Number fx, Number fy);	
 			void setVelocity(Number fx, Number fy);	
 			void setVelocityX( Number fx);	
 			void setVelocityX( Number fx);	
-			void setVelocityY(Number fy);				
+			void setVelocityY(Number fy);
 			
 			
 			void applyImpulse(Number fx, Number fy);
 			void applyImpulse(Number fx, Number fy);
-				
+
+
+			b2Fixture* getFixture();						// Gets the last fixture selected (automatically set on creation)			
+			b2Fixture* getFixture(unsigned short index);	// Gets a specific fixture if there is more than one
+			
 			/**
 			/**
 			* Rectangular physics entity
 			* Rectangular physics entity
 			*/ 
 			*/ 
@@ -75,10 +79,9 @@ namespace Polycode {
 			*/ 						
 			*/ 						
 			static const int ENTITY_MESH = 3;
 			static const int ENTITY_MESH = 3;
 		
 		
-			b2Fixture *fixture;		
-			b2Body* body;
-			b2Shape *shape;
-			
+			b2Body *body;
+			b2Fixture *fixture;								// You do not need a shape pointer
+
 			bool collisionOnly;
 			bool collisionOnly;
 		
 		
 		protected:
 		protected:
@@ -87,4 +90,4 @@ namespace Polycode {
 		ScreenEntity *screenEntity;
 		ScreenEntity *screenEntity;
 	};
 	};
 
 
-}
+}

+ 23 - 15
Modules/Contents/2DPhysics/Source/PolyPhysicsScreen.cpp

@@ -384,9 +384,11 @@ ScreenEntity *PhysicsScreen::getEntityAtPosition(Number x, Number y) {
 	
 	
 	for(int i=0;i<physicsChildren.size();i++) {
 	for(int i=0;i<physicsChildren.size();i++) {
 		PhysicsScreenEntity *ent = physicsChildren[i];
 		PhysicsScreenEntity *ent = physicsChildren[i];
-		if(ent->shape) {
-			if(ent->shape->TestPoint(ent->body->GetTransform(), mousePosition)) {
-				return ent->getScreenEntity();
+		if(ent->fixture) {
+			for (b2Fixture* f = ent->body->GetFixtureList(); f; f = f->GetNext()) {		// This has been changed to accept multiple fixtures
+				if(f->TestPoint(mousePosition)) {										// Fixtures have a Testpoint function that requires just a b2Vec
+					return ent->getScreenEntity();
+				}
 			}
 			}
 		}
 		}
 	}	
 	}	
@@ -403,11 +405,13 @@ bool PhysicsScreen::testEntityAtPosition(ScreenEntity *ent, Number x, Number y)
 	mousePosition.x = x/worldScale;
 	mousePosition.x = x/worldScale;
 	mousePosition.y = y/worldScale;
 	mousePosition.y = y/worldScale;
 	
 	
-	if(pEnt->shape) {
-		if(pEnt->shape->TestPoint(pEnt->body->GetTransform(), mousePosition))
-			return true;
-		else
-			return false;
+	if(pEnt->fixture) {
+		for (b2Fixture* f = pEnt->body->GetFixtureList(); f; f = f->GetNext()) {	// This has been changed to accept multiple fixtures
+			if(f->TestPoint(mousePosition))											// Fixtures have a Testpoint function that requires just a b2Vec
+				return true;
+			else
+				return false;
+		}
 	}
 	}
 	return false;
 	return false;
 }
 }
@@ -465,18 +469,22 @@ PhysicsScreen::~PhysicsScreen() {
 	delete world;	
 	delete world;	
 }
 }
 
 
-PhysicsScreenEntity *PhysicsScreen::getPhysicsEntityByFixture(b2Fixture *fixture) {
-	for(int i=0; i < physicsChildren.size(); i++) {
-		if(physicsChildren[i]->fixture == fixture)
-			return physicsChildren[i];
+PhysicsScreenEntity *PhysicsScreen::getPhysicsEntityByFixture(b2Fixture *fixture) {			// I have made changes so it will search through body fixturelists
+	for(int i=0; i < physicsChildren.size(); i++) {											
+		for (b2Fixture* f = physicsChildren[i]->body->GetFixtureList(); f; f = f->GetNext()) {
+			if(f == fixture)
+				return physicsChildren[i];
+		}
 	}
 	}
 	return NULL;	
 	return NULL;	
 }
 }
 
 
-PhysicsScreenEntity *PhysicsScreen::getPhysicsEntityByShape(b2Shape *shape) {
+PhysicsScreenEntity *PhysicsScreen::getPhysicsEntityByShape(b2Shape *shape) {				// I have made changes so it will search through body fixturelists
 	for(int i=0; i < physicsChildren.size(); i++) {
 	for(int i=0; i < physicsChildren.size(); i++) {
-		if(physicsChildren[i]->shape == shape)
-			return physicsChildren[i];
+		for (b2Fixture *f = physicsChildren[i]->body->GetFixtureList(); f; f = f->GetNext()) {
+			if(f->GetShape() == shape)
+				return physicsChildren[i];
+		}
 	}
 	}
 	return NULL;
 	return NULL;
 }
 }

+ 122 - 81
Modules/Contents/2DPhysics/Source/PolyPhysicsScreenEntity.cpp

@@ -33,88 +33,92 @@ using namespace Polycode;
 
 
 PhysicsScreenEntity::PhysicsScreenEntity(ScreenEntity *entity, b2World *world, Number worldScale, int entType, bool isStatic, Number friction, Number density, Number restitution, bool isSensor, bool fixedRotation, int groupIndex) {
 PhysicsScreenEntity::PhysicsScreenEntity(ScreenEntity *entity, b2World *world, Number worldScale, int entType, bool isStatic, Number friction, Number density, Number restitution, bool isSensor, bool fixedRotation, int groupIndex) {
 	
 	
-	this->worldScale = worldScale;
-	
-	Vector3 entityScale = entity->getCompoundScale();
-	
 	screenEntity = entity;
 	screenEntity = entity;
+
+	Vector3 entityScale = entity->getCompoundScale();
+	this->worldScale = worldScale;
+	collisionOnly = false;
+
 	
 	
-	shape = NULL;
-		
-	b2BodyDef *bodyDef = new b2BodyDef();
-	
-	Matrix4 compoundMatrix = screenEntity->getConcatenatedMatrix();	
-				
-	bodyDef->position.Set(compoundMatrix.getPosition().x/worldScale, compoundMatrix.getPosition().y/worldScale);
-	bodyDef->angle = screenEntity->getRotation()*(PI/180.0f);	
-	bodyDef->bullet = isSensor;	
-	bodyDef->fixedRotation = fixedRotation;	
+	// Create body definition---------------------------------------
+	b2BodyDef bodyDef;
+	bodyDef.position.Set(screenEntity->getPosition2D().x/worldScale, screenEntity->getPosition2D().y/worldScale);
+	bodyDef.angle = screenEntity->getRotation()*(PI/180.0f);	
+	bodyDef.bullet = isSensor;	
+	bodyDef.fixedRotation = fixedRotation;	
+	if(isStatic)
+		bodyDef.type = b2_staticBody;
+	else
+		bodyDef.type = b2_dynamicBody;
+
+		// Create the body
+	body = world->CreateBody(&bodyDef);
 	
 	
-	if(isStatic) {
-		bodyDef->type = b2_staticBody;		
-	} else {
-		bodyDef->type = b2_dynamicBody;	
-	}
-	body = world->CreateBody(bodyDef);
-	delete bodyDef;
-		
+	// Create fixture definition---------------------------------------------
 	b2FixtureDef fDef;
 	b2FixtureDef fDef;
 	fDef.friction = friction;
 	fDef.friction = friction;
 	fDef.restitution = restitution;
 	fDef.restitution = restitution;
 	fDef.density = density;
 	fDef.density = density;
 	fDef.isSensor = isSensor;
 	fDef.isSensor = isSensor;
 	fDef.filter.groupIndex = groupIndex;
 	fDef.filter.groupIndex = groupIndex;
-	
+
+	// Create Shape definition (Circle/Rectangle/Polygon)---------------------------
 	switch(entType) {
 	switch(entType) {
-		case ENTITY_MESH:
-		{
-			b2PolygonShape *b2shape = new b2PolygonShape;			
-			
+		case ENTITY_CIRCLE: {
+			b2CircleShape Shape;
+			// Set fixture shape to shape definition
+			fDef.shape = &Shape;
+			// Create the shape
+			Shape.m_radius = screenEntity->getWidth()/(worldScale*2.0f);
+			// Create the fixture
+			fixture = body->CreateFixture(&fDef);
+			break;
+		}
+		case ENTITY_RECT: {
+			b2PolygonShape Shape;
+			// Set fixture shape to shape definition
+			fDef.shape = &Shape;
+			// Create the shape
+			Shape.SetAsBox(screenEntity->getWidth()/(worldScale*2.0f) * entityScale.x, screenEntity->getHeight()/(worldScale*2.0f) * entityScale.y);
+			// Create the fixture
+			fixture = body->CreateFixture(&fDef);
+			break;
+		}
+		case ENTITY_MESH: {
+			b2PolygonShape Shape;
+			// Set fixture shape to shape definition
+			fDef.shape = &Shape;
+			// Get the screenmesh of the entity
 			ScreenMesh* screenMesh = dynamic_cast<ScreenMesh*>(entity);
 			ScreenMesh* screenMesh = dynamic_cast<ScreenMesh*>(entity);
-			if(screenMesh != NULL) {
-				b2Vec2 *vertices = (b2Vec2*)malloc(sizeof(b2Vec2) * screenMesh->getMesh()->getVertexCount());
-	
-				int index = 0;
-				for(int i=0; i < screenMesh->getMesh()->getPolygonCount(); i++) {
-					Polycode::Polygon *poly = screenMesh->getMesh()->getPolygon(i);
-					for(int j = 0; j < poly->getVertexCount(); j++) {
-						vertices[index].x = poly->getVertex(j)->x/worldScale;
-						vertices[index].y = poly->getVertex(j)->y/worldScale;						
-						index++;
+		
+			if(screenMesh) {
+				for(short i=0, polycount=screenMesh->getMesh()->getPolygonCount(); i < polycount; i++) {
+					// Get the next polygon
+					Polygon* poly = screenMesh->getMesh()->getPolygon(i);
+					// Get the vertex count of current polygon
+					unsigned short vertexcount = poly->getVertexCount();
+
+					if (vertexcount >= 3 && vertexcount <= 8) {
+						// Create new vertices array based on vertexcount
+						b2Vec2* vertices = new b2Vec2[vertexcount];
+						// and copy from the screenmesh
+						for(short index=0; index < vertexcount; index++) {
+							vertices[index].x = poly->getVertex(index)->x/worldScale;
+							vertices[index].y = poly->getVertex(index)->y/worldScale;						
+						}
+						// Create the shape
+						Shape.Set(vertices, vertexcount);
+						// Create the fixture
+						fixture = body->CreateFixture(&fDef);
+
+						delete []vertices;
 					}
 					}
+					else { Logger::log("Between 3 and 8 vertices allowed per polygon\n"); }
 				}
 				}
-				b2shape->Set(vertices, screenMesh->getMesh()->getVertexCount());	
-				free(vertices);
-			} else {
-				Logger::log("Tried to make a mesh collision object from a non-mesh\n");							
 			}
 			}
-
-			fDef.shape = b2shape;				
-			shape = b2shape;
+			else { Logger::log("Tried to make a mesh collision object from a non-mesh\n"); }
 		}
 		}
-		break;
-		case ENTITY_RECT: 
-		{
-			b2PolygonShape *b2shape = new b2PolygonShape;			
-			b2shape->SetAsBox(screenEntity->getWidth()/(worldScale*2.0f) * entityScale.x, screenEntity->getHeight()/(worldScale*2.0f) * entityScale.y);
-			fDef.shape = b2shape;						
-			shape = b2shape;
-		}
-		break;			
-		case ENTITY_CIRCLE:
-		{			
-			b2CircleShape *b2shape = new b2CircleShape;
-			b2shape->m_radius = screenEntity->getWidth()/(worldScale*2.0f);
-			fDef.shape = b2shape;
-			shape = b2shape;
-		}
-		break;
 	}
 	}
-	
-	fixture = body->CreateFixture(&fDef);	
-	
-	collisionOnly = false;
-	
 }
 }
 
 
 void PhysicsScreenEntity::applyTorque(Number torque) {
 void PhysicsScreenEntity::applyTorque(Number torque) {
@@ -141,26 +145,26 @@ void PhysicsScreenEntity::setVelocity(Number fx, Number fy) {
 }
 }
 
 
 void PhysicsScreenEntity::setVelocityX( Number fx) {
 void PhysicsScreenEntity::setVelocityX( Number fx) {
-	body->SetAwake(true);
+	body->SetAwake(true);	
 	b2Vec2 f = body->GetLinearVelocity();
 	b2Vec2 f = body->GetLinearVelocity();
-	f.x = fx;	
+	f.x = fx;
 	body->SetLinearVelocity(f);
 	body->SetLinearVelocity(f);
 }
 }
 
 
 void PhysicsScreenEntity::setVelocityY(Number fy) {
 void PhysicsScreenEntity::setVelocityY(Number fy) {
 	body->SetAwake(true);
 	body->SetAwake(true);
 	b2Vec2 f = body->GetLinearVelocity();
 	b2Vec2 f = body->GetLinearVelocity();
-	f.y = fy;	
-	body->SetLinearVelocity(f);	
+	f.y = fy;
+	body->SetLinearVelocity(f);
 }
 }
 
 
-void PhysicsScreenEntity::applyImpulse(Number fx, Number fy) {
+void PhysicsScreenEntity::applyImpulse(Number fx, Number fy) {	
 	body->SetAwake(true);
 	body->SetAwake(true);
 	b2Vec2 f =  b2Vec2(fx,fy);
 	b2Vec2 f =  b2Vec2(fx,fy);
-	b2Vec2 p = body->GetWorldPoint(b2Vec2(0.0f, 0.0f));	
-	body->ApplyLinearImpulse(f, p);	
+	b2Vec2 p = body->GetWorldPoint(b2Vec2(0.0f, 0.0f));
+	body->ApplyLinearImpulse(f, p);
 }
 }
-			
+
 void PhysicsScreenEntity::setTransform(Vector2 pos, Number angle) {
 void PhysicsScreenEntity::setTransform(Vector2 pos, Number angle) {
 	body->SetTransform(b2Vec2(pos.x/worldScale, pos.y/worldScale), angle*(PI/180.0f));
 	body->SetTransform(b2Vec2(pos.x/worldScale, pos.y/worldScale), angle*(PI/180.0f));
 }
 }
@@ -191,12 +195,49 @@ void PhysicsScreenEntity::Update() {
 	}	
 	}	
 }
 }
 
 
-PhysicsScreenEntity::~PhysicsScreenEntity() {
-	if (body) {
-		if (fixture) {	
-			body->DestroyFixture(fixture);
-		}	
-		body->GetWorld()->DestroyBody(body);	
+
+
+
+
+//==============================================
+//Add on functions to access the fixture library
+//==============================================
+
+
+// Gets the last fixture selected
+b2Fixture* PhysicsScreenEntity::getFixture() { return fixture; }
+
+
+// Returns specific fixture based on index starting from 0
+b2Fixture* PhysicsScreenEntity::getFixture(unsigned short index) {
+	if(fixture)	{
+		short i = 0;
+		for (b2Fixture* f = body->GetFixtureList(); f; f = f->GetNext()) {
+			if (i = index) {
+				fixture = f;
+				return fixture;
+			}
+			else {i++;}
+		}
+		
+		Logger::log("That fixture index does not exist\n");	
+		return fixture = NULL;
 	}
 	}
-	delete shape;
+
+	Logger::log("Fixturelist is for mesh only\n");
+	return fixture = NULL;	
 }
 }
+
+
+
+// I believe that at runtime you are not supposed to edit Shapes; However you still can
+// by getting a fixture(above) and then adding "->GetShape()" on the end to get the fixtures shape
+
+
+
+// Slight change to the destructor
+PhysicsScreenEntity::~PhysicsScreenEntity()
+{
+	if(body)
+		body->GetWorld()->DestroyBody(body);	// DestroyBody deletes fixtures and shapes automaticaly according to box2d documentation
+}