Просмотр исходного кода

Physics entities can now use multiple fixtures

This fixes bug #79. Physics enties can now have multiple fixtues each
with it's own polygon shape. Each polygon is still limited to 8
verticies as Box2D suggests.
Paul Smith 13 лет назад
Родитель
Сommit
79bc2e8ed1

+ 5 - 5
Modules/Contents/2DPhysics/Include/PolyPhysicsScreen.h

@@ -175,7 +175,7 @@ public:
 	* @param fixedRotation If this is set to true, the entity will always have a locked rotation.
 	* @return The physics entity wrapper.
 	*/
-	PhysicsScreenEntity *addPhysicsChild(ScreenEntity *newEntity, int entType, bool isStatic, Number friction=0.1, Number density=1, Number restitution = 0, bool isSensor = false, bool fixedRotation = false, int groupIndex = 0);
+	PhysicsScreenEntity *addPhysicsChild(ScreenEntity *newEntity, int entType, bool isStatic, Number friction=0.1, Number density=1, Number restitution = 0, bool isSensor = false, bool fixedRotation = false);
 
 	/**
 	* Tracks a ScreenEntity as a physics enabled child. 
@@ -189,7 +189,7 @@ public:
 	* @param fixedRotation If this is set to true, the entity will always have a locked rotation.
 	* @return The physics entity wrapper.
 	*/
-	PhysicsScreenEntity *trackPhysicsChild(ScreenEntity *newEntity, int entType, bool isStatic, Number friction=0.1, Number density=1, Number restitution = 0, bool isSensor = false, bool fixedRotation = false, int groupIndex = 0);
+	PhysicsScreenEntity *trackPhysicsChild(ScreenEntity *newEntity, int entType, bool isStatic, Number friction=0.1, Number density=1, Number restitution = 0, bool isSensor = false, bool fixedRotation = false);
 
 	
 	/**
@@ -199,7 +199,7 @@ public:
 	void removePhysicsChild(ScreenEntity *entityToRemove);
 	
 	
-	void removeChild(ScreenEntity *entityToRemove);
+	ScreenEntity* removeChild(ScreenEntity *entityToRemove);
 	
 	
 	/**
@@ -208,7 +208,7 @@ public:
 	* @param entType Physics shape of the entity. Possible values are PhysicsScreenEntity::ENTITY_RECT or PhysicsScreenEntity::ENTITY_CIRCLE.
 	* @param entityToRemove Entity to remove from the screen.
 	*/	
-	PhysicsScreenEntity *addCollisionChild(ScreenEntity *newEntity, int entType, int groupIndex = 0);
+	PhysicsScreenEntity *addCollisionChild(ScreenEntity *newEntity, int entType);
 	
 	/**
 	* Begins tracking collisions for a ScreenEntity.
@@ -216,7 +216,7 @@ public:
 	* @param entType Physics shape of the entity. Possible values are PhysicsScreenEntity::ENTITY_RECT or PhysicsScreenEntity::ENTITY_CIRCLE.
 	* @param entityToRemove Entity to remove from the screen.
 	*/	
-	PhysicsScreenEntity *trackCollisionChild(ScreenEntity *newEntity, int entType, int groupIndex = 0);	
+	PhysicsScreenEntity *trackCollisionChild(ScreenEntity *newEntity, int entType);	
 	
 	/**
 	* Removes an existing joint.

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

@@ -58,10 +58,16 @@ namespace Polycode {
 			
 			void setVelocity(Number fx, Number fy);	
 			void setVelocityX( Number fx);	
-			void setVelocityY(Number fy);				
+			void setVelocityY(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
+			
+															// You do not need a shape pointer
+
 			/**
 			* Rectangular physics entity
 			*/ 
@@ -75,10 +81,9 @@ namespace Polycode {
 			*/ 						
 			static const int ENTITY_MESH = 3;
 		
-			b2Fixture *fixture;		
-			b2Body* body;
-			b2Shape *shape;
-			
+			b2Body *body;
+			b2Fixture *fixture;
+
 			bool collisionOnly;
 		
 		protected:
@@ -87,4 +92,4 @@ namespace Polycode {
 		ScreenEntity *screenEntity;
 	};
 
-}
+}

+ 60 - 30
Modules/Contents/2DPhysics/Source/PolyPhysicsScreen.cpp

