box2d collision with curves - cocos2d-iphone

Hi all
im working on an ipad app using cocos2d objective c and box2d. my question is in relation to box2d and collisions with curves. basically i have circles within a larger circle arena. the smaller circles collide with each other fine but i want to know how to make them collide with the edges of the larger arena circle correctly so that they dont leave the arena and bounce back in. any ideas on how to approach this problem would be great
cheers

ok i got it working but im not sure if its the correct way to do it
int sides = 50;
float x_coordPREV=([Arena contentSize].width/2)*cos(0.0);
float y_coordPREV=([Arena contentSize].width/2)*sin(0.0);
x_coordPREV += Arena.position.x;
y_coordPREV += Arena.position.y;
b2BodyDef arenaBodyDef;
arenaBodyDef.position.Set(0,0);
b2Body *arenaBody = _world->CreateBody(&arenaBodyDef);
b2PolygonShape arenaBox;
b2FixtureDef arenaShapeDef;
arenaShapeDef.shape = &arenaBox;
for(float angle=0.0f;angle<(2*M_PI);angle+=(2*M_PI)/sides){
float x_coord=([Arena contentSize].width/2-10)*cos(angle);
float y_coord=([Arena contentSize].width/2-10)*sin(angle);
x_coord += Arena.position.x;
y_coord += Arena.position.y;
arenaBox.SetAsEdge(b2Vec2(x_coordPREV/PTM_RATIO,y_coordPREV/PTM_RATIO),b2Vec2( x_coord/PTM_RATIO,y_coord/PTM_RATIO ));
arenaBody->CreateFixture(&arenaShapeDef);
x_coordPREV = x_coord;
y_coordPREV = y_coord;
}
this creates a circle out of 50 sides and appears to be doing what i want. if anyone has a better way please let me know
ty

not sur eif this i what you are looking for but i saw this on a forum:
b2BodyDef edgedef;
edgedef.position.Set(0.f,10.f);
b2Body* edge = world->CreateBody(&edgedef);
b2Vec2 vertices[2];
vertices[0].Set(0.0f, 0.0f);
vertices[1].Set(10.0f, 0.0f);
int32 count = 2;
b2PolygonShape polygon;
polygon.Set(vertices, count);
b2FixtureDef edgefixtureDef;
edgefixtureDef.shape = &polygon;
edge->CreateFixture(&edgefixtureDef);
you could see how you could add more points by sending a larger array

Related

Box2D with SFML object are ovverlapping and going over each other after colliding

I am using Box2D and SFML to create a simple game. However, my object (ball) does not completely lands after it hits the ground. It seems that 50% of the ball has passed through my border, which looks really awkward. Below are some pictures for illustration.
Ball Before:
Ball After hitting the border at the ground:
As you can see, 50% of the ball has dissapeared (most probably due to offsets or what). Anyone know how to fix it?
Below are my code for the object creation:
circ_ = sf::CircleShape(radius);
circ_.setOrigin(sf::Vector2f(size.x/2,size.y/2));
circ_.setFillColor(sf::Color(255, 255, 255, 255));
circ_.setOutlineThickness(1);
circ_.setOutlineColor(sf::Color::Black);
bodyDef_.position = b2Vec2(position.x/PIXEL_PER_METER, position.y/PIXEL_PER_METER);
bodyDef_.type = b2_staticBody;
bodyFixtureDef_.density = 1.0f;
bodyFixtureDef_.friction = 0.3f;
bodyFixtureDef_.restitution = 0.8f;
Where on my SFML code, I have created the Box2D object using:
Ball basketBall(world, basketBallSize, basketBallPos, 0.0, basketBallRadius, false);
Where radius = 32.
Anybody could help me with this? Thanks.
Box2d uses the center of a circle/polygon shape as position while SFML uses the top left corner of the sprite/shape as position, so you need to take that into account when translating between SFML and Box2d positions. Also keep in mind Box2d uses meters instead of pixles and radians instead of degrees.
Just do like that:
#include <cmath> // for M_PI define
Sprite.setPosition(sf::Vector2f(b2BallBody->GetPosition().x * PIXEL_PER_METER - Sprite.getGlobalBounds().width * 0.5f,
b2BallBody->GetPosition().y * PIXEL_PER_METER - Sprite.getGlobalBounds().height * 0.5f));
Sprite.setRotation(b2BallBody->GetAngle() * (float)(180.0 / M_PI));

how to prevent softbody ball from destruction in box2d?

