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.
Related
I am developing a game recently (it's should be a space ship game like reassembly).
So my situation:
- i got 2 bodies with 0 restitution and 0 friction
- when they are colliding they slide and lose velocity because of my lineardumping
- but when 1 of them both is rotating (with setangularvelocity), they bounce off with a very high velocity and i can't figure out why they even bounce this hard.
( and i read that there should just be a little bouncing even if there is no restitution, but i am not expecting something like this)
here's some code:
b2PolygonShape shape;
b2BodyDef def;
def.type = b2_dynamicBody;
b2FixtureDef fix;
fix.density = 1.f;
fix.restitution = .0f;
fix.friction = 0.f;
bbody = world->CreateBody(&def);
bbody2 = world->CreateBody(&def);
bbody->SetLinearDamping(2.0f);
bbody2->SetLinearDamping(2.0f);
// PIXELPERMETER is the scaling from pixels to meter. (30)
shape.SetAsBox(32 / PIXELPERMETER/*=30*/, 32 / PIXELPERMETER);
fix.shape = &shape;
bbody->CreateFixture(&fix);
bbody2->CreateFixture(&fix);
bbody2->SetTransform(b2Vec2(-100 / PIXELPERMETER, 0), 0);
Maybe you should try to tweak the mass data of your bodies ?
b2MassData massData;
massData.mass = 50; //Just tweak me
massData.I = 1; //Just never set me to 0 if you don't want to have nAn propagating
massData.center = b2Vec2_zero;
bbody->SetMassData(&massData);
I need to throw my box2d object till off screen.
For example... Rabbit is moving straight on Jungle Path (Road length around 500 metres). In between it got some power to apply, like Axe. So rabbit need to throw that object forward till the off screen. If any bouncable object (like wall and tree) in midway, thrown object need to come back, else it should go to off screen and hide.
At touch event I called below method to create body and for movement I used setlinear velocity.. but it's not moving straight and smooth; then inbetween if any objects (like wall and tree). How to bounce back (reverse travel)?
[self createbody];
-(void) createbody
{
freeBodySprite = [CCSprite spriteWithFile:#"blocks.png"];//web_ani_6_1
//freeBodySprite.position = ccp(100, 300);
[self addChild:freeBodySprite z:2 tag:6];
CGPoint startPos = CGPointMake(100, 320/1.25);
b2BodyDef bodyDef;
bodyDef.type = b2_staticBody;
bodyDef.position = [self toMeters:startPos];
bodyDef.userData = freeBodySprite;
b2CircleShape shape;
float radiusInMeters = ((freeBodySprite.contentSize.width * freeBodySprite.scale/PTM_RATIO) * 0.5f);
shape.m_radius = radiusInMeters;
b2FixtureDef fixtureDef;
fixtureDef.shape = &shape;
fixtureDef.density = 0.07f;
fixtureDef.friction = 0.1f;
fixtureDef.restitution = 0.1f;
b2Fixture *stoneFixture;
circularObstacleBody = world->CreateBody(&bodyDef);
stoneFixture = circularObstacleBody->CreateFixture(&fixtureDef);
freeBody = circularObstacleBody;
}
-(b2Vec2) toMeters:(CGPoint)point
{
return b2Vec2(point.x / PTM_RATIO, point.y / PTM_RATIO);
}
I am bit confused. How to achieve the above requirement ?
I refer this link:- Box2d object throwing smoother and on same velocity
First, In your Code, u didnt show your movement code(where u used that Linear Velocity)
b2vec2 *move = (30,0);
cart->SetLinearVelocity(move);
above code will move your box2d body with 30 velocity in x axis. when ever any object occurs in middle of road. u need to handle those in below methods
void LevelContactListener::BeginContact(b2Contact* contact)
void LevelContactListener::EndContact(b2Contact* contact)
u will get Fixtures from above method. based on that handle the collisons.(i.e.,) your box2d body(player power) and those road objects collided. set the power to reverse direction (-velocity).
You can set friction to 0 and body will nicely bouncing from walls.
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(100/PTM_RATIO, 100/PTM_RATIO);
b2Body * body = _world->CreateBody(&bodyDef);
b2CircleShape circle;
circle.m_radius = 26.0/PTM_RATIO;
b2FixtureDef ShapeDef;
ShapeDef.shape = &circle;
ShapeDef.density = 1.0f;
ShapeDef.friction = 0.f;
ShapeDef.restitution = 1.0f;
b2Fixture *bodyFixture = body->CreateFixture(&ShapeDef);
To create walls you need create ground body for example:
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0,0);
_groundBody = _world->CreateBody(&groundBodyDef);
b2EdgeShape groundBox;
b2FixtureDef groundBoxDef;
groundBoxDef.shape = &groundBox;
groundBox.Set(b2Vec2(0,0), b2Vec2(winSize.width/PTM_RATIO, 0));
_bottomFixture = _groundBody->CreateFixture(&groundBoxDef);
groundBox.Set(b2Vec2(0,0), b2Vec2(0, winSize.height/PTM_RATIO));
_groundBody->CreateFixture(&groundBoxDef);
groundBox.Set(b2Vec2(0, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO,
winSize.height/PTM_RATIO));
_groundBody->CreateFixture(&groundBoxDef);
groundBox.Set(b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO),
b2Vec2(winSize.width/PTM_RATIO, 0));
_groundBody->CreateFixture(&groundBoxDef);
You may add distance joint that will pull object back to the initial position upon its first contact with other collider (see contact listener for details).
I think it is possible to have persistent joint connected your player with throwable object. You just have to handle joint limits (distance) and behaviour (spring and damper).
As I am newbie to cocoa2d I am struggling alot to rotate the physics or dynamic body along an arc path.
The way I tried is as follows:
#define COS_ANIMATOR(position, timeCount, speed, waveMagnitude) ((cosf(timeCount * speed) * waveMagnitude) + position)
#define SIN_ANIMATOR(position, timeCount, speed, waveMagnitude) ((sinf(timeCount * speed) * waveMagnitude) + position)
CCSpriteBatchNode *pipe_parent = [CCSpriteBatchNode batchNodeWithFile:#"pipe.png" capacity:100];
CCTexture2D *pipeSpriteTexture_ = [pipe_parent texture];
PhysicsSprite *pipeSprite = [PhysicsSprite spriteWithTexture:pipeSpriteTexture_ rect:CGRectMake(0 ,0 ,55,122)];
//pipe = [CCSprite spriteWithFile:#"pipe.png"
// rect:CGRectMake(0, 0, 55, 122)];
[self addChild:pipeSprite];
// pipe.position = ccp(s.width/2 , 420.0);
b2BodyDef myBodyDef;
myBodyDef.type = b2_staticBody; //this will be a dynamic body
myBodyDef.position.Set(((s.width/2) - 90)/PTM_RATIO, 420.0/PTM_RATIO); //set the starting position
myBodyDef.angle = 0; //set the starting angle
b2Body* staticBody = world->CreateBody(&myBodyDef);
b2PolygonShape boxShape;
boxShape.SetAsBox(1,1);
b2FixtureDef boxFixtureDef;
boxFixtureDef.shape = &boxShape;
boxFixtureDef.density = 1;
boxFixtureDef.userData = pipeSprite;
boxFixtureDef.filter.groupIndex = -1;
staticBody->CreateFixture(&boxFixtureDef);
[pipeSprite setPhysicsBody:staticBody];
-(void) draw
{
//
// IMPORTANT:
// This is only for debug purposes
// It is recommend to disable it
//
[super draw];
const CGPoint newSpritePosition = ccp(COS_ANIMATOR(150, mTimeCounter, 0.05,50), SIN_ANIMATOR(400, mTimeCounter, -0.05, 50));
pipeSprite.position = newSpritePosition;
ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
kmGLPushMatrix();
world->DrawDebugData();
kmGLPopMatrix();
}
on following this approach my sprite rotating in circular motion instead of rotating in an arc path.
Please give your ideas or suggestions.
Thanks all
I'm not entirely sure what it is you are looking to accomplish when you talk about rotating in an arc path. I only see you setting a position, not a rotation, so are you just wanting to set a position, or a rotation, or both? Your position code looks like you are trying to achieve a circular (or elliptical) path because you are using the sine and cosine in the x,y position.
If you're looking to move a sprite along a sine curve, I did that today and it took a bit of trial and error. I had some variables for the amplitude and period, and from there I traced out a nice sine curve movement in the sprite's update: method.
CGPoint initialPosition; // set this to the sprite's initial position
float amplitude; // in points
float period; // in points
float y, x = initialPosition.x;
-(void) update:(ccTime)dt
{
x += dt * 100; // speed of movement across the screen. Picked by trial and error.
y = initalPosition.y + amplitude * sinf((x - initialPosition.x)/period);
sprite.position = ccp(x,y);
sprite.rotation = cosf((x - initialPosition.x)/period); // optional if you want to rotate along the path as well
}
Don't know if this is anything you are looking for but it might give you some ideas.
Currently, in cocos2d, I have a an app that does the following:
Initiate with a Blank Screen.
When I tap the screen, I get a circle to pop-up. As I hold the circle, the circle will continue to grow at a constant rate. However, despite the fact that the sprite is growing, the box2d physical body isn't, which means that the sprite will not collide with other bodies. I been trying to figure out a way to change the radius that scales with the sprite but no such question exist here for cocos2d. I have noticed other box2d for things other than cocos2d but I am having a hard time translating them over.
//smile.position = ccp(touchLocation.x, touchLocation.y);
smile.scale = .05;
[self addChild:smile];
// b2BodyDef smileBodyDef;
smileBodyDef.type = b2_dynamicBody;
smileBodyDef.position.Set(touchLocation.x/PTM_RATIO, touchLocation.y/PTM_RATIO);
smileBodyDef.userData = smile;
smileBody = world->CreateBody(&smileBodyDef);
//Radius
b2CircleShape smileCircleShape;
int radius = 80;
//Fixture
smileFixtureDef.shape = &smileCircleShape;
smileFixtureDef.density = 0.00f;
smileFixtureDef.friction = .2f;
smileBody->CreateFixture(&smileFixtureDef);
if (CGRectContainsPoint(smileRect, touchLocation)) {
growForever = [CCRepeatForever actionWithAction: [CCScaleBy actionWithDuration: .5 scale: 1.2]];
[growForever setTag:1];
[smile runAction:growForever];
Each time you want to change your radius, grab the shape object associated with the b2Fixture that you created for your body, and then set the new value accordingly:
fixture->GetShape()->m_radius = new_radius/PTM_RATIO;
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?