This is my first box2d game and I am currently following one of Ray Wenderlich collision detection tutorials, however in this code snippet below, I get an error saying "Assertion failed: (IsLocked() == false), function CreateBody". Ive researched the error and know the problem but do not have a solution. Any one have a solution?
- (void)addBoxBodyForSprite:(CCSprite *)sprite {
b2BodyDef spriteBodyDef;
spriteBodyDef.type = b2_dynamicBody;
spriteBodyDef.position.Set(sprite.position.x/PTM_RATIO, sprite.position.y/PTM_RATIO);
spriteBodyDef.userData = sprite;
b2Body *spriteBody = _world->CreateBody(&spriteBodyDef);
b2PolygonShape spriteShape;
As I mentioned here you can't create bodies during Step function is executing. You have to store the information required to create the body somewhere and use it later (after Step exits) to create the body
Related
I am new to Box2D and is currently trying to detect if an object (Ball) has managed to pass through another object (Goal) by using b2Contact. For this, I have implemented b2ContactListener and everything is working fine.
However, I was wondering, is there any way for me to set to detect collision for one direction only? For example, only from left to right, collision will not count if the ball passes through from right to left. I want to implement something like this from here as could be seen from the documentation.
In the documentation, they have detected the direction of the collision by using the points from the object as such
int numPoints = contact->GetManifold()->pointCount;
b2WorldManifold worldManifold;
contact->GetWorldManifold( &worldManifold );
However, for my case, I am using a b2CircleShape for my ball object, which indirectly returns the numPoints to be 0. Thus, I am unable to detect the collision using the above method. Is there any way I could detect the points from the circle? Or is there any way I could detect the direction of the collision?
Maybe this will help you.
b2WorldManifold manifold;
contact->GetWorldManifold(&manifold);
manifold.normal.Normalize();
if(manifold.normal.x > 0){
[...]
}
I am creating an app in which i am trying to Join two bodies in such away that when i move one body, the second body should be moved within the first body.
Here's my code to create a body:
- (b2Body *)addBoxBodyForDynamicSprite:(CCSprite *)sprite {
b2BodyDef spriteBodyDef;
spriteBodyDef.type = b2_dynamicBody;
//spriteBodyDef.position.Set(sprite.position.x/PTM_RATIO, sprite.position.y/PTM_RATIO);
CGPoint asolutePoint = [sprite.parent convertToWorldSpace:sprite.position];
spriteBodyDef.position.Set(asolutePoint.x/PTM_RATIO, asolutePoint.y/PTM_RATIO);
spriteBodyDef.userData = (__bridge void*)sprite;
b2Body *spriteBody = world->CreateBody(&spriteBodyDef);
b2PolygonShape spriteShape;
spriteShape.SetAsBox(sprite.contentSize.width/PTM_RATIO/2,
sprite.contentSize.height/PTM_RATIO/2);
b2FixtureDef spriteShapeDef;
spriteShapeDef.shape = &spriteShape;
spriteShapeDef.density = 0.3;
spriteShapeDef.isSensor = true;
spriteBody->CreateFixture(&spriteShapeDef);
return spriteBody;
}
One body is kinematic and other body is Dynamic. I am moving these bodies by using:
theBody->SetTransform(locationWorld, theBody->GetAngle());
If i apply linear force here, the bodies are not moving & the Joint which i used to fix them is b2WeldJoint.
b2JointDef jointDef;
jointDef.bodyA = another;
jointDef.bodyB = leftHandFixBody;
aJoint = (b2Joint *)world->CreateJoint(&jointDef);
It moves the dynamic body but the kinematic body remains on its position. I want to move both the bodies together. Any help will be really appreciated. Thanks!
Also, according to the manual, kinematic bodies are moved by setting their velocity, not by applying forces.
A kinematic body moves under simulation according to its velocity.
Kinematic bodies do not respond to forces. They can be moved manually
by the user, but normally a kinematic body is moved by setting its
velocity. A kinematic body behaves as if it has infinite mass,
however, Box2D stores zero for the mass and the inverse mass.
Kinematic bodies do not collide with other kinematic or static bodies.
Also, I have found that using SetTransform(...) to move bodies is less than effective. I created a portal with it to jump a body from one place to another, and that worked. But if I updated it every simulation cycle, the body stopped colliding with other bodies. This is just a word of caution.
Was this helpful?
i'm losing myself in this...
Situation:
Working on a game in cocos2d with box2d and I have a ropejoint between one fixed body and one dynamic body.
When I drop the dynamic body is swings from left to right and then from right to left due to the gravity in the world.
The problem:
The swings are getting shorter and shorter till finally the dynamic body hangs still beneath the fixed body. This is normal behavior but I need it to keep swinging.
My thoughts:
I think I need to apply a tangential force to the ropejoint in the direction of the swinging but how to do this is a mystery for now :)
Try setting the damping factor of the rope joint to zero
ropeJointDef.dampingRatio = 0.0f;
Hope it helps!
Here is a little code that should help you with your little problem
bool YourClass::init(){
CCCallFunc *swingL = CCCallFunc::create(this,callfunc_selector(YourClass::swingLeft));
CCDelayTime *delay = CCDelayTime::create(5);
CCCallFunc *swingR = CCCallFunc::create(this, callfunc_selector(YourClass::swingRight));
this->runAction(CCRepeatForever::create(CCSequence::create(swingL,delay,swingR,NULL)));
}
void YourClass::swingLeft(){
b2Body *dynamicBody = get your body from b2world;
dynamicBody->SetLinearVelocity(b2Vec2(-10, 0));//set velocity of the swing
}
void YourClass::swingRight(){
b2Body *dynamicBody = get your body from b2world;
dynamicBody->SetLinearVelocity(b2Vec2(10, 0));//set velocity of the swing
}
Following the tutorial for the breakout game I've created 3 sprites with their own bodies - ball and 2 paddles. My question might be very simple so sorry, I'm still learning. Anyway, my problem is unlike in the example, my sprites are scaled i.e.:
-(id)init {
p1 = [CCSprite spriteWithFile:#"1.png"];
p1.position = ccp(160, winSize.height * 0.08);
p1.scaleX = 190 / 2 / p1.contentSize.width;
p1.scaleY = 58 / 2 / p1.contentSize.height;
b2BodyDef p1BodyDef;
p1BodyDef.type = b2_dynamicBody;
p1BodyDef.position.Set(160/PTM_RATIO, 40/PTM_RATIO);
p1BodyDef.userData = p1;
_p1Body = _world->CreateBody(&p1BodyDef);
b2PolygonShape p1Shape;
p1Shape.SetAsBox(p1.contentSize.width/PTM_RATIO/2, p1.contentSize.height/PTM_RATIO/2);
b2FixtureDef p1ShapeDef;
p1ShapeDef.shape = &p1Shape;
p1ShapeDef.density = 0.3f;
p1ShapeDef.friction = 1.0f;
p1ShapeDef.restitution = 0.0f;
_p1Fixture = _p1Body->CreateFixture(&p1ShapeDef);
}
After creating the body, I created an update method which detect the collision between my paddle and ball using the contact listener. This works okay however, I noticed while testing the game that there are instances wherein the ball bounces even though it hasn't collided with the actual sprite's position like around 2-3cm off for both the top and sides of the paddle. I suspect that this is because the shape of my polygon and the scale-x and -y of my sprite are different. So my question is, how can I set the body's size to be the same as the scaled sprite? I tried something like:
p1Shape.SetAsBox(190 / 2 / p1.contentSize.width/PTM_RATIO/2, 58 / 2 / p1.contentSize.height/PTM_RATIO/2);
But the collision was ignored as if the body wasn't there at all. So how do I make the b2body of my paddle the same size of the paddle sprite if it's been scaled?
I'm not 100% sure but I think I figured it out after some more research. Here's how I set the shape of the body:
p1Shape.SetAsBox(p1.contentSize.width/PTM_RATIO/2 * p1.scaleX, p1.contentSize.height/PTM_RATIO/2 * p1.scaleY);
I can't say for certain that this is the correct solution since I don't have debug draw enabled and I can't figure out just yet how to make it work but judging from the collisions after trying to run some tests on my game, this seems like it fixed my problem. If there's anybody else who might think there's a more correct way of doing this, please let me know. Thanks
I'm trying to make a system of "chunks" in Box2D - i.e. shapes that are attached together in a big lump, so that you can break chunks off into their own body.
Currently, my system is very basic (just starting really) and modelled after the "Breakable" test in the Box2D testbed. It's a body with quite a few basic box fixtures (which will later become polygons). When you click a body, it deletes the fixture and creates a new body with the same fixture, rotation, etc in the same place as the old "chunk".
However, I can only get it to create the new body at the big body's origin
(->GetWorldCenter). What I want to do is find the global location of the fixture to be deleted and replaced, so I can make the new chunk there.
I've read some stuff about b2PolygonShape having a "centroid", but I'm not sure how to access and use that...
To put it simply, I want to find the global location (as x+y or a b2Vec2) of a FIXTURE, NOT a body (that's easy). The fixture will move with the body it's attached to, but I only currently need the position for one frame (having it update would be useful too though).
For Box2D position of the body not so important. Body position is only shift for fixture coordinates. It do not impact to simulation process. So, I don't understand, why you so care about this.
I made something like this, and can say, that using big body's origin works fine. You can see into Box2D testbed to Breakable test. There also used big body's origin. Only reason to calculate new coordinates that I see is strange behavior of SetAngle method.
If you still want centroid, look at ComputeCentroid, located at b2PolygonShape.cpp. Pay attention, method don't declared at b2PolygonShape.h. You can copy code from cpp and use it like this:
b2Fixture* chunk = ...;
b2Vec2 chunkCentroidLocal = ComputeCentorid(chunk->m_vertices,
chunk->m_vertexCount);
b2Vec2 chunkCentroidWorld = bigBody->GetWorldPoint(chunkCentroidLocal);
p.s. Don't forget to transform polygon points, when you will create new body. Simply find difference between big body and new body, and subtract it from every point of polygon.
b2Vec2 shift = chunkCentroidWorld - bigBody->GetWorldCenter();
b2Vec2 newVertices = new b2Vec2[chunk->m_vertexCount];
for(int i = 0; i< chunk->m_vertexCount; i++)
{
newVertices[i] = chunk->m_vertices[i] - shift;
}