i have a ball which is a box2d body and moves around the screen... i want to create multiple balls of similar type and they should also collide among them self..
the code i am using now is
ballcount = [[levelData objectForKey:#"ballcount"]intValue] ;
ballarray = [[NSMutableArray arrayWithCapacity:ballcount]init] ;
for (int j=0; j<ballcount; j++) {
ball = [CCSprite spriteWithFile:#"ball.png"];
[ballarray insertObject:ball atIndex:j];
[self createBallBoundingBox:(CCSprite *)[ballarray objectAtIndex:j]];
[[ballarray objectAtIndex:j]setPosition:ccp(arc4random() % 480 , arc4random() % 320)];
[self addChild:[ballarray objectAtIndex:j]];
}
There is only one sprite appearing on the screen when i run it ? any suggestions what am i doing wrong ... it works perfectly when only one ball is there
Thanks
ok i have got the above code to work but now i am having a problem with the movement in the tick method .. the box2d shapes are moving but the CCSprite shapes are not getting attached to the box2d bodies here is my code
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 isKindOfClass:[Ball class]])
{
b2Vec2 Vel = b->GetLinearVelocity();
float32 angle = atan2(Vel.y, Vel.x);
angle += -M_PI/2;
b->SetTransform(b->GetPosition(),angle);
sprite.position = ccp(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
sprite.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
Ok guys here is my createBoundingBox definition
-(void)createBallBoundingBox:(Ball *)ballSprite{
b2BodyDef BallBodyDef;
ballBodyDef.type = b2_dynamicBody;
ballBodyDef.position.Set(ballSprite.position.x/PTM_RATIO, ballSprite.position.y/PTM_RATIO);
ballBodyDef.userData = ballSprite;
ballBody = world->CreateBody(&ballBodyDef);
/// test circle shape on ballbody
b2CircleShape BallCircleShape;
BallCircleShape.m_radius = 10/PTM_RATIO;
// Create shape
/*
b2PolygonShape ballShape;
int num = 7;
b2Vec2 verts[] = {
b2Vec2(0.0f / PTM_RATIO, 19.2f / PTM_RATIO),
b2Vec2(-10.7f / PTM_RATIO, 15.2f / PTM_RATIO),
b2Vec2(-6.7f / PTM_RATIO, -3.2f / PTM_RATIO),
b2Vec2(-1.7f / PTM_RATIO, -18.0f / PTM_RATIO),
b2Vec2(7.7f / PTM_RATIO, 0.5f / PTM_RATIO),
b2Vec2(10.5f / PTM_RATIO, 14.7f / PTM_RATIO),
b2Vec2(0.2f / PTM_RATIO, 19.0f / PTM_RATIO)
};
ballShape.Set(verts,num);
*/
// Create shape definition and add to body
b2FixtureDef ballFixtureDef;
ballFixtureDef.shape = &ballCircleShape;
ballFixtureDef.density = 1.0f;
ballFixtureDef.friction = 0.0f;
ballFixtureDef.restitution = 1.0f;
ballFixture = ballBody->CreateFixture(&ballFixtureDef);
b2Vec2 direction(5,2);
direction.Normalize();
float force = 1.0f;
b2Vec2 position = ballBody->GetPosition();
//Apply linear velocity
ballBody->ApplyLinearImpulse(force*direction,ballBody->GetPosition());
b2Vec2 Vel = ballBody->GetLinearVelocity();
float32 angle = atan2(Vel.y, Vel.x);
angle += -M_PI/2;
ballBody->SetTransform(ballBody->GetPosition(),angle);
}
any ideas ? Let me know
Thanks a lot guys
inside your method
[self createBallBoundingBox:(CCSprite *)[ballarray objectAtIndex:j]];
//OR NOW
[self createMiceBoundingBox:tempmice];
did you forgot to attach the Ball as UserData to your b2Body
- (void) createMiceBoundingBox: (Ball*) ball
{
//...
b2Body body = ...
body.SetUserData(ball);
//..
}
if not show us the code of the method
EDIT: if you use Mice instead of Ball make sure you update tick method to
if ([sprite isKindOfClass:[Mice class]])
Related
I am still new to cocos2d and I have this problem that when I am using the ccp coordinates it stays at same position even when I move to the next screen. I came to the conclusion it must be that I am not using the tiles coordinates. So I need some help converting.
- (CGPoint)tileCoordForPosition:(CGPoint)position {
float x = floor(position.x / map.tileSize.width);
float levelHeightInPixels = map.mapSize.height * map.tileSize.height;
float y = floor((levelHeightInPixels - position.y) / map.tileSize.height);
return ccp(x, y);
}
-(CGRect)tileRectFromTileCoords:(CGPoint)tileCoords {
float levelHeightInPixels = map.mapSize.height * map.tileSize.height;
CGPoint origin = ccp(tileCoords.x * map.tileSize.width, levelHeightInPixels - ((tileCoords.y + 1) * map.tileSize.height));
return CGRectMake(origin.x, origin.y, map.tileSize.width, map.tileSize.height);
}
that is what i use to translate regular coordinates into tile map coordinates.
now I am trying to spawn an enemy at a certain position specifically (0,0)
-(void)addsaw{
CCSprite *saw = [CCSprite spriteWithFile:#"saw.png"];
// Determine where to spawn the target along the Y axis
CGSize winSize = [[CCDirector sharedDirector] winSize];
int minY =saw.contentSize.height/2;
int maxY = winSize.height - saw.contentSize.height/2;
int rangeY = maxY - minY;
int actualY = ( rangeY) + minY;
//THIS IS THE PROBLEM RIGHT HERE
saw.position = ccp(0,0);
[self addChild:saw];
// Create the actions
id actionMove = [CCMoveTo actionWithDuration:actualDuration
position:ccp(-saw.contentSize.width/2, actualY)];
id actionMoveDone = [CCCallFuncN actionWithTarget:self
selector:#selector(spriteMoveFinished2:)];
[saw runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
saw.tag = 1;
[_saws addObject:saw];
}
How do I change the ccp of my addsaw so I can have it spawn at the tile (0,0) rather than the cocos2d regular (0,0)
you should add your sprite to your cctmxtiledmap instead of the layer!
i am following a tutorial on a simple cocos2d game.
however on that tutorial the bullets that the user fires is only on one direction
what can i do to make it fire on all directions not just one sided?
here is the code of the direction.
int offX = location.x - projectile.position.x;
int offY = location.y - projectile.position.y;
[self addChild:projectile];
int realX = winSize.width + (projectile.contentSize.width/2);
float ratio = (float) offY / (float) offX;
int realY = (realX *ratio) + projectile.position.y;
CGPoint realDest = ccp(realX, realY);
int offRealX = realX - projectile.position.x;
int offRealY = realY - projectile.position.y;
float length = sqrtf((offRealX*offRealX)+(offRealY*offRealY));
float velocity = 480/1;
float realMoveDuration = length/velocity;
[projectile runAction:[Sequence actions:[MoveTo actionWithDuration:realMoveDuration position:realDest],
[CallFuncN actionWithTarget:self selector:#selector(spriteMoveFinished:)], nil]];
all help will be greatly appreciated. Thanks
Assuming you are creating the projectile at the location of your character, you just need to figure out the direction before calculating the end point.
After adding the projectile:
[self addChild:projectile];
Add a scalar float:
float scalarX = 1.0f;
And make it negative if the touch is left of the character:
if (offX < 0.0f) scalar = -1.0f;
Then just multiply the realX by this scalar to make it point the correct way
int realX = scalar * (winSize.width + (projectile.contentSize.width/2));
I am using box2d and cocos2d for my jump based game. I need to jump the character on platforms as they come.
Any ideas of how to do it using box2d ?
You try this:
//OBSTACLE_1:
{
CCSprite *sprite = [CCSprite spriteWithFile:#"hungObstacle1_C2H18.png"];
sprite.position = ccp(1568,704);
sprite.tag = 4;
[self addChild:sprite];
//SHAPE :
{
b2BodyDef bodyDefinition;
bodyDefinition.type = b2_dynamicBody;
bodyDefinition.position.Set(1568/PTM_RATIO, 704/PTM_RATIO);
bodyDefinition.userData = sprite;
body = world->CreateBody(&bodyDefinition);//body is a b2Body
// Create body shape
b2PolygonShape bodyShape;
//row 1, col 1
int num = 8;
b2Vec2 verts[] = {
b2Vec2(14.5f / PTM_RATIO, -27.0f / PTM_RATIO),
b2Vec2(19.5f / PTM_RATIO, -11.0f / PTM_RATIO),
b2Vec2(19.5f / PTM_RATIO, 11.0f / PTM_RATIO),
b2Vec2(16.5f / PTM_RATIO, 24.0f / PTM_RATIO),
b2Vec2(-14.5f / PTM_RATIO, 24.0f / PTM_RATIO),
b2Vec2(-19.5f / PTM_RATIO, 16.0f / PTM_RATIO),
b2Vec2(-19.5f / PTM_RATIO, -13.0f / PTM_RATIO),
b2Vec2(-12.5f / PTM_RATIO, -26.0f / PTM_RATIO)
};
bodyShape.Set(verts, num);
// Create shape definition and add to body
b2FixtureDef bodyFixtureDefinition;
bodyFixtureDefinition.shape = &bodyShape;
bodyFixtureDefinition.density = 5000.0f;
bodyFixtureDefinition.friction = 1.0f;
bodyFixtureDefinition.restitution = 1.0f;//*
fixture=body->CreateFixture(&bodyFixtureDefinition);
}
}
*NOTE:by setting restitution to 1 body will keep jumping all the time just need little force
To simulate jumping, you can use the cpBodyApplyImpulse method and apply a force in a straight up direction. Assuming you've got gravity enabled, this should provide an accuracte simulation, although you may need to tweak it. For example, here is a line from a recent project of mine.
cpBodyApplyImpulse(charBody, cpv(0.0, -25 * scale), charBody->p);
This is making the sprite represented by the charBody jump.
I am new in Box2D....
I have ball image in CCSprite. I want to move ball in whole screen using accelerometer...
tell me
How to use accelerometer in box2d??
Thanks...in advance
The standard cocos2d-box2d template file moves boxes using the accelerometer by applying gravity relative to the accelerometer value.
- (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 );
}
You need to be more specific on what you want the ball to do dependent on how you move the phone. Your question is difficult to answer in its current form.
Get the accelerometer measurements and say Force = coefficient*measurements. The apply this force to your b2Body
Let your Ball Sprite having tag is 1.
Replace this code with your Accelerometer delegate,
I test it on device, its working.
and your ball will move with accelerometer.
-(void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration
{
#define kFilterFactor 0.75
accelerometer.updateInterval = 1.0f/60.0f;
static UIAccelerationValue rollingX = 0, rollingY = 0;
for (b2Body *b = world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetUserData() != NULL)
{
CCSprite *sprite = (CCSprite*)b->GetUserData();
if (sprite.tag == 1) {
rollingX = (acceleration.x * kFilterFactor) + (rollingX * 0.25);
rollingY = (acceleration.y * kFilterFactor) + (rollingY * 0.25);
float accelX = rollingX;
float accelY = rollingY;
CGPoint moveNewPosition = sprite.position;
if (accelX > 0.1) {
moveNewPosition.y += 2;
} if (accelX < 0.1) {
moveNewPosition.y -= 2;
}
if (accelY > 0.1) {
moveNewPosition.x -= 2;
} if (accelY < -0.1) {
moveNewPosition.x += 2;
}
b->SetLinearVelocity(b2Vec2(2,2));
sprite.position = ccp(moveNewPosition.x , moveNewPosition.y );
sprite.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
}
}
I hope it'll work.
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)