Cocos2d draw a polygon using CCSprite - cocos2d-iphone

Can you help. Want to draw a polygon (beams at different angles) and apply box 2d body to it. Can you please let me know how to create a CCSprite with a polygon shape
Any examples would help
Cheers

Create Polygon body.
-(void) createDynamicPoly {
b2BodyDef bodyDefPoly;
bodyDefPoly.type = b2_dynamicBody;
bodyDefPoly.position.Set(3.0f, 10.0f);
b2Body *polyBody = world->CreateBody(&bodyDefPoly);
int count = 8;
b2Vec2 vertices[8];
vertices[0].Set(0.0f / PTM_RATIO,0.0f / PTM_RATIO);
vertices[1].Set(48.0f/PTM_RATIO,0.0f/PTM_RATIO);
vertices[2].Set(48.0f/PTM_RATIO,30.0f/PTM_RATIO);
vertices[3].Set(42.0f/PTM_RATIO,30.0f/PTM_RATIO);
vertices[4].Set(30.0f/PTM_RATIO,18.0f/PTM_RATIO);
vertices[5].Set(18.0f/PTM_RATIO,12.0f/PTM_RATIO);
vertices[6].Set(6.0f/PTM_RATIO,18.0f/PTM_RATIO);
vertices[7].Set(0.0f/PTM_RATIO,30.0f/PTM_RATIO);
b2PolygonShape polygon;
polygon.Set(vertices, count);
b2FixtureDef fixtureDefPoly;
fixtureDefPoly.shape = &polygon;
fixtureDefPoly.density = 1.0f;
fixtureDefPoly.friction = 0.3f;
polyBody->CreateFixture(&fixtureDefPoly);
}
Create your sprite
Attach your sprite to the Polygon body via Fixture and UserData
fixtureDefPoly.SetUserData() = spriteObject;
b2Fixture *fixture;
fixture = circleBody->CreateFixture(&fixtureDefPoly);
fixture->SetUserData(#"spriteObject");
Then Iterate the sprite to the body in your update method.

The easiest way is to open an image editor (such as paint for example or photoshop) and create the image you want. The use it in your program.
Also there is a helloWorld scene when creating an xcode application using cocos2d box2d template. It creates a set of squares with a texture.

CGPoint startPt = edge.start ;
CGPoint endpt = edge.end ;
//length of the stick body
float len = abs(ccpDistance(startPt, endpt))/PTM_RATIO;
//to calculate the angle and position of the body.
float dx = endpt.x-startPt.x;
float dy = endpt.y-startPt.y;
//position of the body
float xPos = startPt.x+dx/2.0f;
float yPos = startPt.y+dy/2.0f;
//width of the body.
float width = 1.0f/PTM_RATIO;
b2BodyDef bodyDef;
bodyDef.position.Set(xPos/PTM_RATIO, yPos/PTM_RATIO);
bodyDef.angle = atan(dy/dx);
NSLog([NSString stringWithFormat:#"Setting angle %f",bodyDef.angle]);
CCSprite *sp = [CCSprite spriteWithFile:#"material-wood.png" rect:CGRectMake(0, 0, 12, 12)];
//TODO: fix shape
[self addChild:sp z:1 ];
bodyDef.userData = sp;
bodyDef.type = b2_dynamicBody;
b2Body* body = world->CreateBody(&bodyDef);
b2PolygonShape shape;
b2Vec2 rectangle1_vertices[4];
rectangle1_vertices[0].Set(-len/2, -width/2);
rectangle1_vertices[1].Set(len/2, -width/2);
rectangle1_vertices[2].Set(len/2, width/2);
rectangle1_vertices[3].Set(-len/2, width/2);
shape.Set(rectangle1_vertices, 4);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
fd.friction = 0.300000f;
fd.restitution = 0.600000f;
body->CreateFixture(&fd);

Related

Box2D ContactListener Not Detecting Collision

I am trying to detect a collision between a static body and a kinematic body using the b2ContactListener class but my code is not detecting a collision between my two fixtures. I placed an EdgeShape at the top of my kinematic body and made it a fixture to detect a collision with my static body fixture. I am using SFML to draw to the screen and detect keyboard events.
Here is my main function:
int main()
{
Vector2f resolution;
resolution.x = VideoMode::getDesktopMode().width;
resolution.y = VideoMode::getDesktopMode().height;
RenderWindow window(VideoMode(resolution.x, resolution.y),
"Box2D Test", Style::Fullscreen);
Vector2f staticRectSize(100.0f, 20.0f);
Vector2f kinematicRectSize(40.0f, 20.0f);
Event keyBoardEvent;
b2Vec2 gravity(0.0f, 0.0f);
b2World world(gravity);
// Creating static body and fixture
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(100.0f, 150.0f);
b2Body* groundBody = world.CreateBody(&groundBodyDef);
b2PolygonShape groundBox;
groundBox.SetAsBox(50.0f, 10.0f);
groundBody->CreateFixture(&groundBox, 0.0f);
// Creating kinematic body and fixture
b2BodyDef bodyDef;
bodyDef.type = b2_kinematicBody;
bodyDef.position.Set(125.0f, 700.0f);
b2Body* body = world.CreateBody(&bodyDef);
b2PolygonShape kinematicBox;
kinematicBox.SetAsBox(20.0f, 10.0f);
b2FixtureDef fixtureDef;
fixtureDef.shape = &kinematicBox;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
body->CreateFixture(&fixtureDef);
// world.Step inputs
float32 timeStep = 1.0f / 60.0f;
int32 velocityIterations = 6;
int32 positionIterations = 2;
RectangleShape staticRect(staticRectSize);
RectangleShape dynamicRect(kinematicRectSize);
b2Vec2 staticPosition = groundBody->GetPosition();
staticRect.setPosition(staticPosition.x, staticPosition.y);
b2Vec2 dynamicPosition = body->GetPosition();
// Creating EdgeShape
b2EdgeShape top;
top.Set(b2Vec2(dynamicPosition.x, dynamicPosition.y), b2Vec2(dynamicPosition.x + 40.0, dynamicPosition.y));
fixtureDef.shape = ⊤
fixtureDef.isSensor = true;
body->CreateFixture(&fixtureDef)->SetUserData("top collision");
// Creating an instance of myContactListener class
myContactListener contactListener;
world.SetContactListener(&contactListener);
while (window.isOpen())
{
world.Step(timeStep, velocityIterations, positionIterations);
dynamicPosition = body->GetPosition();
dynamicRect.setPosition(dynamicPosition.x, dynamicPosition.y);
while (window.pollEvent(keyBoardEvent))
{
if (keyBoardEvent.type == Event::KeyPressed)
{
if (keyBoardEvent.key.code == Keyboard::W)
{
body->SetLinearVelocity(b2Vec2(0, -10));
}
...
window.clear();
window.draw(staticRect);
window.draw(dynamicRect);
window.draw(line);
window.display();
if (Keyboard::isKeyPressed(Keyboard::Escape))
{
break;
}
}
return 0;
}
And here is my MyContactListiner.cpp:
void myContactListener::BeginContact(b2Contact* contact)
{
b2Fixture *fa = contact->GetFixtureA();
b2Fixture *fb = contact->GetFixtureB();
if (fa == NULL || fb == NULL) { return; }
while (1)
{
printf("Collision occurred");
if (Keyboard::isKeyPressed(Keyboard::Escape))
{
break;
}
}
}
Box2D doesn't do collision handling for static bodies directly against other static or kinematic bodies. They're both theoretically of infinite mass for which laws of motion don't seem to make much sense anymore (at least not to me in terms of collisions).
Probably easiest to make the kinematic body a dynamic one instead.
You could alternatively surround one of the bodies with dynamic ones to get the contact listener to fire up. The dynamic bodies can't be made to drive the kinematic or static one it surrounds however in the substep phases without more effort than I think it'd be worth.
Hope this answer helps!

cocos2d sprite tag not being set

I'm using the following to create sprites with b2bodys
but I cant get the sprites tag to set. why isn't [sprite setTag:3]; working?
When I detect a collision with one of these sprites it says the sprite tag is 0
-(void) addNewSpriteAtPosition:(CGPoint)p
{
// CCLOG(#"Add sprite %0.2f x %02.f",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);
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 = 2;
fixtureDef.friction = 0.2f;
body->CreateFixture(&fixtureDef);
CCNode *parent = [self getChildByTag:kTagParentNode];
//We have a 64x64 sprite sheet with 4 different 32x32 images. The following code is
//just randomly picking one of the images
int idx = (CCRANDOM_0_1() > .5 ? 0:1);
int idy = (CCRANDOM_0_1() > .5 ? 0:1);
CCPhysicsSprite *sprite = [CCPhysicsSprite spriteWithTexture:spriteTexture_ rect:CGRectMake(32 * idx,32 * idy,32,32)];
[parent addChild:sprite];
[sprite setPTMRatio:PTM_RATIO];
[sprite setB2Body:body];
[sprite setPosition: ccp( p.x, p.y)];
[sprite setTag:3];
}

Making sprite bounce in an angle in box2d

In the game I'm trying to make, I have a ball sprite which bounces thanks to box2d. Here's how my current code looks:
-(id)init
{
ball = [CCSprite spriteWithFile:#"ball.png"];
ball.position = ccp(150, winSize.height * 0.78);
[self addChild:ball];
ball.tag = 2;
b2BodyDef ballBodyDef;
ballBodyDef.type = b2_dynamicBody;
ballBodyDef.position.Set(150/PTM_RATIO, 450/PTM_RATIO);
ballBodyDef.userData = ball;
_body = _world->CreateBody(&ballBodyDef);
b2CircleShape circle;
circle.m_radius = 26.0/PTM_RATIO;
b2FixtureDef ballShapeDef;
ballShapeDef.shape = &circle;
ballShapeDef.density = 0.5f;
ballShapeDef.friction = 1.0f;
ballShapeDef.restitution = 1.0f;
_ballFixture = _body->CreateFixture(&ballShapeDef);
b2Vec2 force = b2Vec2(160, 375);
_body->ApplyLinearImpulse(force, ballBodyDef.position);}
- (void)update:(ccTime) dt {
if(_isPaused == 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 == 2)
{
sprite.position = ccp(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
sprite.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
}}
Bouncing itself works fine, my problem is there are instances wherein the ball would bounce on a straight line so to speak, either vertically or horizontally continuously which I am trying to avoid. So my question is, how can I make my ball sprite bounce at an angle instead of a straight line so it wouldn't get stuck bouncing infinitely in the same direction?
You could apply a tiny force or gravity change to the body or the world, "randomly" or at equal intervals.

Attaching a Body to a Sprite

I am trying to test/create a sample game using Cocos2d 2.0 and box2d. I have a bunch of sprites on the screen and when I press the Sprite, I want a body to be automatically attached to that Sprite. I tried to use the TouchesEnd method but it doesn't seem to work.
Can someone push me in the right direction?
Try this way...
-(void)createB2Body
{
b2PolygonShape shape;
float xDist = (sprite.contentSize.width*0.5f)/PTM_RATIO ;
float yDist = (sprite.contentSize.height*0.5f)/PTM_RATIO ;
shape.SetAsBox(xDist, yDist);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.userData = sprite;
bd.linearDamping = 0.5f;
bd.angularDamping = 0.5f;
bd.position.Set(self.position.x/PTM_RATIO, self.position.y/PTM_RATIO);
b2FixtureDef fixDef;
fixDef.shape = &shape;
fixDef.density = 1.0f;
fixDef.friction = 0.1f;
fixDef.restitution = 1.0f;
fixDef.isSensor = true;
self.body = self.world->CreateBody(&bd);
self.body->CreateFixture(&fixDef);
}
Only on touch? then use ccTouchesBegan.

box2d bodies fall up instead of down

Im working with cocos2d v1.0.1 & the respective Box2d version. In the simulator it all works. Its just a body created at a touch location that drops down to the ground. But I ran it on the device, iphone4, and the objects float upwards.
Why would this happen?
Gravity is set to -0.3f. I have another dynamic body in the scene and it appears on the bottom of the ground as it should. Its just the touch objects that float up. Sleep is True.
I just set sleep to false and now the rover also floats up. But it should not float up. here is my world creation method:
- (void)setupWorld {
b2Vec2 gravity = b2Vec2(0.0f, -0.3f);
bool doSleep = false;
world = new b2World(gravity, doSleep);
}
and here is my body creation from init:
Box2DSprite *roverSprite = [Box2DSprite spriteWithSpriteFrameName:#"rover.png"];
[self createBoxAtLocation:ccp(100,15) withSize:CGSizeMake(50, 50) forSprite:roverSprite isBox:TRUE];
[sceneSpriteBatchNode addChild:roverSprite];
and here is the createBox method:
- (void)createBoxAtLocation:(CGPoint)location withSize:(CGSize)size forSprite:(Box2DSprite *)sprite isBox:(BOOL)isBox{
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
b2Body *body = world->CreateBody(&bodyDef);
//
body->SetUserData(sprite);
sprite.body = body;
b2FixtureDef fixtureDef;
//
if (isBox) {
b2PolygonShape shape;
shape.SetAsBox(sprite.contentSize.width/3/PTM_RATIO,
sprite.contentSize.height/3/PTM_RATIO);
fixtureDef.shape = &shape;
} else {
b2CircleShape shape;
shape.m_radius = sprite.contentSize.width/2/PTM_RATIO;
fixtureDef.shape = &shape;
}
fixtureDef.density = 1.0;
fixtureDef.friction = 1.0;
fixtureDef.restitution = 0.5;
body->CreateFixture(&fixtureDef);
}
The same method is also used for the touch created objects which are created from these lines:
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [touch locationInView:[touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
//b2Vec2 locationWorld = b2Vec2(touchLocation.x/PTM_RATIO, touchLocation.y/PTM_RATIO);
Box2DSprite *sprite = [Box2DSprite spriteWithSpriteFrameName:#"koko1.png"];
[self createBoxAtLocation:touchLocation withSize:CGSizeMake(50, 50) forSprite:sprite isBox:TRUE];
[sceneSpriteBatchNode addChild:sprite];
return TRUE;
}
Are you in portrait or landscape mode? If in landscape, perhaps you have the device rotated left instead of right. The device orientation can swap the y-values of the accelerometer on you. Not sure if this is related to your issue.
Turns out I had the Target Settings Rotation to Right instead of Left.