I've been working on a game with destructible environments and I've come up with a solution where I check for possible destruction within my ContactListener object. Obviously because this is taking place within Step(), I postpone processing the destruction until the moment after the step. I do this by pooling "destruction events" that need to be processed within the contact listener, and then immediately after Step() calling something like contactListener->processDestructionEvents();.
The way I do this is by capturing the colliding fixtures within the beginContact event and then determining the angle of impact, then using that angle to raycast on the fixture itself. I then grap the vertices from the b2PolygonShape of the fixture, then generate two new shapes which are split based on the impact and exit points of the ray. The original fixture is destroyed on the body, and then a new fixture is generated for the first new shape and added to the original body. For the second shape, a new body is generated and that shape is added to this new body.
Anyway everything works great, in debug view I can see that the new shapes have been generated and are all in place, as they should be. However, I get really screwed up behavior at this point. As soon as this process is complete, neither the original nor the newly generated body will collide with anything. If I enable continuous physics, SOMETIMES a dynamic object will collide with one of the edges of these bodies/fixtures, but not always. I'm wondering if it's something I'm doing wrong in my approach to rebuilding bodies/fixtures at runtime. Here is the code for generating the new objects, any help would be greatly appreciated.
void PhysicsContactListener::processDestructionEvents() {
if(!hasDestructionEvents) {return;}
for(destructionEventsIterator = destructionEvents.begin(); destructionEventsIterator != destructionEvents.end(); ++destructionEventsIterator) {
b2Filter f1, f2;
f1.groupIndex = destructionEventsIterator->originalFixture->GetFilterData().groupIndex;
f1.categoryBits = destructionEventsIterator->originalFixture->GetFilterData().categoryBits;
f1.maskBits = destructionEventsIterator->originalFixture->GetFilterData().maskBits;
f2.groupIndex = destructionEventsIterator->originalFixture->GetFilterData().groupIndex;
f2.categoryBits = destructionEventsIterator->originalFixture->GetFilterData().categoryBits;
f2.maskBits = destructionEventsIterator->originalFixture->GetFilterData().maskBits;
b2PolygonShape newShape0 = destructionEventsIterator->newFixtures[0];
b2FixtureDef fixture0Def;
fixture0Def.shape = &newShape0;
fixture0Def.density = 1.0f;
fixture0Def.restitution = 0.2f;
b2Fixture* fixture1 = destructionEventsIterator->hostBody->CreateFixture(&fixture0Def);
fixture1->SetFilterData(f1);
//destructionEventsIterator->hostBody->SetAwake(true);
destructionEventsIterator->hostBody->ResetMassData();
//destructionEventsIterator->hostBody->SetActive(true);
destructionEventsIterator->hostBody->SetTransform(destructionEventsIterator->hostBody->GetPosition(), destructionEventsIterator->hostBody->GetAngle());
b2BodyDef bd;
bd.position = destructionEventsIterator->hostBody->GetPosition();
bd.angle = destructionEventsIterator->hostBody->GetAngle();
bd.type = destructionEventsIterator->hostBody->GetType();
b2Body* newBody = destructionEventsIterator->hostBody->GetWorld()->CreateBody(&bd);
b2PolygonShape* newShape1 = (b2PolygonShape*)(&destructionEventsIterator->newFixtures[1]);
b2Fixture* fixture2 = newBody->CreateFixture(newShape1, destructionEventsIterator->hostBodyDensity);
fixture2->SetFilterData(f2);
newBody->SetAngularVelocity(destructionEventsIterator->hostBody->GetAngularVelocity());
newBody->SetLinearVelocity(destructionEventsIterator->hostBody->GetLinearVelocity());
//newBody->SetAwake(true);
newBody->ResetMassData();
//newBody->SetActive(true);
newBody->SetTransform(destructionEventsIterator->hostBody->GetPosition(), destructionEventsIterator->hostBody->GetAngle());
destructionEventsIterator->hostBody->DestroyFixture(destructionEventsIterator->originalFixture);
}
The two pieces don't collide with each other? Take a look at the categoryBits and maskBits values that each fixture ends up with - looks like each piece is given the same values for these. My guess is you are just overlooking the fact that these masks are checked against each other both ways, eg. from the Box2D source code:
bool collide =
(filterA.maskBits & filterB.categoryBits) != 0 &&
(filterA.categoryBits & filterB.maskBits) != 0;
On the other hand if you mean the pieces collide with nothing at all and simply fall through the ground and down forever except for SOMETIMES, then I might suspect an incorrect polygon winding.
btw a b2Filter holds only primitives so you could assign those directly:
b2Filter f1 = destructionEventsIterator->originalFixture->GetFilterData();
...also, the first SetTransform and the second ResetMassData are redundant.
Related
using Unreal Engine 4, I am attempting to move my vehicle (AWheeledVehicle) in the forward direction. I am correctly referencing the correct vehicle, but still it won't move.
Not sure what I'm doing wrong.
Attached below is my Vehicle and Controller class
AAIWheeledVehicle
AAIWheeledVehicle::AAIWheeledVehicle(){
AIControllerClass = AMyAIVehicleController::StaticClass();
}
AMyAIVehicleController
void AMyAIVehicleController::Possess(APawn *pawn){
Super::Possess(pawn);
//FVector location2 = pawn->GetActorLocation(); // -11310, 8910, 0
// initialize location of target point
location.X = -9620.0f;
location.Y = 8910.0f;
location.Z = 0.0f;
scaleValue = 1.0f;
target = GetWorld()->SpawnActor<ATargetPoint>(location, FRotator::ZeroRotator);
target->SetActorLocation(location);
// get AI vehicle reference
vehicle = Cast<AWheeledVehicle>(pawn);
// add forward movement to vehicle, scale = 1
vehicle->AddMovementInput(GetActorForwardVector(), scaleValue);
//vehicle->GetVehicleMovement()->Velocity.X = 1.0f;
//vehicle->GetVehicleMovement()->SetThrottleInput(1.0f);
//vehicle->GetVehicleMovement()->SetSteeringInput(1.0f);
//vehicle->GetVehicleMovement()->SetHandbrakeInput(false);
// set rotaion of vehicle to rotation of the target point
vehicle->SetActorRotation(target->GetActorRotation());
}
Vehicle setup in UE4 is tricky. It has a few moving parts that work together. Make sure that you have the initial vehicle setup working otherwise it may not move at all regardless of the code involved. (btw the code looks fine, but I recommend testing in blueprints to verify all is correct with setup)
I made a video about vehicle setup in UE4 on my channel, This might solve your problem. Go through and make sure the setup is the same, since you need to do this whether you are using C++ or blueprints. Here's the link:
UE4 - How to Make Vehicles
EDIT 2: Problem solved! I can´t promise it will work with different settings, but by putting my block´s body density to 0, the stack of blocks did not fall when new blocks are added.
I´m sorry about the poor title of the question, I´ll explain my problem closer here:
So, I´ve used Box2D and cocos2D to setup a simple project where two boxes stacks on top of each other (I´m planning to expand to 8-10 boxes). Right now, using a friction of 10.0f on each box, the box at the top still moves around a little. If I would add more boxes, the "tower" would fall and I don´t want that.
I want the boxes to use the gravity to move down, but I never ever want them to change there start x-value.
So, how could I prevent my tower of boxes to fall over or prevent my boxes from moving in x-direction?
EDIT: Posting some code
This code creates on of the boxes, the other one just have a different sprite file.
CCSprite *block = [CCSprite spriteWithFile:#"red.png"];
block.position = ccp(200,380);
[self addChild:block];
//Body definition
b2BodyDef blockDef;
blockDef.type = b2_dynamicBody;
blockDef.position.Set(200/PTM_RATIO, 200/PTM_RATIO);
blockDef.userData = block;
b2Body *blockBody = _world->CreateBody(&blockDef);
//Create the shape
b2PolygonShape blockShape;
blockShape.SetAsBox(block.contentSize.width/PTM_RATIO/2, block.contentSize.height/PTM_RATIO/2);
//Fixture defintion
b2FixtureDef blockFixtureDef;
blockFixtureDef.shape = &blockShape;
blockFixtureDef.restitution = 0.0f;
blockFixtureDef.density = 10.0f;
blockFixtureDef.friction = 10.0f;
_redBlockFixture = blockBody->CreateFixture(&blockFixtureDef);
Nothing fancy.
Regards.
You could setup a 2 (1 pixel wide) walls in box2D to the left and right of the block. Here's some sample code for the left wall. To create the right wall, just copy and past the code and change the variable names and the position of the BodyDef.
// Constant you'll need to define
float wallHeight;
// Create wall body
b2BodyDef wallBodyDef;
wallBodyDef.type = b2_dynamicBody;
wallBodyDef.position.Set(200 - block.contentSize.width/PTM_RATIO/2, 0);
b2Body *wallBody = _world->CreateBody(&wallBodyDef);
// Create wall shape
b2PolygonShape wallShape;
wallShape.SetAsBox(1, wallHeight);
// Create shape definition and add to body
b2FixtureDef wallShapeDef;
wallShapeDef.shape = &wallShape;
wallShapeDef.density = 100.0f;
wallShapeDef.friction = 0.0f;
wallShapeDef.restitution = 0.0f;
b2Fixture *wallFixture = wallBody->CreateFixture(&wallShapeDef);
I solved this problem by adjusting the restitution (bounce) of the static surface upon which the blocks are stacked. For example, if the floor has a restitution of .2, a stack of five blocks will look like they are compressing into each other, and eventually topple:
Set the restitution of the floor to 0, and the blocks stay stacked the way you would expect:
Hi I'm having some fun with Box2D. And I'm working on a network game that requires full sync with all bodies. (There wont be many bodies).
So the plan is that i start up a server with some bodies in it. The server does the world simulation steps. Then after a while a client connects. When it does the server sends all state data for all bodies in the world to the client and the client will create them as NEW bodies. And then the client will have an exact fully synchronized copy of the game on the client side. Any small change on the server is copied and sent as message to the client. And because Box2D is deterministic any change on the server side will behave exactly the same on the client.
This works great if all bodies are awake. However when i one of them are asleep the simulations becomes unsynced. The positions, angles and velocitys for sleeping bodies differ with just a few decimals. actually it looks like they just need to be resting to screw up the sync.
So what i noticed was that even if i EXPLICITLY set a NEW body to be asleep, after the next world step it will become awake again. I'm guessing that is because Box2D needs to run a check on new bodies of some sort.
Is there anyway to fix this? And keep the sync?
currently im resyncing all bodies every 120th frame if offsync is detected by my checksum check. and keeps doing that until they are insync again. this causes some snapping of the game objects but still works surprisingly well, but id rather the game would not get offsync in the first place.
the server will send the float and int values to the client who will create the bodies using the following code. the server uses pretty much the same code when creating bodies on the server side:
//------------create world---------------
b2Vec2 gravity(0.0f, -10.0f);
b2World world(gravity);
world.SetAllowSleeping(true);
//---------------create bodies from values sent by server----------------------
//body def
b2BodyDef bodyDef;
if(bodyType == static_body)
bodyDef.type = b2_staticBody;
else if(bodyType == dynamic_body)
bodyDef.type = b2_dynamicBody;
else
throw "error invalid body def types";
bodyDef.angle = angle;
bodyDef.angularDamping = angularDamping;
bodyDef.angularVelocity = angularVelocity;
bodyDef.gravityScale = gravityScale;
bodyDef.linearDamping = linearDamping;
bodyDef.linearVelocity.x = linearVelocityX;
bodyDef.linearVelocity.y = linearVelocityY;
bodyDef.position.x = positionX;
bodyDef.position.y = positionY;
bodyDef.active = isActive;
bodyDef.awake = isAwake;
bodyDef.bullet = isBullet;
bodyDef.fixedRotation = isFixedRotation;
bodyDef.allowSleep = isSleepingAllowed;
//body
// Call the body factory which allocates memory for the ground body
// from a pool and creates the ground box shape (also from a pool).
// The body is also added to the world.
body = world.CreateBody(&bodyDef);
//fixture def
b2PolygonShape polygonShape;
polygonShape.SetAsBox(shapeWidth, shapeHeight);
b2FixtureDef fixtureDef;
fixtureDef.shape = &polygonShape;
fixtureDef.restitution = 0.5f; // air resistance / fluid resistance
fixtureDef.density = 1.0f;
fixtureDef.friction = 1.0f;
//fixture
body->CreateFixture(&fixtureDef);
//set mass inertia and center
b2MassData md;
md.center = b2Vec2_zero;
md.I = intertia;
md.mass = mass;
body->SetMassData(&md);
//these cannot be predefined for some reason, seems like a bug in box2d
body->SetFixedRotation(isFixedRotation);
//----------run game simulations-----------
float32 timeStep = 1.0f / 60.0f;
int32 velocityIterations = 6;
int32 positionIterations = 2;
world.Step(timeStep, velocityIterations, positionIterations);
I asked in box2d forum and it seems like the internal state of box2d may differ if the simulation starts at different time steps. so the only solution is to work around it.
http://www.box2d.org/forum/viewtopic.php?f=3&t=8462&p=36115#p36115
I'm having a lot of trouble detecting collisions in a zero-G space game. Hopefully this image will help me explain:
http://i.stack.imgur.com/f7AHO.png
The white rectangle is a static body with a b2PolygonShape fixture attached, as such:
// Create the line physics body definition
b2BodyDef wallBodyDef;
wallBodyDef.position.Set(0.0f, 0.0f);
// Create the line physics body in the physics world
wallBodyDef.type = b2_staticBody; // Set as a static body
m_Body = world->CreateBody(&wallBodyDef);
// Create the vertex array which will be used to make the physics shape
b2Vec2 vertices[4];
vertices[0].Set(m_Point1.x, m_Point1.y); // Point 1
vertices[1].Set(m_Point1.x + (sin(angle - 90*(float)DEG_TO_RAD)*m_Thickness), m_Point1.y - (cos(angle - 90*(float)DEG_TO_RAD)*m_Thickness)); // Point 2
vertices[2].Set(m_Point2.x + (sin(angle - 90*(float)DEG_TO_RAD)*m_Thickness), m_Point2.y - (cos(angle - 90*(float)DEG_TO_RAD)*m_Thickness)); // Point 3
vertices[3].Set(m_Point2.x, m_Point2.y); // Point 3
int32 count = 4; // Vertex count
b2PolygonShape wallShape; // Create the line physics shape
wallShape.Set(vertices, count); // Set the physics shape using the vertex array above
// Define the dynamic body fixture
b2FixtureDef fixtureDef;
fixtureDef.shape = &wallShape; // Set the line shape
fixtureDef.density = 0.0f; // Set the density
fixtureDef.friction = 0.0f; // Set the friction
fixtureDef.restitution = 0.5f; // Set the restitution
// Add the shape to the body
m_Fixture = m_Body->CreateFixture(&fixtureDef);
m_Fixture->SetUserData("Wall");[/code]
You'll have to trust me that that makes the shape in the image. The physics simulation works perfectly, the player (small triangle) collides with the body with pixel perfect precision. However, I come to a problem when I try to determine when a collision takes place so I can remove health and what-not. The code I am using for this is as follows:
/*------ Check for collisions ------*/
if (m_Physics->GetWorld()->GetContactCount() > 0)
{
if (m_Physics->GetWorld()->GetContactList()->GetFixtureA()->GetUserData() == "Player" &&
m_Physics->GetWorld()->GetContactList()->GetFixtureB()->GetUserData() == "Wall")
{
m_Player->CollideWall();
}
}
I'm aware there are probably better ways to do collisions, but I'm just a beginner and haven't found anywhere that explains how to do listeners and callbacks well enough for me to understand. The problem I have is that GetContactCount() shows a contact whenever the player body enters the purple box above. Obviously there is a rectangular bounding box being created that encompasses the white rectangle.
I've tried making the fixture an EdgeShape, and the same thing happens. Does anyone have any idea what is going on here? I'd really like to get collision nailed so I can move on to other things. Thank you very much for any help.
The bounding box is an AABB (axis aligned bounding box) which means it will always be aligned with the the Cartesian axes. AABBs are normally used for broadphase collision detection because it's a relatively simple (and inexpensive) computation.
You need to make sure that you're testing against the OBB (oriented bounding box) for the objects if you want more accurate (but not pixel perfect, as Micah pointed out) results.
Also, I agree with Micah's answer that you will most likely need a more general system for handling collisions. Even if you only ever have just walls and the player, there's no guarantee that which object will be A and which will be B. And as you add other object types, this will quickly unravel.
Creating the contact listener isn't terribly difficult, from the docs (added to attempt to handle your situation):
class MyContactListener:public b2ContactListener
{
private:
PlayerClass *m_Player;
public:
MyContactListener(PlayerClass *player) : m_Player(player)
{ }
void BeginContact(b2Contact* contact)
{ /* handle begin event */ }
void EndContact(b2Contact* contact)
{
if (contact->GetFixtureA()->GetUserData() == m_Player
|| contact->GetFixtureB()->GetUserData() == m_Player)
{
m_Player->CollideWall();
}
}
/* we're not interested in these for the time being */
void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
{ /* handle pre-solve event */ }
void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
{ /* handle post-solve event */ }
};
This requires you to assign m_Player to the player's fixture's user data field. Then you can use the contact listener like so:
m_Physics->GetWorld()->SetContactListener(new MyContactListener(m_Player));
How do you know GetFixtureA is the player and B is the wall? Could it be reversed? Could there be an FixtureC? I would think you would need a more generic solution.
I've used a similar graphics framework (Qt) and it had something so you could grab any two objects and call something like 'hasCollided' which would return a bool. You could get away with not using a callback and just call it in the drawScene() or check it periodically.
In Box2D the existence of a contact just means that the AABBs of two fixtures overlaps. It does not necessarily mean that the shapes of the fixtures themselves are touching.
You can use the IsTouching() function of a contact to check if the shapes are actually touching, but the preferred way to deal with collisions is to use the callback feature to have the engine tell you whenever two fixtures start/stop touching. Using callbacks is much more efficient and easier to manage in the long run, though it may be a little more effort to set up initially and there are a few things to be careful about - see here for an example: http://www.iforce2d.net/b2dtut/collision-callbacks
I am using Cocos2D with Box2D to create a simple physics game. I want to adjust the volume of a collision sound effect depending on the speed of the colliding body. The faster the body is travelling when it collides, the louder the sound. I am using the SimpleAudioEngine library which has a playSound method with a gain parameter. Is there a way to convert the speed of the colliding body (a b2Body object) to a value between 0 and 1 that I can apply to the gain?
In the post solve function get an impulse value, divide it by 100 perhaps? I'm not sure what the levels of impulse you get are.
void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
{
b2Fixture* fixtureA = contact->GetFixtureA();
b2Fixture* fixtureB = contact->GetFixtureB();
void* userDataA = fixtureA->GetBody()->GetUserData();
CCNode *myActorA = (CCNode*)userDataA;
void* userDataB = fixtureB->GetBody()->GetUserData();
CCNode *myActorB = (CCNode*)userDataB;
// stuff above will allow you to work out which objects are hitting each other
// get the impulse
int impulseInt = impulse->normalImpulses[0];
}