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).
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 the following function which initialises the scene in cocos2dxand to my knowledge i have done everything right. But my CCSprite is still not acting as a Physics body. It remains stationary in the centre of the screen whereas it should fall down and be affected by gravity.
Any help would be appreciated. Thanks in advance.
void HelloWorld::initPhysics()
{
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
CCSize screenSize = CCDirector::sharedDirector()->getWinSize();
//creating the world
b2Vec2 gravity;
gravity.Set(0.0f, -20.0f);
world = new b2World(gravity);
// Do we want to let bodies sleep?
world->SetAllowSleeping(true);
world->SetContinuousPhysics(true);
CCSprite* bird = CCSprite::create("Harry#2x.png");
bird->setScale(2.0);
bird->setPosition(ccp(visibleSize.width/2, visibleSize.height/2));
addChild(bird);
b2Body *_body;
// Create ball body and shape
b2BodyDef ballBodyDef;
ballBodyDef.type = b2_dynamicBody;
ballBodyDef.position.Set(screenSize.width,screenSize.height);
ballBodyDef.userData = bird;
_body = world->CreateBody(&ballBodyDef);
b2CircleShape circle;
circle.m_radius = 26.0/PTM_RATIO;
b2FixtureDef ballShapeDef;
ballShapeDef.shape = &circle;
ballShapeDef.density = 100.0f;
ballShapeDef.friction = 0.5f;
ballShapeDef.restitution = 0.7f;
_body->CreateFixture(&ballShapeDef);
}
Here is my update function and i have added the world variable as global.
void HelloWorld::update(float dt)
{
int velocityIterations = 8;
int positionIterations = 1;
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->setPosition( CCPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO) );
myActor->setRotation( -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()) );
}
}
}
Your b2World* world is a local variable. That means it'll be out of scope at the end of the current function, which indicates that you have no way of calling the world->Step(..) method which is the method you have to call regularly (every frame usually) in order to advance the physics world's state. Without stepping the world there will be no movement.
I have used soft body physics in my game to make ball.Now when ball falls down on some platforms which are also b2Bodies or on GrounBody it completely destroyed & it's shape also changed.
I have referred this link : http://www.uchidacoonga.com/2012/04/soft-body-physics-with-box2d-and-cocos2d-part-44/
but when i am trying to change some of values like radius,frequencyHz ,dampingRatio etc then it gives result as per my first image , in which my ball looks so unshaped & destructed .
- (void) createPhysicsObject:(b2World *)world {
// Center is the position of the circle that is in the center (inner circle)
b2Vec2 center = b2Vec2(240/PTM_RATIO, 160/PTM_RATIO);
b2CircleShape circleShape;
circleShape.m_radius = 0.20f;
b2FixtureDef fixtureDef;
fixtureDef.shape = &circleShape;
fixtureDef.density = 0.1;
fixtureDef.restitution = -2;
fixtureDef.friction = 1.0;
// Delta angle to step by
deltaAngle = (2.f * M_PI) / NUM_SEGMENTS;
// Radius of the wheel
float radius = 50;
// Need to store the bodies so that we can refer back
// to it when we connect the joints
bodies = [[NSMutableArray alloc] init];
for (int i = 0; i < NUM_SEGMENTS; i++) {
// Current angle
float theta = deltaAngle*i;
// Calculate x and y based on theta
float x = radius*cosf(theta);
float y = radius*sinf(theta);
// Remember to divide by PTM_RATIO to convert to Box2d coordinate
b2Vec2 circlePosition = b2Vec2(x/PTM_RATIO, y/PTM_RATIO);
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
// Position should be relative to the center
bodyDef.position = (center + circlePosition);
// Create the body and fixture
b2Body *body;
body = world->CreateBody(&bodyDef);
body->CreateFixture(&fixtureDef);
// Add the body to the array to connect joints to it
// later. b2Body is a C++ object, so must wrap it
// in NSValue when inserting into it NSMutableArray
[bodies addObject:[NSValue valueWithPointer:body]];
}
// Circle at the center (inner circle)
b2BodyDef innerCircleBodyDef;
// Make the inner circle larger
circleShape.m_radius = 0.8f;
innerCircleBodyDef.type = b2_dynamicBody;
// Position is at the center
innerCircleBodyDef.position = center;
innerCircleBody = world->CreateBody(&innerCircleBodyDef);
innerCircleBody->CreateFixture(&fixtureDef);
// Connect the joints
b2DistanceJointDef jointDef;
for (int i = 0; i < NUM_SEGMENTS; i++) {
// The neighbor
const int neighborIndex = (i + 1) % NUM_SEGMENTS;
// Get current body and neighbor
b2Body *currentBody = (b2Body*)[[bodies objectAtIndex:i] pointerValue];
b2Body *neighborBody = (b2Body*)[[bodies objectAtIndex:neighborIndex] pointerValue];
// Connect the outer circles to each other
jointDef.Initialize(currentBody, neighborBody,
currentBody->GetWorldCenter(),
neighborBody->GetWorldCenter() );
// Specifies whether the two connected bodies should collide with each other
jointDef.collideConnected = true;
jointDef.frequencyHz = 25.0f;
jointDef.dampingRatio = 0.5f;
world->CreateJoint(&jointDef);
// Connect the center circle with other circles
jointDef.Initialize(currentBody, innerCircleBody, currentBody->GetWorldCenter(), center);
jointDef.collideConnected = true;
jointDef.frequencyHz = 25.0;
jointDef.dampingRatio = 0.5;
world->CreateJoint(&jointDef);
}
}
This code give me the result as shown here.Is there any solution to avoid this situation ???
i want output like this
for that what changes i should made ? any suggestions !! please help.
i would also like to know the reason behind this.
It looks like the triangle fan is reacting with itself. Since you use a triangle fan to create a ball the triangles shouldn't interact, they are connected only. The code on the website you provided is a little bit different. After the first jointDef.Initialize the frequency and dampingRatio are 0.
But some other informations are missing like your NUM_SEGMENTS. Provide complete working code/functions (not the whole application), so someone other could compile and check it also.
I am doing one game. in that moving boy sprite with body created. the boy body when move front side or back side that will falling down.
How fix the body y axis 0?
CCSprite *boySprite=[CCSprite spriteWithFile:#"object_boy.png"];
boySprite.position=ccp(100,50);
b2BodyDef boyBodyDef;
boyBodyDef.type = b2_dynamicBody;
boyBodyDef.linearDamping = 1;
boyBodyDef.angularDamping = 1;
boyBodyDef.position.Set(25.0f/PTM_RATIO,(150)/PTM_RATIO);
boyBodyDef.angle=0;
boyBodyDef.userData = _boy;
boyBody = world->CreateBody(&boyBodyDef);
b2PolygonShape boyBox;
b2FixtureDef boyBoxDef;
boyBoxDef.shape = &boyBox;
boyBoxDef.density = 0.5F;
boyBox.SetAsBox(11.0f/PTM_RATIO, 30.0f/PTM_RATIO);
boyFixture = boyBody->CreateFixture(&boyBoxDef);
[self addChild:boySprite z:1];
Set fixedRotation in b2BodyDef to true.
boyBodyDef.fixedRotation = true;
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?