i am using box2d to developed iphone game.But i have not a lot of experience.I move a body to a location using this code
body->SetTransform(b2Vec2(posx2,posy2), 0);
and the body does move.But i need it to move with animation.in objective c i use UIView Animation to do similar type of things. can anyone tell how it possible in cocos2d box2d??
This the way i did this.....
switch of the default tick method using /.../
and move the body manually...
b->SetTransform(b2Vec2(posx1, posy1), 0);
id action = [CCMoveTo actionWithDuration:0.4 position:CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO)];
[sprite runAction:action];
another way:
don't comment off the tick....and inside tick instead of these:
myActor.position = CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
you can reset position with animation as like the above....
Related
I am working with tile map and box2d with cocos2D in the game for iOS, i want to move the tile with respect to physics bodies, i.e. to combine one or more tiles in a body and on contact if body is moving then tile sprites should also move. Please suggest something to do so.
You could use a CCPhysicsSprite for this.
The following code is from the default Box2D project in Cocos2d v2.
-(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 = 1.0f;
fixtureDef.friction = 0.3f;
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)];
}
NOTE The position of the sprite has been set after the body has been created. If you do it the other way around, you may get an exception. See here.
I have a box2d object that is being moved down the screen via gravity
int32 velocityIterations = 6;
int32 positionIterations = 2;
self.world->Step(dt, velocityIterations, positionIterations);
self.world->ClearForces();
for(b2Body *b = self.world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
id object = (id)b->GetUserData();
if([object isKindOfClass:[FallingObject class]])
{
CCSprite *sprite = (CCSprite *)b->GetUserData();
sprite.position = CGPointMake(b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
sprite.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
}
When the user moves their finger across the screen either left or right i want to move the box2d object left or right while the object is still moving down the screen.
Can anyone suggest the best way to do this. I have tried applying linear velocity but it just seems to shoot of screen.
Any suggestions
Thanks
There some ways to do this, and you need to try the best for your case.
You can apply forces, impulse, or change the body velocity manually just for X parameter:
// x axis force
b2Vec2 xAxisForce = b2Vec2(10, 0);
// Try one of these
b->ApplyForce(xAxisForce, b->GetWorldCenter());
b->ApplyForceToCenter(xAxisForce);
b->ApplyLinearImpulse(xAxisForce, b->GetWorldCenter());
// Or change the body velocity manually
b->SetLinearVelocity(b2Vec2(10, b->GetLinearVelocity().y));
Hi you there how to move body to exact position like CCMoveTo action in cocos2d. i figure out how to make this with SetLinearVelocity
b2Vec2 force = (t * endPosition) - body->GetLinearVelocity();
[self runAction: [CCSequence actions: [CCCallBlock actionWithBlock:^{
body->SetLinearVelocity( force );
}],
[CCDelayTime actionWithDuration: (1.0f / t)],
[CCCallBlock actionWithBlock:^{
body->SetLinearVelocity( b2Vec2_zero );
}],nil]];
i found on forum this code but it doesn't help me..
b2Vec2 currentPosition = body->GetPosition();
b2Vec2 desiredPosition = ...;
b2Vec2 necessaryMovement = desiredPosition - currentPosition;
float necessaryDistance = necessaryMovement.Length();
necessaryMovement.Normalize();
float forceMagnitude = b2Min(maxAllowableForce, necessaryDistance);
b2Vec2 force = forceMagnitude * necessaryMovement;
body->ApplyForce( force, body->GetWorldCenter() );
same problem can't stop body at target point.. so please help me.
you have to run the code you have found in update call.
every update you move your object a little bit towards to your "desiredPosition"
float pForce = 10;
b2Vec2 forceDir = b2Vec2( ( desiredPosition.x - body->GetPosition().x ) * pForce ,
( desiredPosition.y - body->GetPosition().y ) * pForce );
apply foreDir to your body and play with pForce
I've found out that if you need to move, for example, rockets or something like that toward a target then it's better if you use a KinematicBody and the set the linear velocity of the body at each frame.
The formula given by Chakalaka works fine if you see the Vector2 as the linear velocity of the body you want to move.
I have a little issue with my game. In my main game scene I create a Player object from a class, like this:
player = [Player spriteWithFile:#"Icon-Small#2x.png"];
player.position = ccp(100.0f, 180.0f);
[player createBox2dObject:world];
Below is the main chunk of my small Player class that creates the body and the fixture so I can use it in a box2d world.
b2BodyDef playerBodyDef;
playerBodyDef.type = b2_dynamicBody;
playerBodyDef.position.Set(self.position.x/PTM_RATIO, self.position.y/PTM_RATIO);
playerBodyDef.userData = self;
playerBodyDef.fixedRotation = true;
playerBodyDef.linearDamping = 4.0;
body = world->CreateBody(&playerBodyDef);
b2CircleShape circleShape;
circleShape.m_radius = 0.7;
b2FixtureDef fixtureDef;
fixtureDef.shape = &circleShape;
fixtureDef.density = 1.0f;
fixtureDef.friction = 1.0f;
fixtureDef.restitution = 1.0f;
body->CreateFixture(&fixtureDef);
The result of this code is a Box2d object with Icon-Small#2x.png over it. When I move a joystick, a Box2D impulse is applied and the player moves. Simple enough, right?
In non-retina displays, this works fine. However, when I switch to Retina in the simulator, Icon-Small#2x.png is created a little higher and farther to the right, not over the Box2D circle. Then, gravity is applied and they both fall down to the platform. Icon-Small#2x.png falls twice as fast. When I move the joystick, the Box2D circle moves, but Icon-Small#2x.png moves twice as fast and the camera follows it, soon leaving the circle off the screen. I doubt this issue has really anything to do with the code I have here, I feel like its a scaling issue hidden somewhere in my game. Does anyone have suggestions?
Edit:
I move the sprite with:
[player moveRight];
This is moveRight in the player class:
-(void) moveRight {
b2Vec2 impulse = b2Vec2(2.0f, 0.0f);
body->ApplyLinearImpulse(impulse, body->GetWorldCenter());
}
Shouldn't be any issue here, right?
Edit (again):
Here's my update: method-
- (void) update:(ccTime)dt {
int32 velocityIterations = 8;
int32 positionIterations = 1;
world->Step(dt, velocityIterations, positionIterations);
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext()) {
if (b->GetUserData() != NULL) {
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());
}
}
b2Vec2 pos = [player body]->GetPosition();
CGPoint newPos = ccp(-1 * pos.x * PTM_RATIO + 50, self.position.y * PTM_RATIO);
[self setPosition:newPos];
}
I have a feeling that the issue is somewhere in here. I've tried changing PTM_RATIO around, but it doesn't affect the speed. Any ideas?
Edit: see comment below, almost have this figured out
You problem probably stems from the fact you are using a #2x image... Read, http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:how_to_develop_retinadisplay_games_in_cocos2d
There it states:
WARNING: It is NOT recommend to use the ”#2x” suffix. Apple treats those images in a special way which might cause bugs in your cocos2d application.
So to solve your problem read through the information on using png files with the -hd suffix.
For the comment:
Do you have some code that looks something like...
world->Step(dt, 10, 10);
for(b2Body *b = world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *sprite = (CCSprite *)b->GetUserData();
sprite.position = ccp(b->GetPosition().x * PTM_RATIO,b->GetPosition().y * PTM_RATIO);
}
}
See how the code loops through all the box2d bodies in the word and sets the position of the sprite that is associated with the box2d body?
In my game every 2 seconds I create a new body and then I apply an impulse to this Box2d body.
My problem is that impulse is still the same, but the body behaves in two ways:
It slowly goes upwards , or another time it quickly falls down
I want the body to behave in the same way after impulse, is it possible?
Code:
- (void)newBullet
{
CGPoint touchedAt;
touchedAt.x = 184;
touchedAt.y = 1200;
bullet = [CCSprite spriteWithSpriteSheet:spriteSheet rect:CGRectMake(586, 719, 32, 32)];
[spriteSheet addChild: bullet z: 10 tag: 8];
bullet.position = ccp( touchedAt.x , touchedAt.y);
bullet.rotation = 90;
bulletBodyDef.type = b2_dynamicBody;
bulletBodyDef.position.Set(touchedAt.x / PTM_RATIO, touchedAt.y / PTM_RATIO);
bulletBodyDef.userData = bullet;
bulletBodyDef.angle = CC_DEGREES_TO_RADIANS( 90 );
bulletBody = _world->CreateBody(&bulletBodyDef);
b2CircleShape bulletShape;
bulletShape.m_radius = bullet.contentSize.width/PTM_RATIO/2;
b2FixtureDef bulletShapeDef;
bulletShapeDef.shape = &bulletShape;
bulletShapeDef.density = 0.0f;
bulletShapeDef.friction = 0.9f;
bulletShapeDef.restitution = 0.0f;
bulletShapeDef.isSensor = false;
bulletFixture = bulletBody->CreateFixture(&bulletShapeDef);
b2Vec2 force = b2Vec2(6.0f, 4.0f );
bulletBody->ApplyImpulse(force, bulletBody->GetPosition());
}
Video(Sorry for poor quality, but you can see what I mean)
http://vimeo.com/34215327
I don't know how you are calling this method, but I suggest that you have more control over where you call the method and where you do the box2d time step, it might not be related to that, but its worth checking out. What might be happening is that the impulse is not being applied because the solver which determines the speed of the body isn't called until you reset forces (which I assume you are doing), and so the effect is lost.