I'm using cocos2d-x 2.0.3 with Box2d 2.2.1 and has first example I've introduced a dynamic body (a boat defined with PhysicsEditor) in a frame. Applying a gravity the behaviour expected is that the boat collide with the frame but instead it go through.
Here is the definition of world and bodies:
// create world
b2Vec2 gravity;
gravity.Set(0.1f, -0.0f);
bool doSleep = true;
world = new b2World(gravity);
world->SetAllowSleeping(doSleep);
world->SetContinuousPhysics(true);
// Debug Draw functions
m_debugDraw = new GLESDebugDraw( PTM_RATIO * CCDirector::sharedDirector()->getContentScaleFactor());
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);
// for the screenBorder body we'll need these values
CCSize screenSize = size;
float widthInMeters = screenSize.width / PTM_RATIO;
float heightInMeters = screenSize.height / PTM_RATIO;
b2Vec2 lowerLeftCorner = b2Vec2(- widthInMeters / 2, 0.0);
b2Vec2 lowerRightCorner = b2Vec2(widthInMeters / 2, 0.0);
b2Vec2 upperLeftCorner = b2Vec2(- widthInMeters / 2, heightInMeters);
b2Vec2 upperRightCorner = b2Vec2(widthInMeters/2, heightInMeters);
// Define the static container body, which will provide the collisions at screen borders.
b2BodyDef screenBorderDef;
screenBorderDef.position.Set(0, 0);
screenBorderDef.type = b2_staticBody;
b2Body* screenBorderBody = world->CreateBody(&screenBorderDef);
b2EdgeShape screenBorderShape;
// Create fixtures for the four borders (the border shape is re-used)
screenBorderShape.Set(lowerLeftCorner, lowerRightCorner);
screenBorderBody->CreateFixture(&screenBorderShape, 0);
screenBorderShape.Set(lowerRightCorner, upperRightCorner);
screenBorderBody->CreateFixture(&screenBorderShape, 0);
screenBorderShape.Set(upperRightCorner, upperLeftCorner);
screenBorderBody->CreateFixture(&screenBorderShape, 0);
screenBorderShape.Set(upperLeftCorner, lowerLeftCorner);
screenBorderBody->CreateFixture(&screenBorderShape, 0);
// add sail boat sprite
CCSprite *sailBoatSprite = CCSprite::create("SailBoat.png");
addChild(sailBoatSprite, -1, kSailingBoat);
sailBoatSprite->setAnchorPoint(ccp(0.5, 0.5));
sailBoatSprite->setPosition(ccp(0.0, 128.0));
// add sail boat body
GB2ShapeCache *shapeCache = GB2ShapeCache::sharedGB2ShapeCache();
shapeCache->addShapesWithFile("SailBoat.plist");
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(0.0/PTM_RATIO, 128.0/PTM_RATIO);
bodyDef.userData = sailBoatSprite;
b2Body *body = world->CreateBody(&bodyDef);
shapeCache->addFixturesToBody(body, "SailBoat");
sailBoatSprite->setAnchorPoint(GB2ShapeCache::sharedGB2ShapeCache()->anchorPointForShape("SailBoat"));
this->schedule(schedule_selector(SailingFieldNode::tick));
Here is the updates method:
void SailingFieldNode::tick(float dt)
{
int32 velocityIterations = 8;
int32 positionIterations = 1;
world->Step(0.01, velocityIterations, positionIterations);
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetUserData() != NULL) {
CCSprite *myActor = (CCSprite*)b->GetUserData();
myActor->setPosition(ccp( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO));
myActor->setRotation(-1 * CC_RADIANS_TO_DEGREES(b->GetAngle()));
}
}
}
void SailingFieldNode::draw()
{
CCLayer::draw();
ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position);
kmGLPushMatrix();
world->DrawDebugData();
kmGLPopMatrix();
CHECK_GL_ERROR_DEBUG();
}
As you can see in the following screenshot the boat is in the frame then there should be the collision:
Any help?
Thanks in advance.
Jean
Problem solved, the issue was that in PhysicsEditor I haven't set the dynamic body in a category (with the flag). In my code I don't use them yet but probably you must set it in one category to have collisions (I've set my body in bit_0).
Jean
Related
My dynamic body is not falling down after setting the world. It is not following the gravity. Even I apply force on the body it isn't work.
b2Vec2 gravity(0.0f, -9.8f);
b2World world(gravity);
//PineCone
class PineCone
{
private:
//Surface box
SDL_Rect box;
//Real position
float rX, rY;
//Velocity
float xVel, yVel;
//Physics world
b2World* world;
//Body
b2Body* pBodyPineCone;
public:
//Specify
void specify(int w, int h, SDL_Surface* source, SDL_Surface* dest, b2World* world);
//Input
void handle_input();
//Motion
void updatepos();
//void checkStanding(SDL_Rect env[], int N_SOLIDS);
//Render
void show();
};
void PineCone::specify(int w, int h, SDL_Surface* source, SDL_Surface* dest, b2World* world)
{
//Source
pPineCone = source;
//Destination
pScreen = dest;
// Define the dynamic pinecone. We set its position and call the body factory.
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
// Define a ball shape for our dynamic body.
b2CircleShape dynamicPineCone;
dynamicPineCone.m_p.Set(0, 0); //position, relative to body position
dynamicPineCone.m_radius = 0.5; //radius
// Define the dynamic body fixture.
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicPineCone;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
// Add the shape to the body.
bodyDef.position.Set(0, 20);
pBodyPineCone = world->CreateBody(&bodyDef);
pBodyPineCone->CreateFixture(&fixtureDef);
}
void PineCone::show()
{
int blit = SDL_BlitSurface( pPineCone, NULL, pScreen, &box );
if( blit < 0 )
{
exit(1);
}
}
I am not sure if I missed something in Main.
int main(int argc, char *argv[])
{
B2_NOT_USED(argc);
B2_NOT_USED(argv);
// Prepare for simulation. Typically we use a time step of 1/60 of a
// second (60Hz) and 10 iterations. This provides a high quality simulation
// in most game scenarios.
float32 timeStep = 1.0f / 60.0f;
int32 velocityIterations = 6;
int32 positionIterations = 2;
// Start the timer
g_dwStartTicks = SDL_GetTicks();
init();
load_files();
//PineCone
PineCone myPineCone;
myPineCone.specify(g_iPineConeSize, g_iPineConeSize, pPineCone, pScreen, &world);
//
// The Main Game Loop
//
do
{
// Record the current time
g_dwStartTime = SDL_GetTicks();
//
// Handle they keyboard events here
//
while (SDL_PollEvent(&event) > 0)
{
if (event.type == SDL_QUIT)
{
// Quit event! (Window close, kill signal, etc.)
g_iLoopDone = TRUE;
}
}
world.Step(timeStep, velocityIterations, positionIterations);
myPineCone.handle_input();
if (g_bPlaying || g_bEnd)
{
//Show pinecone
myPineCone.show();
}
// Update the display
SDL_Flip(pScreen);
g_dwEndTime = SDL_GetTicks();
if (g_dwEndTime < g_dwStartTime + (1000 / 60))
{
SDL_Delay(g_dwStartTime + (1000 / 60) - g_dwEndTime);
}
}while (!g_iLoopDone);
//Clean Up
clean_up();
return 0;
}
I can think for example that the physical self is updating're not visualizing
what the Sprite (Image) not update the corresponding value of its physical body.
Try to give it a Box2D body position if the image does not move you do not
have to be the update of physics.
Try this:
void setL1b2SpritePosition(Point position)
{
pBodyPineCone->SetAwake (true);
pBodyPineCone->setPosition(position);
//update box2d
pBodyPineCone->SetTransform(
b2Vec2(position.x / PTM_RATIO, position.y/ PTM_RATIO),
_body->GetAngle());
}
void updatePhysics()
{
_world->Step(.1, 10, 10);
for (b2Body *b = _world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetUserData() != NULL)
{
Sprite *ballData = dynamic_cast<Sprite*> ((Sprite *) b->GetUserData());
ballData->setPosition(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
ballData->setRotation(-1 * CC_RADIANS_TO_DEGREES(b->GetAngle()));
}
}
}
I keep getting the same crash report "'Signature not found for selector - does it have the following form? -(void) name: (ccTime) dt'".
This is getting pretty annoying now, i only wanted to make the Backgound scrolling infinitely.
Here is my code:
-(id) init {
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init])) {
self.isTouchEnabled = YES;
self.isAccelerometerEnabled = YES;
CGSize screenSize = [CCDirector sharedDirector].winSize;
/*CCSprite *Player = [CCSprite spriteWithFile:#"Icon.png"];
Player.position = ccp(screenSize.width/2 -110, screenSize.height/2);
Player.scale = 0.7;
[self addChild:Player];
[self scheduleUpdate];*/
CCLOG(#"Screen width %0.2f screen height %0.2f",screenSize.width,screenSize.height);
b2Vec2 gravity;
gravity.Set(0.0f, -10.0f);
bool doSleep = true;
world = new b2World(gravity, doSleep);
world->SetContinuousPhysics(true);
// Debug Draw functions
/*m_debugDraw = new GLESDebugDraw( PTM_RATIO );
world->SetDebugDraw(m_debugDraw);
uint32 flags = 0;
flags += b2DebugDraw::e_shapeBit;
//flags += b2DebugDraw::e_jointBit;
//flags += b2DebugDraw::e_aabbBit;
//flags += b2DebugDraw::e_pairBit;
//flags += b2DebugDraw::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.
b2PolygonShape groundBox;
// bottom
groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(screenSize.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);
// top
groundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO));
groundBody->CreateFixture(&groundBox,0);
//Set up sprite
BG1 = [CCSprite spriteWithFile:#"SkyAndClouds.png"];
BG1.anchorPoint = ccp(0,0);
BG1.position = ccp(0, 0);
BG1.scale = 0.5;
[self addChild:BG1];
BG2 = [CCSprite spriteWithFile:#"SkyAndClouds.png"];
BG2.anchorPoint = ccp(0,0);
BG2.position = ccp([BG1 boundingBox].size.width-1,0);
[self addChild:BG2];
[self schedule: #selector(AnimatedBG:) interval:0];
CCSpriteBatchNode *batch = [CCSpriteBatchNode batchNodeWithFile:#"Stick.png" capacity:150];
[self addChild:batch z:0 tag:kTagBatchNode];
[self addNewSpriteWithCoords:ccp(screenSize.width/2-110, screenSize.height/2)];
[self addZombieWithCoords:ccp(screenSize.width/2+240, screenSize.height/2)];
CCLabelTTF *label = [CCLabelTTF labelWithString:#"Stick, you Better Run!" fontName:#"Helvetica" fontSize:16];
[self addChild:label z:0];
[label setColor:ccc3(0,0,255)];
label.position = ccp( screenSize.width/2, screenSize.height-17);
[self schedule: #selector(tick:)];
}
return self;
}
-(void)AnimatedBG {
BG1.position = ccp(BG1.position.x-1,BG1.position.y);
}
Your AnimatedBG method should be defined as:
-(void) AnimatedBG:(ccTime)dt {
}
You should also make sure you have a definition for your scheduled tick: method:
-(void) tick:(ccTime)dt {
}
I'm developing game in iPhone in that pixel perfect collision will work only if one sprite appears on scene otherwise it wont work.can you please provide me some information?
I used this code for pixel perfect collision between animated sprites(spritesheet).
-(BOOL) isCollisionBetweenSpriteA:(CCSprite*)spr1 spriteB:(CCSprite*)spr2 pixelPerfect:(BOOL)pp
{
BOOL isCollision = NO;
CGRect intersection = CGRectIntersection([spr1 boundingBox], [spr2 boundingBox]);
// Look for simple bounding box collision
if (!CGRectIsEmpty(intersection))
{
// If we're not checking for pixel perfect collisions, return true
if (!pp) {return YES;}
CGPoint spr1OldPosition = spr1.position;
CGPoint spr2OldPosition = spr2.position;
spr1.position = CGPointMake(spr1.position.x - intersection.origin.x, spr1.position.y - intersection.origin.y);
spr2.position = CGPointMake(spr2.position.x - intersection.origin.x, spr2.position.y - intersection.origin.y);
intersection = CGRectIntersection([spr1 boundingBox], [spr2 boundingBox]);
// Assuming that the spritebatchnode of both sprites is the same, I just use one. If each sprite has a different sprite batch node as parent you should modify the code to get the spriteBatchNode for each sprite and visit them.
CCSpriteBatchNode* _sbnMain =(CCSpriteBatchNode*) spr1.parent;
//NOTE: We are assuming that the spritebatchnode is always at 0,0
// Get intersection info
unsigned int x = (intersection.origin.x)* CC_CONTENT_SCALE_FACTOR();
unsigned int y = (intersection.origin.y)* CC_CONTENT_SCALE_FACTOR();
unsigned int w = intersection.size.width* CC_CONTENT_SCALE_FACTOR();
unsigned int h = intersection.size.height* CC_CONTENT_SCALE_FACTOR();
unsigned int numPixels = w * h;// * CC_CONTENT_SCALE_FACTOR();
// create render texture and make it visible for testing purposes
int renderWidth = w+1;
int renderHeight = h+1;
if(renderWidth<32)
{
renderWidth =32;
}
if(renderHeight < 32)
{
renderHeight =32;
}
renderTexture = [[CCRenderTexture alloc] initWithWidth:renderWidth height:renderHeight pixelFormat:kCCTexture2DPixelFormat_RGBA8888];
//rt is always going to be at 0,0 - can't change it.
renderTexture.position = CGPointMake(0, 0);
[self addChild:renderTexture];
renderTexture.visible = NO;
//NSLog(#"\nintersection = (%u,%u,%u,%u), area = %u",x,y,w,h,numPixels);
// Draw into the RenderTexture
[renderTexture beginWithClear:0 g:0 b:0 a:0];
// Render both sprites: first one in RED and second one in GREEN
glColorMask(1, 0, 0, 1);
[_sbnMain visitSprite:spr1];
glColorMask(0, 1, 0, 1);
[_sbnMain visitSprite:spr2];
glColorMask(1, 1, 1, 1);
// Get color values of intersection area
ccColor4B *buffer = malloc( sizeof(ccColor4B) * numPixels );
glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
[renderTexture end];
// Read buffer
unsigned int step = 1;
for(unsigned int i=0; i<numPixels; i+=step)
{
ccColor4B color = buffer[i];
if (color.r > 0 && color.g > 0)
{
isCollision = YES;
break;
}
}
// Free buffer memory
free(buffer);
spr1.position = spr1OldPosition;
spr2.position = spr2OldPosition;
[renderTexture release];
[self removeChild:renderTexture cleanup:YES];
} return isCollision;}
Ball is not getting bounced what am I doing wrong ?
here is the class
#include "GameLayer.h"
USING_NS_CC;
GameLayer::GameLayer(){
mWorld = NULL;
mBody=NULL;
mBall=NULL;
}
GameLayer::~GameLayer(){
delete mWorld;
mBody=NULL;
delete mBall;
mBall=NULL;
}
bool GameLayer::init()
{
if ( !CCLayer::init() )
{
return false;
}
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
// Create sprite and add it to the layer
mBall = CCSprite::spriteWithFile("Ball.jpg",CCRectMake(0,0,52,52));
mBall->setPosition(ccp(100,100));
addChild(mBall);
// Create a world
b2Vec2 gravity;
gravity.Set(0.0f,-10.0f);
mWorld = new b2World(gravity);
// Do we want to let bodies sleep?
// mWorld->SetAllowSleeping(true);
// mWorld->SetContinuousPhysics(true);
//Definition of the body
// body definition to specify initial properties of the body such as position or velocity.
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0,0);
// use the world object to create a body object by specifying the body definition.
b2Body *groundBody = mWorld->CreateBody(&groundBodyDef);
//Create the shape as needed (for ground all the sides)
b2EdgeShape groundEdge;
groundEdge.Set(b2Vec2_zero,b2Vec2(winSize.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundEdge,0);
groundEdge.Set(b2Vec2(0,0), b2Vec2(0, winSize.height/PTM_RATIO));
groundBody->CreateFixture(&groundEdge,0);
groundEdge.Set(b2Vec2(0, winSize.height/PTM_RATIO),
b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO));
groundBody->CreateFixture(&groundEdge,0);
groundEdge.Set(b2Vec2(winSize.width/PTM_RATIO,
winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO, 0));
groundBody->CreateFixture(&groundEdge,0);
// Create the another body
//1. body defn
//2. create body from game world
// 3. define shape and create fixtures
b2BodyDef ballBodyDef;
ballBodyDef.position.Set(100/PTM_RATIO,100/PTM_RATIO);
// applying sprite as userdata to the bodydef
ballBodyDef.userData = mBall;
mBody = mWorld->CreateBody(&ballBodyDef);
// created different shapes as you want
b2CircleShape circle;
circle.m_radius = 26.0/PTM_RATIO;
//create the fixturedef
b2FixtureDef ballShapeDef;
ballShapeDef.shape = &circle;
ballShapeDef.density=1.0f;
ballShapeDef.friction=0.2f;
ballShapeDef.restitution=0.8f;
mBody->CreateFixture(&ballShapeDef);
setAccelerometerEnabled(true);
scheduleUpdate();
return true;
}
void GameLayer::update(float dt){
mWorld->Step(dt,10,10);
for(b2Body *b = mWorld->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *ballData = (CCSprite *)b->GetUserData();
ballData->setPosition(ccp(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO));
ballData->setRotation(-1 * CC_RADIANS_TO_DEGREES(b->GetAngle()));
}
}
}
void GameLayer::didAccelerate(CCAcceleration* pAccelerationValue)
{
b2Vec2 gravity(-pAccelerationValue->y * 15,pAccelerationValue->x *15);
mWorld->SetGravity(gravity);
}
b2BodyDef has b2_staticBody type by default. Try to set
ballBodyDef.type = b2_dynamicBody;
i have a problem with revolutejoint. When i make a line with litlle boxes and revoluteJoint i noticed a strange behavior of my first box. it separates from rest of the boxes.
You can see it here:
Youtube
You can compile it, and you'll see what im talking about…
HelloWorldScene.h
// When you import this file, you import all the cocos2d classes
#import "cocos2d.h"
#import "Box2D.h"
#import "GLES-Render.h"
// HelloWorld Layer
#interface HelloWorld : CCLayer
{
b2World* world;
GLESDebugDraw *m_debugDraw;
}
// returns a Scene that contains the HelloWorld as the only child
+(id) scene;
-(void) Test;
#end
HelloWorldScene.mm
// Import the interfaces
#import "HelloWorldScene.h"
//Pixel to metres ratio. Box2D uses metres as the unit for measurement.
//This ratio defines how many pixels correspond to 1 Box2D "metre"
//Box2D is optimized for objects of 1x1 metre therefore it makes sense
//to define the ratio so that your most common object type is 1x1 metre.
#define PTM_RATIO 32
// enums that will be used as tags
enum {
kTagTileMap = 1,
kTagBatchNode = 1,
kTagAnimation1 = 1,
};
// HelloWorld implementation
#implementation HelloWorld
+(id) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorld *layer = [HelloWorld node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
// initialize your instance here
-(id) init
{
if( (self=[super init])) {
// enable touches
self.isTouchEnabled = YES;
// enable accelerometer
self.isAccelerometerEnabled = YES;
CGSize screenSize = [CCDirector sharedDirector].winSize;
CCLOG(#"Screen width %0.2f screen height %0.2f",screenSize.width,screenSize.height);
// Define the gravity vector.
b2Vec2 gravity;
gravity.Set(0.0f, -10.0f);
// Do we want to let bodies sleep?
// 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, doSleep);
world->SetContinuousPhysics(true);
// Debug Draw functions
m_debugDraw = new GLESDebugDraw( PTM_RATIO );
world->SetDebugDraw(m_debugDraw);
uint32 flags = 0;
flags += b2DebugDraw::e_shapeBit;
flags += b2DebugDraw::e_jointBit;
// flags += b2DebugDraw::e_aabbBit;
// flags += b2DebugDraw::e_pairBit;
// flags += b2DebugDraw::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.
b2PolygonShape groundBox;
// bottom
groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(screenSize.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);
// top
groundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO));
groundBody->CreateFixture(&groundBox,0);
// left
groundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(0,0));
groundBody->CreateFixture(&groundBox,0);
// right
groundBox.SetAsEdge(b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);
//Set up sprite
[self Test];
[self schedule: #selector(tick:)];
}
return self;
}
- (void) Test {
// Circle
b2Body *circle1;
b2BodyDef bd1;
bd1.position.Set(45.0f/PTM_RATIO, 180.0f/PTM_RATIO);
bd1.type = b2_kinematicBody;
bd1.fixedRotation = false;
bd1.allowSleep = false;
circle1 = world->CreateBody(&bd1);
b2CircleShape shapecircle1;
shapecircle1.m_radius = 0.5f;
b2FixtureDef fdcircle1;
fdcircle1.shape = &shapecircle1;
fdcircle1.density = 2.0f;
fdcircle1.friction = 2.0f;
circle1->CreateFixture(&fdcircle1);
// Boxes
b2PolygonShape shape;
shape.SetAsBox(6.0f/PTM_RATIO, 0.125f);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 20.0f;
fd.friction = 0.2f;
b2RevoluteJointDef jd;
jd.collideConnected = false;
const float32 y = 9.0f;
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(15.0f/PTM_RATIO, y);
b2Body* prevBody = world->CreateBody(&bd);
prevBody->CreateFixture(&fd);
b2Vec2 anchor(float32(0), y);
for (int32 i = 1; i < 8; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set((15.0f + (i*10))/PTM_RATIO, y);
b2Body* body = world->CreateBody(&bd);
body->CreateFixture(&fd);
b2Vec2 anchor(float32(i*10)/PTM_RATIO, y);
jd.Initialize(prevBody, body, anchor);
world->CreateJoint(&jd);
prevBody = body;
}
}
-(void) 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);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
world->DrawDebugData();
// restore default GL states
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
-(void) tick: (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())
{
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());
}
}
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
delete world;
world = NULL;
delete m_debugDraw;
// don't forget to call "super dealloc"
[super dealloc];
}
#end
Any idea? Thanks in advance
The problem in your case is that your first box makes a 360 degree rotation around the anchor. This can happen to first and last box. I think you need to restrict the 360 degree rotation for your join. You have do define that maximum angle that your box can achieve. You can do it by using motors in your joints. Following is some code from Box2D manual to create motors for your joints,
b2RevoluteJointDef jointDef;
jointDef.Initialize(body1, body2, myBody1->GetWorldCenter());
jointDef.lowerAngle = -0.5f * b2_pi; // -90 degrees
jointDef.upperAngle = 0.25f * b2_pi; // 45 degrees
jointDef.enableLimit = true;
jointDef.maxMotorTorque = 10.0f;
jointDef.motorSpeed = 0.0f;
jointDef.enableMotor = true;
I hope it helps.