I have used soft body physics in my game to make ball.Now when ball falls down on some platforms which are also b2Bodies or on GrounBody it completely destroyed & it's shape also changed.
I have referred this link : http://www.uchidacoonga.com/2012/04/soft-body-physics-with-box2d-and-cocos2d-part-44/
but when i am trying to change some of values like radius,frequencyHz ,dampingRatio etc then it gives result as per my first image , in which my ball looks so unshaped & destructed .
- (void) createPhysicsObject:(b2World *)world {
// Center is the position of the circle that is in the center (inner circle)
b2Vec2 center = b2Vec2(240/PTM_RATIO, 160/PTM_RATIO);
b2CircleShape circleShape;
circleShape.m_radius = 0.20f;
b2FixtureDef fixtureDef;
fixtureDef.shape = &circleShape;
fixtureDef.density = 0.1;
fixtureDef.restitution = -2;
fixtureDef.friction = 1.0;
// Delta angle to step by
deltaAngle = (2.f * M_PI) / NUM_SEGMENTS;
// Radius of the wheel
float radius = 50;
// Need to store the bodies so that we can refer back
// to it when we connect the joints
bodies = [[NSMutableArray alloc] init];
for (int i = 0; i < NUM_SEGMENTS; i++) {
// Current angle
float theta = deltaAngle*i;
// Calculate x and y based on theta
float x = radius*cosf(theta);
float y = radius*sinf(theta);
// Remember to divide by PTM_RATIO to convert to Box2d coordinate
b2Vec2 circlePosition = b2Vec2(x/PTM_RATIO, y/PTM_RATIO);
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
// Position should be relative to the center
bodyDef.position = (center + circlePosition);
// Create the body and fixture
b2Body *body;
body = world->CreateBody(&bodyDef);
body->CreateFixture(&fixtureDef);
// Add the body to the array to connect joints to it
// later. b2Body is a C++ object, so must wrap it
// in NSValue when inserting into it NSMutableArray
[bodies addObject:[NSValue valueWithPointer:body]];
}
// Circle at the center (inner circle)
b2BodyDef innerCircleBodyDef;
// Make the inner circle larger
circleShape.m_radius = 0.8f;
innerCircleBodyDef.type = b2_dynamicBody;
// Position is at the center
innerCircleBodyDef.position = center;
innerCircleBody = world->CreateBody(&innerCircleBodyDef);
innerCircleBody->CreateFixture(&fixtureDef);
// Connect the joints
b2DistanceJointDef jointDef;
for (int i = 0; i < NUM_SEGMENTS; i++) {
// The neighbor
const int neighborIndex = (i + 1) % NUM_SEGMENTS;
// Get current body and neighbor
b2Body *currentBody = (b2Body*)[[bodies objectAtIndex:i] pointerValue];
b2Body *neighborBody = (b2Body*)[[bodies objectAtIndex:neighborIndex] pointerValue];
// Connect the outer circles to each other
jointDef.Initialize(currentBody, neighborBody,
currentBody->GetWorldCenter(),
neighborBody->GetWorldCenter() );
// Specifies whether the two connected bodies should collide with each other
jointDef.collideConnected = true;
jointDef.frequencyHz = 25.0f;
jointDef.dampingRatio = 0.5f;
world->CreateJoint(&jointDef);
// Connect the center circle with other circles
jointDef.Initialize(currentBody, innerCircleBody, currentBody->GetWorldCenter(), center);
jointDef.collideConnected = true;
jointDef.frequencyHz = 25.0;
jointDef.dampingRatio = 0.5;
world->CreateJoint(&jointDef);
}
}
This code give me the result as shown here.Is there any solution to avoid this situation ???
i want output like this
for that what changes i should made ? any suggestions !! please help.
i would also like to know the reason behind this.
It looks like the triangle fan is reacting with itself. Since you use a triangle fan to create a ball the triangles shouldn't interact, they are connected only. The code on the website you provided is a little bit different. After the first jointDef.Initialize the frequency and dampingRatio are 0.
But some other informations are missing like your NUM_SEGMENTS. Provide complete working code/functions (not the whole application), so someone other could compile and check it also.

How to rotate the physics or dynamic body along an arc path in cocos2d(box2D)

