Box2d + CoCos2d: Moving an Object automatically to simulate computer movement in a game - cocos2d-iphone

I am working on a hockey game and I am implementing Single Player mode. I am trying to move the "computer's" paddle in offense mode (move towards the ball). I am using CoCos2d and Box2d. I am moving the paddle using MouseJoints. The problem is the Paddle doesnt move at all!
tick is called in init method
[self schedule:#selector(tick:)];
...
- (void)tick:(ccTime) dt
{
_world->Step(dt, 10, 10);
CCSprite *computer_paddle;
CCSprite *ball;
b2Body *computer_paddle_b2Body;
float32 direction;
b2Vec2 velocity;
for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *sprite = (CCSprite *)b->GetUserData();
if (sprite.tag == 1) { //ball
ball = sprite;
static int maxSpeed = 10;
velocity = b->GetLinearVelocity();
float32 speed = velocity.Length();
direction = velocity.y;
if (speed > maxSpeed) {
b->SetLinearDamping(0.5);
} else if (speed < maxSpeed) {
b->SetLinearDamping(0.0);
}
}
if (sprite.tag == 3){ // paddle
computer_paddle = sprite;
computer_paddle_b2Body = b;
}
// update sprite position
sprite.position = ccp(b->GetPosition().x * PTM_RATIO,b->GetPosition().y * PTM_RATIO);
sprite.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
// update the computer paddle in single player moving it towards the ball using MouseJoint
//move towards the ball
b2Vec2 b2Position = b2Vec2(ball.position.x/PTM_RATIO,ball.position.y/PTM_RATIO);
b2MouseJointDef md1;
md1.bodyA = _groundBody;
md1.bodyB = computer_paddle_b2Body;
md1.target = b2Position;
md1.collideConnected = true;
md1.maxForce = 9999.0 * computer_paddle_b2Body->GetMass();
_mouseJoint = (b2MouseJoint *)_world->CreateJoint(&md1);
computer_paddle_b2Body->SetAwake(true);

Check whether:
a) the body is sleeping
b) the body is a static body
If it is sleeping and you have no other bodies, disable sleeping entirely. Otherwise disable sleeping of the body: body->SetSleepingAllowed(NO)
Note: this is according to Box2D 2.2.1 API Reference which isn't the default in cocos2d 1.0 yet, so the function may be different in your Box2D version.
Also check that your body is dynamic by looking up the b2BodyDef's type member and, if necessary, set it to be dynamic (see the b2BodyType enumeration). I'm not sure what the default is, it should be dynamic but this may depend on the Box2D version.

Related

How to add sprite in box2d body (c++, cocos2d)?