@@ -274,34 +274,51 @@ void PhysicsScreen::setVelocity(ScreenEntity *ent, Number fx, Number fy) {
 	PhysicsScreenEntity *pEnt = getPhysicsByScreenEntity(ent);
 	if(pEnt == NULL)
 		return;
-	pEnt->setVelocity(fx, fy);	
+	
+	pEnt->body->SetAwake(true);
+	b2Vec2 f = pEnt->body->GetLinearVelocity();
+	if(fx != 0)
+		f.x = fx;
+	if(fy != 0)
+		f.y = fy;
+	
+	pEnt->body->SetLinearVelocity(f);
 }
 
 void PhysicsScreen::setVelocityX(ScreenEntity *ent, Number fx) {
 	PhysicsScreenEntity *pEnt = getPhysicsByScreenEntity(ent);
 	if(pEnt == NULL)
 		return;
-	pEnt->setVelocityX(fx);
+	
+	pEnt->body->SetAwake(true);
+	b2Vec2 f = pEnt->body->GetLinearVelocity();
+	f.x = fx;	
+	pEnt->body->SetLinearVelocity(f);
+	
 }
 
 void PhysicsScreen::setVelocityY(ScreenEntity *ent, Number fy) {
 	PhysicsScreenEntity *pEnt = getPhysicsByScreenEntity(ent);
 	if(pEnt == NULL)
 		return;
-	pEnt->setVelocityY(fy);
+	
+	pEnt->body->SetAwake(true);
+	b2Vec2 f = pEnt->body->GetLinearVelocity();
+	f.y = fy;	
+	pEnt->body->SetLinearVelocity(f);	
 }
 
 
