Box2D with UIKit - Body Physics - ios

I followed this tutorial on how to add Box2D to my existing ViewBased Application.
http://www.cocoanetics.com/2010/05/physics-101-uikit-app-with-box2d-for-gravity/
Now when my body/UIButton is above half way my screen, it flies upward. and when it's half way downward, it flies downward. Also the physics are not seeming to be very realistic. I built my world the same way it is (with a couple of modifications to make it Xcode 4.0 compatible) built in the tutorial. Same goes for the timer, and the body creation. Anyone know what's wrong? (let me know if you need more detail)
Here is my code for body creation:
// Define the dynamic body.
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
CGPoint p = physicalView.center;
CGPoint boxDimensions = CGPointMake(physicalView.bounds.size.width/PTM_RATIO/2.0,physicalView.bounds.size.height/PTM_RATIO/2.0);
bodyDef.position.Set(p.x/PTM_RATIO, (self.stage.frame.size.height - p.y)/PTM_RATIO);
bodyDef.userData = (__bridge void *)physicalView;
// Tell the physics world to create the body
b2Body *body = world->CreateBody(&bodyDef);
// Define another box shape for our dynamic body.
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(boxDimensions.x, boxDimensions.y);
// Define the dynamic body fixture.
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 3.0f; // 0 is a ball, and 1 is a rock
fixtureDef.friction = 0.3f; // 0 is a lubercated ball, 1 is rough as sand paper
fixtureDef.restitution = 0.5f; // 0 is a lead ball, 1 is a super bouncy ball
body->CreateFixture(&fixtureDef);
Here is my code for setting up the world:
CGSize screenSize = self.stage.bounds.size;
screenSize.width = 368;
// Define the gravity vector.
b2Vec2 gravity;
gravity.Set(0.0f, -9.81f);
// Do we want to let bodies sleep?
// This will speed up the physics simulation
bool doSleep = false;
// Construct a world object, which will hold and simulate the rigid bodies.
world = new b2World(gravity);
world->SetAllowSleeping(doSleep);
world->SetContinuousPhysics(true);
// Define the ground body.
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0, 0); // bottom-left corner
// 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.
b2Body* groundBody = world->CreateBody(&groundBodyDef);
// Define the ground box shape.
b2EdgeShape groundBox;
// bottom
groundBox.Set(b2Vec2(0,0), b2Vec2(screenSize.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox, 0);
// top
groundBox.Set(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO));
groundBody->CreateFixture(&groundBox, 0);
// left
groundBox.Set(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(0,0));
groundBody->CreateFixture(&groundBox, 0);
// right
groundBox.Set(b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox, 0);
// a dynamic body reacts to forces right away
body->SetType(b2_dynamicBody);
// we abuse the tag property as pointer to the physical body
physicalView.tag = (int)body;

The problem was I had an invisible UIView that programically pops into the view and started colliding with the other objects.

Related

Circular body positioning not working in box2d(cocos2dx)

I'm developing a cocos2dX game. I use box2d for physics simulation. I'm trying to add a circular body and a rectangular body. Here is my code
// Create circular sprite and body
CCSprite* ball_sprite = CCSprite::create("ball.png");
this->addChild(ball_sprite);
b2BodyDef ballBodyDef;
ballBodyDef.type = b2_dynamicBody;
ballBodyDef.position.Set(screenSize.width/PTM_RATIO, screenSize.height/2/PTM_RATIO);//im running it in an iphone retina and screensize is 640x960
ballBodyDef.userData = ball_sprite;
ball_body = _world->CreateBody(&ballBodyDef);
b2CircleShape ballshape;
ballshape.m_radius = BALL_SIZE/2;
b2FixtureDef ballShapeDef;
ballShapeDef.shape = &ballshape;
ballShapeDef.density = 100.0f;
ballShapeDef.friction = 0.5f;
ballShapeDef.restitution = 0.7f;
ball_body->CreateFixture(&ballShapeDef);
// Create rectangular sprite and body
CCSprite* block_sprite = CCSprite::create("HelloWorld.png");
this->addChild(block_sprite);
b2BodyDef blockBodyDef;
blockBodyDef.type = b2_staticBody;
blockBodyDef.position.Set(0, screenSize.height/2/PTM_RATIO);
blockBodyDef.userData = block_sprite;
block_bodie = _world->CreateBody(&blockBodyDef);
b2PolygonShape blockshape;
blockshape.SetAsBox(B_WIDTH/PTM_RATIO,B_HEIGHT/PTM_RATIO);
b2FixtureDef blockShapeDef;
blockShapeDef.shape = &blockshape;
blockShapeDef.density = 100.0f;
blockShapeDef.friction = 0.5f;
blockShapeDef.restitution = 0.7f;
block_bodie->CreateFixture(&blockShapeDef);
The rectangular body is shown in the screen as expected.
But the circular body is not shown in the screen.
When I printed the position of circular body in the update function, the positions are large numbers around 2000. And this position is different each time I run the programm.
If the rectangular body is not added(commenting the line block_bodie->CreateFixture(&blockShapeDef);) then the circular body is shown in the screen as I expected.
What I'm doing wrong here?
Thanks in advance.
Are these two bodies overlapping when they are created? Most likely the circle is simply being pushed away by the rectangle, because the rectangle is static and the circle is dynamic. If you try creating both of them, but don't call the world Step function to run the physics simulation, you will probably see them both on screen.
You could create them so that they are not overlapping, or at least not overlapping as much, or make one of them a sensor, or set their collision category and mask bits so they don't interact.
Of course, I am assuming you are looking at the debug draw display, which is really the only way to know for sure what the physics engine is doing.

