Detecting collision of two bodies, each one has different shape - iphone

I want to detect collision between two bodies, one body has circle shape and another one has convex body (by using vertexes and number of vertexes), and I use contact listener class to detect collision between bodies. I tried detect collision between two circle shapes and it succeeded, but when I tried to detect collision between two bodies (one has convex shape and another one has circle shape) and it failed! even I use tags to identify these bodies.
How can I detect two bodies which have two different shapes (circle and convex)?
ContactListener.h code:
#import "Box2D.h"
class ContactListener : public b2ContactListener
{
private:
void BeginContact(b2Contact* contact);
void EndContact(b2Contact* contact);
};
ContactListener.mm code:
#import "ContactListener.h"
#import "SimpleAudioEngine.h"
#import "cocos2d.h"
void ContactListener::BeginContact(b2Contact* contact) {
b2Body* bodyA = contact->GetFixtureA()->GetBody();
b2Body* bodyB = contact->GetFixtureB()->GetBody();
CCSprite* spriteA = (CCSprite*)bodyA->GetUserData();
CCSprite* spriteB = (CCSprite*)bodyB->GetUserData();
if (spriteA != NULL && spriteB != NULL) {
if (spriteA.tag == 1 && spriteB.tag == 50) { // this is work (two shapes are circles
[[SimpleAudioEngine sharedEngine] playEffect:#"Pin.wav"];
NSLog(#"Contact With Pin is Beginning");
}
if (spriteA.tag == 1 && spriteB.tag == 51) { // this is not work (one is circle shape and another one is convex shape)
[[SimpleAudioEngine sharedEngine] playEffect:#"Jump.wav"];
NSLog(#"Contact With Barrier is Beginning");
}
}
}
void ContactListener::EndContact(b2Contact* contact) {
b2Body* bodyA = contact->GetFixtureA()->GetBody();
b2Body* bodyB = contact->GetFixtureB()->GetBody();
CCSprite* spriteA = (CCSprite*)bodyA->GetUserData();
CCSprite* spriteB = (CCSprite*)bodyB->GetUserData();
if (spriteA != NULL && spriteB != NULL) {
}
}
Tags on above code:
tag of ball (main sprite of game) shape is 1
tag of circle shape is 50
tag of convex shape is 51
Edit:
This is code of object's bodies creation:
#define pinSpriteTag 50
#define barrierSpriteTag 51
#define ballSpriteTag 1
// Creating ball of game (has b2CircleShape)
-(void) createBallOfGameWithPositionX:(int)x yPosition:(int)y radius:(float)radius {
// Put ball on screen
ballOfGameSprite = [CCSprite spriteWithFile:#"GameBall-1-ipad.png"];
ballOfGameSprite.position = ccp(x, y);
[self addChild:ballOfGameSprite z:1 tag: ballSpriteTag];
// Create body of ball
b2BodyDef ballOfGameBodyDef;
ballOfGameBodyDef.type = b2_staticBody;
ballOfGameBodyDef.position.Set(ballOfGameSprite.position.x/PTM_RATIO, ballOfGameSprite.position.y/PTM_RATIO);
ballOfGameBodyDef.userData = ballOfGameSprite;
ballOfGameBody = world->CreateBody(&ballOfGameBodyDef);
// Create Physics properties of ball
b2CircleShape ballOfGameShape;
ballOfGameShape.m_radius = radius/PTM_RATIO;
// Create fixture of ball
b2FixtureDef ballOfGameFixtureDef;
ballOfGameFixtureDef.shape = &ballOfGameShape;
ballOfGameFixtureDef.density = 0.9f;
ballOfGameFixtureDef.friction = 1.0f;
ballOfGameFixtureDef.restitution = 0.9f;
ballOfGameBody->CreateFixture(&ballOfGameFixtureDef);
}
// Creating pin of game (has b2CircleShape)
-(void) createNormalPinOnScreenWithPositionX:(int)x yPosition:(int)y radius:(float)radius {
// Put ball on screen
CCSprite *pin = [CCSprite spriteWithFile:#"GamePinNormal-ipad.png"];
pin.position = ccp(x, y);
[self addChild:pin z:2 tag:pinSpriteTag];
// Create body of ball
b2BodyDef pinBodyDef;
pinBodyDef.type = b2_staticBody;
pinBodyDef.position.Set(pin.position.x/PTM_RATIO, pin.position.y/PTM_RATIO);
pinBodyDef.userData = pin;
b2Body *pinBody = world->CreateBody(&pinBodyDef);
// Create Physics properties of ball
b2CircleShape pinShape;
pinShape.m_radius = radius/PTM_RATIO;
// Create fixture of ball
b2FixtureDef pinFixtureDef;
pinFixtureDef.shape = &pinShape;
pinFixtureDef.density = 0.9f;
pinFixtureDef.friction = 1.0f;
pinFixtureDef.restitution = 0.85f;
pinBody->CreateFixture(&pinFixtureDef);
}
// Creating Barrier of game (has b2PolygonShape)
-(void) createBarrierOnScreenPositionX:(int)x yPosition:(int)y imageName:(NSString *)imageName verts:(b2Vec2*)verts verNum:(int)verNum {
CCSprite *BarrierOfGameSprite = [CCSprite spriteWithFile:imageName];
BarrierOfGameSprite.position = ccp(x, y);
[self addChild:BarrierOfGameSprite z:1 tag:barrierSpriteTag];
b2BodyDef BarrierOfGameBodyDef;
BarrierOfGameBodyDef.type = b2_staticBody;
BarrierOfGameBodyDef.position.Set(BarrierOfGameSprite.position.x/PTM_RATIO, BarrierOfGameSprite.position.y/PTM_RATIO);
BarrierOfGameBodyDef.userData = BarrierOfGameSprite;
b2Body *BarrierOfGameBody = world->CreateBody(&BarrierOfGameBodyDef);
b2PolygonShape BarrierOfGameShape;
BarrierOfGameShape.Set(verts, verNum);
b2FixtureDef BarrierOfGameFixtureDef;
BarrierOfGameFixtureDef.shape = &BarrierOfGameShape;
BarrierOfGameFixtureDef.density = 0.9f;
BarrierOfGameFixtureDef.friction = 1.0f;
BarrierOfGameFixtureDef.restitution = 0.0f;
BarrierOfGameBody->CreateFixture(&BarrierOfGameFixtureDef);
}

Do not detect the collision between two shape.
The best way is to set the object as the userData of the body.
#implemention RigidBody
-(id)init{
...
self.body->userData = self;
}
And then compare the class and address
void beginContact(b2contact contact){
RigidBody *A = (RigidBody*)contact->GetFixtureA()->GetBody()->GetUserData();
if([A isKindOfClass:[RigidBody class]]){
}
// Or
if(self == A){
}
I hope it 's helpful for you.

Related

Multiple sprites with same SKPhysics body object

I am building an airport simulation game using sprite kit. My layout for the game states intact before adding SKPhysics body and once SKPhysicsbody is set for nodes, my sprite nodes goes wary.
This is what I am adding to scene without SKPhysicsBody. Imagine a airport with many gates and flights standing next to the gates. That is what I am trying to achieve with below code.
#implementation MyScene
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
allPlanes = [[NSMutableArray alloc]init];
// setting gravity to 0
[[self physicsWorld] setGravity:CGVectorMake(0, 0)];
[[self physicsWorld] setContactDelegate:self];
[self setBackgroundColor:[UIColor whiteColor]];
// Below method will provide runway and other static objects that can be seen in an airport
[self setupAirport];
/* This is where I am setting up by plane sprites.This method will provide a node which is added to the scene. As you can notice, the sprites are added at specific coordinates until they fill the screen. Imagine three or four gates with flights standing by those gates. That is what I am trying to achieve with below while loop */
int xval = 20;
while (xval < kScreenWidth)
{
[self setupFlightAtPoint:xval];
xval = xval + 60;
}
}
return self;
}
Now code for methods [self setupFlightAtPoint:xPos]
-(void) setupFlightAtPoint:(CGFloat ) xPos
{
// Below code will provide a static gate like object.gateNode is of type Gate class which is a subclass of SKNode
gateNode = [[Gate node] newGate];
[gateNode setPosition:CGPointMake(xPos, kScreenHeight * 0.37)];
[self addChild:gateNode];
// Below code provide plane node and positions it near the gate object.Plane is subclass of SKNode
Plane *plane = [[Plane alloc]init];
imageNode = [plane newPlane];
imageNode.planeIdentifier = xPos;
[imageNode setPosition:CGPointMake(gateNode.frame.origin.x + 12, gateNode.frame.origin.y+15)];
[allPlanes addObject:imageNode];
[self addChild:imageNode];
}
Plane object method
-(instancetype) newPlane
{
[self setScale:0.10];
SKSpriteNode *spriteNode = [SKSpriteNode spriteNodeWithImageNamed:#"plane.png"];
[self addChild:spriteNode];
return self;
}
Till now everything looks fine.Please see attached image called scene1 to see what I see with above code.
Now my problem begins here when I am trying to set physics body to my plane sprites. In my "newPlane" method, I am adding below code
-(instancetype) newPlane
{
[self setScale:0.10];
SKSpriteNode *spriteNode = [SKSpriteNode spriteNodeWithImageNamed:#"plane.png"];
[self addChild:spriteNode];
SKPhysicsBody *planePhysics = [SKPhysicsBody bodyWithRectangleOfSize:spriteNode.frame.size];
[spriteNode setPhysicsBody:planePhysics];
[[spriteNode physicsBody] setAffectedByGravity:NO];
return self;
}
After setting Physicsbodies, my scene looks like this
only one plane sprite is seen in my scene now and I am not able to figure out why?
Try initializing and assigning the physics body before adding the sprite as child:
-(instancetype) newPlane
{
[self setScale:0.10];
SKSpriteNode *spriteNode = [SKSpriteNode spriteNodeWithImageNamed:#"plane.png"];
spriteNode.position = CGPointMake(100, 200);
SKPhysicsBody *planePhysics = [SKPhysicsBody bodyWithRectangleOfSize:spriteNode.frame.size];
spriteNode.physicsBody = planePhysics;
spriteNode.physicsBody.affectedByGravity = NO;
[self addChild:spriteNode];
return self;
}
I also converted the code to use dot notation, I find this easier to type and read.

cocos2D and Box2D : How to get exact touched sprite?

I am trying to move sprite on touch moved. but when two sprites is there i am geting touch of two sprites. that's why sprites are not moving properly.
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
{
if (_mouseJoint != NULL) return;
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
for(int i=0;i<[mutArrFixtures count];i++)
{
b2Fixture *fixture;
[[mutArrFixtures objectAtIndex:i] getValue:&fixture];
if (fixture->TestPoint(locationWorld)){
for(int j=0; j<[mutArrPaddleBody count]; j++)
{
b2Body *body;
[[mutArrPaddleBody objectAtIndex:j] getValue:&body];
b2MouseJointDef md;
if(body == fixture->GetBody())
{
md.bodyA = _groundBody;
md.bodyB = body;
md.target = locationWorld;
md.collideConnected = true;
md.maxForce = 1000.0f * body->GetMass();
_mouseJoint = (b2MouseJoint *)_world->CreateJoint(&md);
body->SetAwake(true);
}
}
}
}
}
i have an array of b2Fixture mutArrFixtures and also an array mutArrPaddleBody of b2body. but in this if i touch on second sprite i get touch on first sprite and second sprite.. two sprites positions are same...
In touch function, check tag of the sprite. If that is ur right sprite then move. Show me some code that u used for touch movement.
.......
Replace these code with next one
b2Body *body;
[[mutArrPaddleBody objectAtIndex:j] getValue:&body];
b2MouseJointDef md;
if(body == fixture->GetBody())
with
b2Body* body = fixture->GetBody();
CCSprite *sprite = (CCSprite*)body->GetUserData();
if( sprite && sprite.tag == kTagHero)
{
}
Make sure u added tag kTagHero for ur moving sprite.
....
enum gameTag {
kTagHero = 1001
};
and assign sprite.tag = kTagHero
......

Trying to implement radial gravity with Cocos2d 2.X

I am trying to learn how to implement radial gravity to specific objects and I was using the tutorial on (http://www.vellios.com/2010/06/11/radial-gravity-w-box2d-source/), but this tutorial is written an older version of Cocos2d. I have tried to fixed it as much as I could. If someone can point me in the right direction, i would really appreciate. Here is what I have so far. I commented the places that I am having problems with. Thank you.
HelloWorldLayer.h
#import <GameKit/GameKit.h>
// When you import this file, you import all the cocos2d classes
#import "cocos2d.h"
#import "Box2D.h"
#import "GLES-Render.h"
#define PTM_RATIO 32
// HelloWorldLayer
#interface HelloWorldLayer : CCLayer <GKAchievementViewControllerDelegate, GKLeaderboardViewControllerDelegate>
{
b2World* world; // strong ref
GLESDebugDraw *m_debugDraw; // strong ref
}
// returns a CCScene that contains the HelloWorldLayer as the only child
+(CCScene *) scene;
#end
HelloWorldLayer.mm
// Import the interfaces
#import "HelloWorldLayer.h"
// Needed to obtain the Navigation Controller
#import "AppDelegate.h"
#define PTM_RATIO 32
#define kRADIAL_GRAVITY_FORCE 250.0f
enum {
kTagParentNode = 1,
kTagTileMap = 1,
kTagSpriteSheet = 1,
kTagAnimation1 = 1,
};
#pragma mark - HelloWorldLayer
#interface HelloWorldLayer()
-(void) initPhysics;
-(void) addNewSpriteAtPosition:(CGPoint)p;
-(void) createMenu;
#end
#implementation HelloWorldLayer
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
-(id) init
{
if( (self=[super init])) {
// enable events
self.isTouchEnabled = YES;
self.isAccelerometerEnabled = YES;
CGSize screenSize = [CCDirector sharedDirector].winSize;
CCLOG(#"Screen width %0.2f screen height %0.2f",screenSize.width,screenSize.height);
b2Vec2 gravity;
gravity.Set(0.0f, -10.0f);
// This will speed up the physics simulation
bool doSleep = true;
// Construct a world object, which will hold and simulate the rigid bodies.
world = new b2World(gravity);
world->SetAllowSleeping(doSleep);
world->SetContinuousPhysics(true);
//Set up sprite
CCSprite *sheet = [CCSprite spriteWithFile:#"blocks.png"];
[self addChild:sheet z:0 tag:kTagSpriteSheet];
[self addNewSpriteAtPosition:ccp(screenSize.width/2, screenSize.height/2)];
//ERROR Use of undeclared identifier 'CCLabel'
//ERROR Use of undeclared identifier 'label'
CCLabel *label = [CCLabel labelWithString:#"Tap Screen" fontName:#"Marker Felt" fontSize:32];
// ERROR Use of undeclared identifier 'label'
[self addChild:label z:0];
//ERROR Use of undeclared identifier 'label'
[label setColor:ccc3(0,0,255)];
//ERROR Use of undeclared identifier 'label'
label.position = ccp( screenSize.width/2, screenSize.height-50);
// Create our static "Planet" - Nick
b2CircleShape shape;
shape.m_radius = 1.0f;
shape.m_p.Set(8.0f, 8.0f);
b2FixtureDef fd;
fd.shape = &shape;
//ERROR Use of undeclared identifier 'planet'
planet = groundBody->CreateFixture(&fd);
// End Create Planet - Nick
[self schedule: #selector(tick:)];
// init physics
[self initPhysics];
[self scheduleUpdate];
}
return self;
}
-(void) dealloc
{
delete world;
world = NULL;
delete m_debugDraw;
m_debugDraw = NULL;
[super dealloc];
}
-(void) createMenu
{
}
-(void) initPhysics
{
CGSize s = [[CCDirector sharedDirector] winSize];
b2Vec2 gravity;
gravity.Set(0.0f, -10.0f);
world = new b2World(gravity);
// Do we want to let bodies sleep?
world->SetAllowSleeping(true);
world->SetContinuousPhysics(true);
// Debug Draw functions
m_debugDraw = new GLESDebugDraw( PTM_RATIO );
world->SetDebugDraw(m_debugDraw);
uint32 flags = 0;
flags += b2Draw::e_shapeBit;
// flags += b2Draw::e_jointBit;
// flags += b2Draw::e_aabbBit;
// flags += b2Draw::e_pairBit;
// flags += b2Draw::e_centerOfMassBit;
m_debugDraw->SetFlags(flags);
// 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(s.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);
// top
groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO));
groundBody->CreateFixture(&groundBox,0);
// left
groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(0,0));
groundBody->CreateFixture(&groundBox,0);
// right
groundBox.Set(b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);
}
-(void) draw
{
//
// IMPORTANT:
// This is only for debug purposes
// It is recommend to disable it
//
[super draw];
// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
// Needed states: GL_VERTEX_ARRAY,
// Unneeded states: GL_TEXTURE_2D, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
glDisable(GL_TEXTURE_2D);
glDisable(GL_COLOR_BUFFER_BIT);
world->DrawDebugData();
}
-(void) addNewSpriteAtPosition:(CGPoint)p
{
CCLOG(#"Add sprite %0.2f x %02.f",p.x,p.y);
CCSprite *sheet = (CCSprite*) [self getChildByTag:kTagSpriteSheet];
int idx = (CCRANDOM_0_1() > .5 ? 0:1);
int idy = (CCRANDOM_0_1() > .5 ? 0:1);
//ERROR Cannot initialize a parameter of type 'CCTexture2D *' with an lvalue of type 'CCSprite *'
CCSprite *sprite = [CCSprite spriteWithTexture:sheet rect:CGRectMake(32 * idx,32 * idy,32,32)];
[sheet addChild:sprite];
sprite.position = ccp( p.x, p.y);
// Define the dynamic body.
//Set up a 1m squared box in the physics world
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
bodyDef.userData = sprite;
b2Body *body = world->CreateBody(&bodyDef);
// Define another box shape for our dynamic body.
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(.5f, .5f);//These are mid points for our 1m box
// Define the dynamic body fixture.
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
body->CreateFixture(&fixtureDef);
}
-(void) update: (ccTime) dt
{
//It is recommended that a fixed time step is used with Box2D for stability
//of the simulation, however, we are using a variable time step here.
//You need to make an informed choice, the following URL is useful
//http://gafferongames.com/game-physics/fix-your-timestep/
int32 velocityIterations = 8;
int32 positionIterations = 1;
// Instruct the world to perform a single step of simulation. It is
// generally best to keep the time step and iterations fixed.
world->Step(dt, velocityIterations, positionIterations);
//Iterate over the bodies in the physics world
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
{
b2Body* ground = planet->GetBody();
b2CircleShape* circle = (b2CircleShape*)planet->GetShape();
// Get position of our "Planet" - Nick
b2Vec2 center = ground->GetWorldPoint(circle->m_p);
// Get position of our current body in the iteration - Nick
b2Vec2 position = b->GetPosition();
// Get the distance between the two objects. - Nick
b2Vec2 d = center - position;
// The further away the objects are, the weaker the gravitational force is - Nick
float force = kRADIAL_GRAVITY_FORCE / d.LengthSquared(); // 150 can be changed to adjust the amount of force - Nick
d.Normalize();
b2Vec2 F = force * d;
// Finally apply a force on the body in the direction of the "Planet" - Nick
b->ApplyForce(F, position);
if (b->GetUserData() != NULL) {
//Synchronize the AtlasSprites position and rotation with the corresponding body
CCSprite *myActor = (CCSprite*)b->GetUserData();
myActor.position = CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
}
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//Add a new body/atlas sprite at the touched location
for( UITouch *touch in touches ) {
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
[self addNewSpriteAtPosition:location];
}
}
- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration
{
static float prevX=0, prevY=0;
//#define kFilterFactor 0.05f
#define kFilterFactor 1.0f // don't use filter. the code is here just as an example
float accelX = (float) acceleration.x * kFilterFactor + (1- kFilterFactor)*prevX;
float accelY = (float) acceleration.y * kFilterFactor + (1- kFilterFactor)*prevY;
prevX = accelX;
prevY = accelY;
// accelerometer values are in "Portrait" mode. Change them to Landscape left
// multiply the gravity by 10
b2Vec2 gravity( -accelY * 10, accelX * 10);
world->SetGravity( gravity );
}
#pragma mark GameKit delegate
-(void) achievementViewControllerDidFinish:(GKAchievementViewController *)viewController
{
AppController *app = (AppController*) [[UIApplication sharedApplication] delegate];
[[app navController] dismissModalViewControllerAnimated:YES];
}
-(void) leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController
{
AppController *app = (AppController*) [[UIApplication sharedApplication] delegate];
[[app navController] dismissModalViewControllerAnimated:YES];
}
#end

Problem to detect diamond shape in box2d

I make a simple game.
It has many diamond image and one ball. when ball touch with diamond shape then collision occur. in my application when ball touch on the edge then collision working correctly but when ball touch on the corner then collision is not working.
Code is hear..
- (id)init {
if ((self=[super init])) {
CGSize winSize = [CCDirector sharedDirector].winSize;
self.isTouchEnabled = YES;
self.isAccelerometerEnabled=YES;
// Create a world
b2Vec2 gravity = b2Vec2(0.0f, 0.0f);
bool doSleep = true;
_world = new b2World(gravity, doSleep);
// Create edges around the entire screen
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0,0);
_groundBody = _world->CreateBody(&groundBodyDef);
b2PolygonShape groundBox;
b2FixtureDef groundBoxDef;
groundBoxDef.shape = &groundBox;
groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(winSize.width/PTM_RATIO, 0));
_bottomFixture = _groundBody->CreateFixture(&groundBoxDef);
groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(0, winSize.height/PTM_RATIO));
_groundBody->CreateFixture(&groundBoxDef);
groundBox.SetAsEdge(b2Vec2(0, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO));
_groundBody->CreateFixture(&groundBoxDef);
groundBox.SetAsEdge(b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO, 0));
_groundBody->CreateFixture(&groundBoxDef);
// Create sprite and add it to the layer
CCSprite *ball = [CCSprite spriteWithFile:#"ball1.png" rect:CGRectMake(0, 0, 16,16)];
// ball.position = ccp(180, 400);
ball.tag = 1;
// Create ball body
b2BodyDef ballBodyDef;
ballBodyDef.type = b2_dynamicBody;
ballBodyDef.position.Set(180/PTM_RATIO, 450/PTM_RATIO);
ballBodyDef.userData = ball;
ballBody = _world->CreateBody(&ballBodyDef);
// Create circle shape
b2CircleShape circle;
circle.m_radius = 16/PTM_RATIO;
//circle.m_radius = 50/PTM_RATIO;
// Create shape definition and add to body
b2FixtureDef ballShapeDef;
ballShapeDef.shape = &circle;
ballShapeDef.density = 1.0f;
ballShapeDef.friction = 0.0f; // We don't want the ball to have friction!
ballShapeDef.restitution = 0.0f;
_ballFixture = ballBody->CreateFixture(&ballShapeDef);
// Give shape initial impulse...
b2Vec2 force = b2Vec2(0, 0);
ballBody->ApplyLinearImpulse(force, ballBodyDef.position);
for(int i = 0; i < 5; i++)
{
static int padding=25;
CCSprite *block = [CCSprite spriteWithFile:#"diamond2.png"];
int xOffset = padding+block.contentSize.width/5+((block.contentSize.width+padding)*i);
block.position = ccp(xOffset, 250);
block.tag = 2;
[self addChild:block];
// Create block body
b2BodyDef blockBodyDef;
// blockBodyDef.type = b2_dynamicBody;
blockBodyDef.position.Set(xOffset/PTM_RATIO, 400/PTM_RATIO);
blockBodyDef.userData = block;
b2Body *blockBody = _world->CreateBody(&blockBodyDef);
// Create block shape
b2PolygonShape blockShape;
blockShape.SetAsBox(block.contentSize.width/PTM_RATIO/8,
block.contentSize.height/PTM_RATIO/8
);
// Create shape definition and add to body
b2FixtureDef blockshapeDef;
blockshapeDef.shape = &blockShape;
blockshapeDef.density = 0.0;
blockshapeDef.friction = 10.0;
blockshapeDef.restitution = 0.1f;
blockBody->CreateFixture(&blockshapeDef);
}
[self addChild:ball];
// Create contact listener
_contactListener = new MyContactListener();
_world->SetContactListener(_contactListener);
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:#"background-music-aac.caf"];
[self schedule:#selector(tick:)];
}
return self;
}
- (void)tick:(ccTime) dt {
// bool blockFound = false;
_world->Step(dt, 10, 10);
for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *sprite = (CCSprite *)b->GetUserData();
if (sprite.tag == 1) {
static int maxSpeed = 20;
b2Vec2 velocity = b->GetLinearVelocity();
float32 speed = velocity.Length();
// When the ball is greater than max speed, slow it down by
// applying linear damping. This is better for the simulation
// than raw adjustment of the velocity.
if (speed > maxSpeed) {
b->SetLinearDamping(0.2);
} else if (speed < maxSpeed) {
b->SetLinearDamping(0.0);
}
}
sprite.position = ccp(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
sprite.rotation = 1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
}
Plz help me for detect correct collsion detection near corner of the diamond shape....
I'm not sure i understood but it seems you are not making a diamond, you are making a square/box:
blockShape.SetAsBox(block.contentSize.width/PTM_RATIO/8,block.contentSize.height/PTM_RATIO/8);
maybe that's why you're saying collision is not working.
If your body is a square and your sprite is a diamond there are three options:
Or diamond has equal width and height and it's only necessary to rotate the square. Should be no problem with collision this way.
Or other shapes collide on the (invisible)corner of square when is not supposed to be there (when sprite/diamond fits inside square and square has no rotation or diamond has width != height needing a customized shape)
Or other shapes are not colliding with diamond sprite corner (when square is smaller and fits inside diamond sprite).
There are other methods to create customized shapes like:
void b2PolygonShape::Set(const b2Vec2* vertices, int32 count)
void b2PolygonShape::SetAsEdge(const b2Vec2& v1, const b2Vec2& v2)

How to set the position of a sprite within a box2d body?

Basically I have 2 polygons for my body. When I add a sprite for userData, the position of the texture isn't where I want it to be. What I want to do is adjust the position of the texture within the body. Here's the code sample of where I am setting this:
CCSpriteSheet *sheet = (CCSpriteSheet*) [self getChildByTag:kTagSpriteSheet];
CCSprite *pigeonSprite = [CCSprite spriteWithSpriteSheet:sheet rect:CGRectMake(0,0,40,32)];
[sheet addChild:pigeonSprite z:0 tag:kPigeonSprite];
pigeonSprite.position = ccp( p.x, p.y);
bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
bodyDef.userData = sprite;
b2Body *body = world->CreateBody(&bodyDef);
b2CircleShape dynamicCircle;
dynamicCircle.m_radius = .25f;
dynamicCircle.m_p.Set(0.0f, 1.0f);
// Define the dynamic body fixture.
b2FixtureDef circleDef;
circleDef.shape = &dynamicCircle;
circleDef.density = 1.0f;
circleDef.friction = 0.3f;
body->CreateFixture(&circleDef);
b2Vec2 vertices[3];
vertices[0].Set(-0.5f, 0.0f);
vertices[1].Set(0.5f, 0.0f);
vertices[2].Set(0.0f, 1.0f);
b2PolygonShape triangle;
triangle.Set(vertices, 3);
b2FixtureDef triangleDef1;
triangleDef1.shape = &triangle;
triangleDef1.density = 1.0f;
triangleDef1.friction = 0.3f;
body->CreateFixture(&triangleDef1);
I'm not that familiar with objective-c but I'll give it a try.
All I can see is that you are storing a pointer to the sprite object in the body's user data and then leaving it there. If you want the body's position to be transferred to the sprite you need to update it every frame.
In C++ this would look something like this.
// To be called each time physics should be updated.
void physicsStep(float32 timeStep, int32 velocityIterations, int32 positionIterations) {
// This is the usual update routine.
world.Step(timeStep, velocityIterations, positionIterations);
world.ClearForces();
// SpriteClass can be replaced with any class you favor.
// Assume there is a known pointer to the b2Body. Otherwise you'll have to get that,
// or iterate over all bodies in the world.
SpriteClass *sprite = (SpriteClass*)body->GetUserData();
// Once you have the pointer you can transfer all the data.
sprite.position = body->GetPosition();
sprite.angle = body->GetAngle();
// ... and so on
}
User data is just an arbitrary storage space in the b2Body and Box2D has no idea about what you decide to store there.
To move sprite with body then You have to set the sprite position accotring to body
in your update method
like this in COCOS2D-X
Here
sprite = static_cast<CCSprite*>body->GetUserData();
sprite->setPosition(vec2(body->GetPosition().x*PTM_RATIO, body->GetPosition().y*PTM_RATIO));
sprite->setRotation(-CC_Radian_to_Degree(body->GetAngle));
PTM_RATIO = 32;