-PhysicsScreenEntity *PhysicsScreen::addCollisionChild(ScreenEntity *newEntity, int entType, int groupIndex) {
+PhysicsScreenEntity *PhysicsScreen::addCollisionChild(ScreenEntity *newEntity, int entType) {
 	PhysicsScreenEntity *ret;
-	ret = addPhysicsChild(newEntity, entType, false, 0,0.0,0, true, groupIndex);
+	ret = addPhysicsChild(newEntity, entType, false, 0,0.0,0, true);
 	ret->collisionOnly = true; 
 	return ret;
 }
 
-PhysicsScreenEntity *PhysicsScreen::trackCollisionChild(ScreenEntity *newEntity, int entType, int groupIndex) {
+PhysicsScreenEntity *PhysicsScreen::trackCollisionChild(ScreenEntity *newEntity, int entType) {
 	PhysicsScreenEntity *ret;
-	ret = trackPhysicsChild(newEntity, entType, false, 0,0.0,0, true, groupIndex);
+	ret = trackPhysicsChild(newEntity, entType, false, 0,0.0,0, true);
 	ret->collisionOnly = true; 
 	return ret;
 }
@@ -329,7 +346,11 @@ void PhysicsScreen::applyImpulse(ScreenEntity *ent, Number fx, Number fy) {
 	PhysicsScreenEntity *pEnt = getPhysicsByScreenEntity(ent);
 	if(pEnt == NULL)
 		return;
-	pEnt->applyImpulse(fx, fy);
+	
+	pEnt->body->SetAwake(true);
+	b2Vec2 f =  b2Vec2(fx,fy);
+	b2Vec2 p = pEnt->body->GetWorldPoint(b2Vec2(0.0f, 0.0f));	
+	pEnt->body->ApplyLinearImpulse(f, p);	
 }
 
 
@@ -384,9 +405,11 @@ ScreenEntity *PhysicsScreen::getEntityAtPosition(Number x, Number y) {
 	
 	for(int i=0;i<physicsChildren.size();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 +426,13 @@ bool PhysicsScreen::testEntityAtPosition(ScreenEntity *ent, Number x, Number y)
 	mousePosition.x = x/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;
 }
@@ -417,14 +442,14 @@ void PhysicsScreen::destroyMouseJoint(b2MouseJoint *mJoint) {
 		mJoint = NULL;
 }
 
-PhysicsScreenEntity *PhysicsScreen::addPhysicsChild(ScreenEntity *newEntity, int entType, bool isStatic, Number friction, Number density, Number restitution, bool isSensor, bool fixedRotation, int groupIndex) {
+PhysicsScreenEntity *PhysicsScreen::addPhysicsChild(ScreenEntity *newEntity, int entType, bool isStatic, Number friction, Number density, Number restitution, bool isSensor, bool fixedRotation) {
 	addChild(newEntity);
-	return trackPhysicsChild(newEntity, entType, isStatic, friction, density, restitution, isSensor, fixedRotation, groupIndex);
+	return trackPhysicsChild(newEntity, entType, isSensor, friction, density, restitution, isSensor, fixedRotation);
 }
 
-PhysicsScreenEntity *PhysicsScreen::trackPhysicsChild(ScreenEntity *newEntity, int entType, bool isStatic, Number friction, Number density, Number restitution, bool isSensor, bool fixedRotation, int groupIndex) {
+PhysicsScreenEntity *PhysicsScreen::trackPhysicsChild(ScreenEntity *newEntity, int entType, bool isStatic, Number friction, Number density, Number restitution, bool isSensor, bool fixedRotation) {
 	newEntity->setPositionMode(ScreenEntity::POSITION_CENTER);
-	PhysicsScreenEntity *newPhysicsEntity = new PhysicsScreenEntity(newEntity, world, worldScale, entType, isStatic, friction, density, restitution, isSensor,fixedRotation, groupIndex);
+	PhysicsScreenEntity *newPhysicsEntity = new PhysicsScreenEntity(newEntity, world, worldScale, entType, isStatic, friction, density, restitution, isSensor,fixedRotation);
 	physicsChildren.push_back(newPhysicsEntity);
 	newPhysicsEntity->body->SetAwake(true);
 	return newPhysicsEntity;
@@ -445,12 +470,13 @@ void PhysicsScreen::removePhysicsChild(ScreenEntity *entityToRemove) {
 	Screen::removeChild(entityToRemove);	
 }
 
-void PhysicsScreen::removeChild(ScreenEntity *entityToRemove) {
+ScreenEntity* PhysicsScreen::removeChild(ScreenEntity *entityToRemove) {
 	if(getPhysicsByScreenEntity(entityToRemove)) {
 		removePhysicsChild(entityToRemove);
 	} else {
 		Screen::removeChild(entityToRemove);	
 	}
+	return entityToRemove;
 }
 
 
@@ -464,23 +490,27 @@ PhysicsScreen::~PhysicsScreen() {
 	}
 	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;	
 }
 
-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++) {
-		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;
 }
-	
+
 void PhysicsScreen::handleEvent(Event *event) {	
 	Screen::handleEvent(event);
 }

+ 127 - 82
Modules/Contents/2DPhysics/Source/PolyPhysicsScreenEntity.cpp

@@ -31,90 +31,98 @@ THE SOFTWARE.
 
 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) {
-	
-	this->worldScale = worldScale;
-	
-	Vector3 entityScale = entity->getCompoundScale();
-	
+PhysicsScreenEntity::PhysicsScreenEntity(ScreenEntity *entity, b2World *world, Number worldScale, int entType, bool isStatic, Number friction, Number density, Number restitution, bool isSensor, bool fixedRotation,  int groupIndex)
+{
 	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;
 	fDef.friction = friction;
 	fDef.restitution = restitution;
 	fDef.density = density;
 	fDef.isSensor = isSensor;
 	fDef.filter.groupIndex = groupIndex;
-	
+
+	// Create Shape definition (Circle/Rectangle/Polygon)---------------------------
 	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);
-			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 {
+			}
+			else {
 				Logger::log("Tried to make a mesh collision object from a non-mesh\n");							
 			}
-
-			fDef.shape = b2shape;				
-			shape = b2shape;
-		}
-		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) {
@@ -141,26 +149,26 @@ void PhysicsScreenEntity::setVelocity(Number fx, Number fy) {
 }
 
 void PhysicsScreenEntity::setVelocityX( Number fx) {
-	body->SetAwake(true);
+	body->SetAwake(true);	
 	b2Vec2 f = body->GetLinearVelocity();
-	f.x = fx;	
+	f.x = fx;
 	body->SetLinearVelocity(f);
 }
 
 void PhysicsScreenEntity::setVelocityY(Number fy) {
 	body->SetAwake(true);
 	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);
 	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) {
 	body->SetTransform(b2Vec2(pos.x/worldScale, pos.y/worldScale), angle*(PI/180.0f));
 }
@@ -191,12 +199,49 @@ void PhysicsScreenEntity::Update() {
 	}	
 }
 
-PhysicsScreenEntity::~PhysicsScreenEntity() {
-	if (body) {
-		if (fixture) {	
-			body->DestroyFixture(fixture);
-		}	
-		body->GetWorld()->DestroyBody(body);	
+
+
+
+
+//========================================
+//Add on functions for 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
+}