setTouchEnabled(true);
ball=CCSprite::create("soccer_ball.png");
ball->setPosition(ccp(100,100));
addChild(ball,1);
//CREATE WORLD
b2Vec2 gravity(0, -9.8); //normal earth gravity, 9.8 m/s/s straight down!
bool doSleep = true;
myWorld = new b2World(gravity);
myWorld->SetAllowSleeping(doSleep);
//BODY DEFINITION
myBodyDef.type = b2_dynamicBody; //this will be a dynamic body
myBodyDef.position.Set(0, 20); //set the starting position
myBodyDef.angle = 0; //set the starting angle return true;
myBodyDef.userData=ball;
//CREATE SHAPE
b2CircleShape ballShape;
ballShape.m_p.Set(2.0f,3.0f);
ballShape.m_radius=50.0/PTM_RATIO;
//CREATE BODY
dynamicBody = myWorld->CreateBody(&myBodyDef);
//FIXTURE DEFINITION
b2FixtureDef ballFixtureDef;
ballFixtureDef.shape = &ballShape;
ballFixtureDef.density = 1;
dynamicBody->CreateFixture(&ballFixtureDef);
}
void HelloWorld::update()
{
float32 timeStep = 1/20.0; //the length of time passed to simulate (seconds)
int32 velocityIterations = 8; //how strongly to correct velocity
int32 positionIterations = 3; //how strongly to correct position
myWorld->Step( timeStep, velocityIterations, positionIterations);
}
I am learning box2d basic concepts and i have put my code here. I created a box2d circle shape. now i want to add sprite of ball in that circle shape. I have used myBodyDef.userData=ball; but it is not working .. i used gles-render code to debug draw but in that circle body is different and ball sprite is different. when i applyforce or impluse body works perfectly but dont attached to ball sprite..is any mistake in my code. I want to apply force to ball and ball should bounce according to physics but i can not attach to body plz help me.
Body and sprite looks like this
Here's my version working for V-3.6:
void GamePlayScreen::update(float dt) {
phyWorld->Step(dt, 8, 1);
// Iterate over the bodies in the physics phyWorld
for (b2Body* b = phyWorld->GetBodyList(); b; b = b->GetNext()) {
if (b->GetUserData() != NULL) {
// Synchronize the AtlasSprites position and rotation with the corresponding body
Sprite* sprActor = (Sprite*) b->GetUserData();
sprActor->setPosition(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
sprActor->setRotation(-1 * CC_RADIANS_TO_DEGREES(b->GetAngle()));
}
}
}

CCSprite not acting as Physics body in COCOS2dx?

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.

Moving a box2d object along the x axis while gravity pulls on the y axis

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));

Box2D object speed

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?

Tilemap platform collision detection with Cocos2d

I'm getting my feet wet with game development by working on a platformer using Cocos2d for iPhone. I'm struggling a bit in getting collision detection running so that my character will have his jump action cancelled when he hits a platform.
I'm using a technique from this tutorial where I create a separate layer of "meta tiles". The problem is that collision detection does not occur until the character sprite is well within the collidable tile, not on top of it.
I'm using the code below to determine the tile coordinate based on my character sprite's current position:
- (CGPoint) tileCoordForPosition: (CGPoint) position {
int x = position.x / tileMap.tileSize.width;
int y = ((tileMap.mapSize.height * tileMap.tileSize.height) - position.y) / tileMap.tileSize.height;
return ccp(x, y);
}
I tried various techniques, even trying to figure out what tile was below my character using this code:
- (void) update: (ccTime) dt {
BOOL isCollision = NO;
if (firstRun) {
oldY = player.position.y;
firstRun = NO;
}
CGPoint oneTileDown = ccp(player.position.x, player.position.y / 2);
CGPoint tileCoord = [gameplayLayer tileCoordForPosition:oneTileDown];
int tileGid = [gameplayLayer.meta tileGIDAt:tileCoord];
if (tileGid) {
NSDictionary* tileProperties = [gameplayLayer.tileMap propertiesForGID:tileGid];
if (tileProperties) {
NSString* collision = [tileProperties valueForKey:#"Collidable"];
if (collision && [collision compare:#"True"] == NSOrderedSame) {
//CCLOG(#"Collision Below");
isCollision = YES;
if (player.characterState == kStateFalling) {
[player stopAllActions];
}
}
}
}
if (oldY < player.position.y) {
CCLOG(#"Character is jumping");
player.characterState = kStateJumping;
}
else if (oldY > player.position.y) {
CCLOG(#"Character is falling");
player.characterState = kStateFalling;
}
oldY = player.position.y;
}
But the same problem happens: my character jumps, lands inside of the collision tile and is stopped instead of landing on top of the tile.
Is there a better way of checking for collision in a tilemap?
I have the solution to this issue.
In the method (CGPoint) tileCoordForPosition: (CGPoint) position you have to write the following:
int x = position.x / tileMap.tileSize.width;
int y = ((tileMap.mapSize.height * tileMap.tileSize.height + player.contenSize().height / 2) - position.y) / tileMap.tileSize.height;
return ccp(x, y);
player is a sprite from which you have to add half its height.
What you need to do is use CGRectContainRect to check if the player sprite's bounding box is intersecting with and of the tiles where it shouldn't.