SpriteKit Node Rotational Issues

I am trying to develop a basic game for iOS involving a rag doll-like entity. Basically (as you can tell below), I have a head, a body, and a right arm (all three are basic sprite nodes) connected via pin joints, simulating joins in the human body (roughly).
The head and the body work perfectly in that, when a force is applied, the body rotates around the head perfectly and eventually comes to a rest under the head, vertically (see picture).
The arm's base is pinned with a pin joint to the body and is supposed to rotate around its base (kind of like a shoulder) and it is set with an initial rotation of 45 degrees so it looks like an arm before the physics engine takes over.
My question is: why doesn't the arm come to rest in a vertical position (like the body) due to gravity? Shouldn't gravity cause the arm to rotate about its base until the tip of the arm rests directly below the top of the arm (shoulder)? Furthermore, when a force is applied to the body (shown in the example code below), the body rotates about the neck joint, exactly as it should, but the arm does not move from its current orientation (and this is not desirable).
If this is not the case, how would I achieve this effect?
Thank you for your time and I'd be happy to provide any additional information if desired
Picture of physics simulation at rest:
Relevant code which demonstrates the problem:
//make the head node
SKSpriteNode *head = [SKSpriteNode spriteNodeWithImageNamed:#"head"];
head.size = CGSizeMake(20 * [CFLConstants universalWidthScaleFactor], 20 * [CFLConstants universalWidthScaleFactor]);
head.position = position;
head.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:head.size.width/2];
head.physicsBody.categoryBitMask = CFLPhysicsCategoriesHead;
head.physicsBody.collisionBitMask = 0;
head.physicsBody.dynamic = NO;
[self.ragdollLayer addChild:head];
//make the body node
SKSpriteNode *body = [SKSpriteNode spriteNodeWithImageNamed:#"body"];
body.size = CGSizeMake(head.size.width, head.size.width * 3);
body.position = CGPointMake(head.position.x, head.position.y - head.size.height/2 - body.size.height/2);
body.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:body.size];
body.physicsBody.categoryBitMask = CFLPhysicsCategoriesBody;
body.physicsBody.collisionBitMask = 0;
[self.ragdollLayer addChild:body];
//attach the head and the body (via a neck joint)
SKPhysicsJointPin *neckJoint = [SKPhysicsJointPin jointWithBodyA:head.physicsBody bodyB:body.physicsBody anchor:CGPointMake(head.position.x, head.position.y - head.size.height/2)];
[self.physicsWorld addJoint:neckJoint];
//make the right arm
SKSpriteNode *rightArm = [SKSpriteNode spriteNodeWithImageNamed:#"arm"];
rightArm.size = CGSizeMake(head.size.width/5, head.size.width/5 * 10);
rightArm.anchorPoint = CGPointZero;
CGPoint rightArmPosition = CGPointMake(body.position.x + body.size.width * 1/5, body.position.y + body.size.height * 1/5);
rightArm.position = rightArmPosition;
rightArm.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rightArm.size];
rightArm.physicsBody.categoryBitMask = CFLPhysicsCategoriesRightArm;
rightArm.physicsBody.collisionBitMask = 0;
rightArm.zRotation = -M_PI_4;
//force which makes the arm problem even more noticeable
[body.physicsBody applyImpulse:CGVectorMake(100, 0)];
[self.ragdollLayer addChild:rightArm];
//make the joint which holds the right arm to the body, but should allow the arm to rotate about this point (and doesn't)
SKPhysicsJointPin *rightShoulderJoint = [SKPhysicsJointPin jointWithBodyA:body.physicsBody bodyB:rightArm.physicsBody anchor:rightArmPosition];
[self.physicsWorld addJoint:rightShoulderJoint];
In my experience, this is because changing the anchor point on the sprite, doesn't change the anchor point for the physics body. Though I swear sometimes you don't have to, so maybe it's an order of operations thing. But anyways, offset the center of the physics body to account for the sprite anchor point. Something like:
spriteRightArm.anchorPoint = CGPointMake(0, 1);
spriteRightArm.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:spriteRightArm.size center:CGPointMake(spriteRightArm.size.width/2, -spriteRightArm.size.height/2)];

Cocos2d: Disable rotation display for CCSprite