As I am newbie to cocoa2d I am struggling alot to rotate the physics or dynamic body along an arc path.
The way I tried is as follows:
#define COS_ANIMATOR(position, timeCount, speed, waveMagnitude) ((cosf(timeCount * speed) * waveMagnitude) + position)
#define SIN_ANIMATOR(position, timeCount, speed, waveMagnitude) ((sinf(timeCount * speed) * waveMagnitude) + position)
CCSpriteBatchNode *pipe_parent = [CCSpriteBatchNode batchNodeWithFile:#"pipe.png" capacity:100];
CCTexture2D *pipeSpriteTexture_ = [pipe_parent texture];
PhysicsSprite *pipeSprite = [PhysicsSprite spriteWithTexture:pipeSpriteTexture_ rect:CGRectMake(0 ,0 ,55,122)];
//pipe = [CCSprite spriteWithFile:#"pipe.png"
// rect:CGRectMake(0, 0, 55, 122)];
[self addChild:pipeSprite];
// pipe.position = ccp(s.width/2 , 420.0);
b2BodyDef myBodyDef;
myBodyDef.type = b2_staticBody; //this will be a dynamic body
myBodyDef.position.Set(((s.width/2) - 90)/PTM_RATIO, 420.0/PTM_RATIO); //set the starting position
myBodyDef.angle = 0; //set the starting angle
b2Body* staticBody = world->CreateBody(&myBodyDef);
b2PolygonShape boxShape;
boxShape.SetAsBox(1,1);
b2FixtureDef boxFixtureDef;
boxFixtureDef.shape = &boxShape;
boxFixtureDef.density = 1;
boxFixtureDef.userData = pipeSprite;
boxFixtureDef.filter.groupIndex = -1;
staticBody->CreateFixture(&boxFixtureDef);
[pipeSprite setPhysicsBody:staticBody];
-(void) draw
{
//
// IMPORTANT:
// This is only for debug purposes
// It is recommend to disable it
//
[super draw];
const CGPoint newSpritePosition = ccp(COS_ANIMATOR(150, mTimeCounter, 0.05,50), SIN_ANIMATOR(400, mTimeCounter, -0.05, 50));
pipeSprite.position = newSpritePosition;
ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
kmGLPushMatrix();
world->DrawDebugData();
kmGLPopMatrix();
}
on following this approach my sprite rotating in circular motion instead of rotating in an arc path.
Please give your ideas or suggestions.
Thanks all
I'm not entirely sure what it is you are looking to accomplish when you talk about rotating in an arc path. I only see you setting a position, not a rotation, so are you just wanting to set a position, or a rotation, or both? Your position code looks like you are trying to achieve a circular (or elliptical) path because you are using the sine and cosine in the x,y position.
If you're looking to move a sprite along a sine curve, I did that today and it took a bit of trial and error. I had some variables for the amplitude and period, and from there I traced out a nice sine curve movement in the sprite's update: method.
CGPoint initialPosition; // set this to the sprite's initial position
float amplitude; // in points
float period; // in points
float y, x = initialPosition.x;
-(void) update:(ccTime)dt
{
x += dt * 100; // speed of movement across the screen. Picked by trial and error.
y = initalPosition.y + amplitude * sinf((x - initialPosition.x)/period);
sprite.position = ccp(x,y);
sprite.rotation = cosf((x - initialPosition.x)/period); // optional if you want to rotate along the path as well
}
Don't know if this is anything you are looking for but it might give you some ideas.

Cocos2D+Box2D: Stack bodies that doesn´t fall?

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:

How to move a sprite at a certain angle with a joystick

Hi I have finally made a working joystick in cocos2d. I am able to rotate a sprite to the exact angle that the joystick thumb, or cap, is 'pointing'. However, I am unable to move the sprite in that same direction. Is there an easy way to move the sprite with the way I have the rotating code set up? Also is there a way to keep it moving if your thumb is still pressed, but not moving the joystick?. PS this code is all within the TouchesMoved method. PPS. the cap is the thumb, the pad is the joystick background, and the Sprite2 is the sprite that I want to move. (95, 95) is the center of the pad sprite.
if(capSprite.position.x>=padSprite.position.x){
id a3 = [CCFlipX actionWithFlipX:NO];
[sprite2 runAction:a3];
}
if(capSprite.position.x<=padSprite.position.x){
id a4 = [CCFlipX actionWithFlipX:YES];
[sprite2 runAction:a4];
}
CGPoint pos1 = ccp(95, 95);
CGPoint pos2 = ccp(capSprite.position.x, capSprite.position.y);
int offX = pos2.x-pos1.x;
int offY = pos2.y-pos1.y;
float angleRadians = atanf((float)offY/(float)offX);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float theAngle = -1 * angleDegrees;
sprite2.rotation = theAngle;
I'm not familiar with cocos2d but I had a quick look at the documentation and this sample might be of use to you:
if keys[key.UP]:
self.target.acceleration = (200 * rotation_x, 200 * rotation_y)
I had written a long explanation answering your second question but I believe this "self.target.acceleration" solves that too. You can read more at the cocos2d API documentation.
What I generally do is get the angle, convert it to a CGPoint with ccpForAngle(float) and then multiply the CGPoint by a value:
float angle = whatever;
CGPoint anglePoint = ccpForAngle(angle);
// You will need to play with the mult value
angle = ccpMult(angle, 2.5);
// This also works with box2D or probably Chipmunk.
sprite.position = angle;