I am creating a sprite like this:
CatSprite *aCat = [CatSprite spriteWithFile:#"Icon-Small.png"];
// add sprite to CCLayer
[self addChild:aCat];
// and then define the body and shape
cpBody *body = cpBodyNew(10.0f, cpMomentForPoly(1000.0f, num, verts, CGPointZero));
body->p = ccp(x, y);
cpSpaceAddBody(space, body);
cpShape* shape = cpPolyShapeNew(body, num, verts, CGPointZero);
shape->e = 0.5f; shape->u = 1.0f;
shape->data = aCat;
cpSpaceAddShape(space, shape);
I am applying physics and constraints to the body in chipmunk space. What I want is to disable the display of the body rotation, in other words when body rotate I want the sprite to stay on 0 degree. Any ideas please?
Thank you
So there is inevitably somewhere that you are copying the rotation of the body to the sprite. Unless you are using the released-days-ago alpha preview of Cocos2D v3, CCSprites and cpBodies don't actually work together unless you write code that syncs the sprite with the body. Simply don't copy the rotation for that sprite.
You can also disable body rotation completely, setting its inertia to INFINITY, e.g. cpBodyNew(10.0f, INFINITY);

Starling + Box2d - Collision not precise

I create stage walls and a box inside on my mobile app using starling + as3.
Ok, now when I test the app the box falls but it does not match the walls, as if there
was an offset:
https://www.dropbox.com/s/hd4ehnfthh0ucfm/box.png
Here is how I created the boxes (walls and the box).
It seems like there is an offset hidden, what do you think?
public function createBox(x:Number, y:Number, width:Number, height:Number, rotation:Number = 0, bodyType:uint = 0):void {
/// Vars used to create bodies
var body:b2Body;
var boxShape:b2PolygonShape;
var circleShape:b2CircleShape;
var fixtureDef:b2FixtureDef = new b2FixtureDef();
fixtureDef.shape = boxShape;
fixtureDef.friction = 0.3;
// static bodies require zero density
fixtureDef.density = 0;
var quad:Quad;
bodyDef = new b2BodyDef();
bodyDef.type = bodyType;
bodyDef.position.x = x / WORLD_SCALE;
bodyDef.position.y = y / WORLD_SCALE;
// Box
boxShape = new b2PolygonShape();
boxShape.SetAsBox(width / WORLD_SCALE, height / WORLD_SCALE);
fixtureDef.shape = boxShape;
fixtureDef.density = 0;
fixtureDef.friction = 0.5;
fixtureDef.restitution = 0.2;
// create the quads
quad = new Quad(width, height, Math.random() * 0xFFFFFF);
quad.pivotX = 0;
quad.pivotY = 0;
// this is the key line, we pass as a userData the starling.display.Quad
bodyDef.userData = quad;
//
body = m_world.CreateBody(bodyDef);
body.CreateFixture(fixtureDef);
body.SetAngle(rotation * (Math.PI / 180));
_clipPhysique.addChild(bodyDef.userData);
}
The SetAsBox method takes half width and half height as its parameters. I'm guessing your graphics don't match your box2d bodies. So either you will need to make your graphics twice as big or multiply your SetAsBox params by 0.5. Also the body pivot will be in the center of it, so offset your movieclip accordingly depending on its pivot position.
Note that box2d has a debugrenderer which can outline your bodies for you to see what's going on.

b2PrismaticJoint position don't fit with ground

Hello everybody i'm developing a game with cocos2d v1 and i'm using box2d. i'm enabling the retina display. and i'm creating a bucket. i want to move my bucket only in the x axis so i did a b2PrismaticJoint but the problem is that the bucket doesn't fit with the ground. here is my code : `CCSprite *tube = [CCSprite spriteWithFile:#"tube.png"];
tube.position = ccp(SCREEN_WIDTH/2, SCREEN_HEIGHT/2);
[self addChild:tube];
b2BodyDef bucketBodyDef;
bucketBodyDef.type = b2_dynamicBody;
bucketBodyDef.position.Set(tube.contentSize.width/PTM_RATIO, tube.contentSize.height/PTM_RATIO);
bucketBodyDef.userData = tube;
tubeBody = world->CreateBody(&bucketBodyDef);
b2PolygonShape bucketShape;
bucketShape.SetAsBox(tube.contentSize.width/2/PTM_RATIO, tube.contentSize.height/2/PTM_RATIO);
// Create shape definition and add to body
b2FixtureDef bucketShapeDef;
bucketShapeDef.shape = &bucketShape;
bucketShapeDef.density = 10.0f;
bucketShapeDef.friction = 0.4f;
tubeFixture = tubeBody->CreateFixture(&bucketShapeDef);
[self createTubeFixtures];
// Restrict bucket along the x axis
b2PrismaticJointDef jointDef;
b2Vec2 worldAxis(1.0f, 0.0f);
jointDef.collideConnected = true;
jointDef.Initialize(tubeBody, groundBody,
tubeBody->GetWorldCenter(), worldAxis);
world->CreateJoint(&jointDef);`
When i remove the joint all is good..please see the picture attached. thanks!
I did a little mistake that's cost me two days!! and that was on setting the coordinates of the body : b2BodyDef bucketBodyDef;
bucketBodyDef.type = b2_dynamicBody;
**bucketBodyDef.position.Set(tube.contentSize.width/2/PTM_RATIO, tube.contentSize.height/2/PTM_RATIO);**
bucketBodyDef.userData = tube;
tubeBody = world->CreateBody(&bucketBodyDef);

Resources