character gets stuck walking across multiple box2d bodies

Forums Programming physics: Box2d, Chipmunk et al character gets stuck walking across multiple box2d bodies

This topic contains 9 replies, has 4 voices, and was last updated by  rohin 1 year, 8 months ago.

Viewing 10 posts - 1 through 10 (of 10 total)
Author Posts
Author Posts
February 20, 2012 at 7:51 am #239322

chadwyk
Participant
@chadwyk

Hello all. I’ve been working on this problem but can’t find a solution. Maybe I’m just not searching for the right thing in the forums, but here is my situation.

I have a tiled level with a tmx map. Each tile for the ground is parsed and has a box2d body. That works great. However, when my character walks along the ground, he sometimes comes to a complete halt at the start of a new tile’s body. It’s like one body is higher than the other, which isn’t the case, they all have the same Y value and height. To move my character, I am applying a linear force in the direction that I want him to move. If he gets stuck I can back up and go forward again and he usually goes then, like it may be a momentum issue? I don’t know. I played with the friction values on both my character and the ground’s bodies thinking that might help but that didn’t seem to do anything different other than make him slide a little bit. He still would get stuck.

The other thing I notice is that when he is able to walk along, he seems to slow down and speed up slightly even though I’m applying a steady linear force to him.

Any help would be appreciative.

thanks

February 20, 2012 at 8:18 am #366225

chadwyk
Participant
@chadwyk

Hmmm.. I may have found the solution. Apparently this is a known issue when using character shapes that are rectangular over rectangular tiles.

From the box2d FAQ:

Using many boxes for your terrain may not work well because box-like characters can get snagged on internal corners. A future update to Box2D should allow for smooth motion over edge chains. In general you should avoid using a rectangular character because collision tolerances will still lead to undesirable snagging.

For more information see this post: http://box2d.org/forum/viewtopic.php?f=3&t=3048

I’m not sure if this future fix has already been implemented or not as the link goes to posts that were dated in 2010. But if it’s as simple as changing the shape of my character, that should be simple enough I hope. I’ll try it in the morning.

February 20, 2012 at 2:58 pm #366226

Jan
Keymaster
@jan

what kind of shape are you using for your cahracter? a simple box can result in this kind of problems.

February 20, 2012 at 3:03 pm #366227

Jan
Keymaster
@jan

example of something i used in the past.

b2PolygonShape dynamicBox;</p>

<p>b2Vec2 boxVertices[8];

boxVertices[0].Set(-0.5f, -0.75f);

boxVertices[1].Set(-0.25f, -0.975f);

boxVertices[2].Set(0.25f, -0.975f);

boxVertices[3].Set(0.5f, -0.75f);

boxVertices[4].Set(0.5f, 0.9f);

boxVertices[5].Set(0.4f, 0.975f);

boxVertices[6].Set(-0.4f, 0.975f);

boxVertices[7].Set(-0.5f, 0.9f);

dynamicBox.Set(boxVertices, 8);

it’s like a simplified rounded box. that helped me with similar problems.

the radius of the corners can add a cool behaviour… the character can slide down on edges of terrain-blocks. but it is not good for all scenarios.

February 20, 2012 at 3:09 pm #366228

itlgames
Moderator
@itlgames

I’ve actually had same problem. First thing I tried was to make the character a rounded corner rectangle. Worked ok, but gave me other issues, not nice ones. Then I found out that if you build your terrain tiles as edges instead, it works perfectly!! And your character can be a straight rectangle.

Anyway a good improvement you should do is build all consecutive terrain tiles of same type in rows in one single body. that will improve performance if you have a big map.

February 20, 2012 at 5:30 pm #366229

chadwyk
Participant
@chadwyk

Thanks! I think I’m going to do a combination of the two. I tried rounding the corners like @nf said, and that seems to have worked. I have a few different tilesets which serve as platforms, some that can be smashed, so some need their individual bodies still. I am getting 60fps, but I should probably still link the tiles that don’t get smashed by parsing them out and link them together. I just need to figure out edges now!

February 20, 2012 at 8:39 pm #366230

itlgames
Moderator
@itlgames

If it helps, this is how I converted a normal shape to edges:

b2PolygonShape shape;
shape.SetAsBox(size.width/PTM_RATIO, size.height/PTM_RATIO);
b2FixtureDef fixtureDef;
fixtureDef.shape = &shape;
fixtureDef.density = 1.0;
fixtureDef.friction = 0.0;
fixtureDef.restitution = 0.0;
body->CreateFixture(&fixtureDef);

to:

b2Vec2 lowerLeft = b2Vec2(0 - (size.width/PTM_RATIO), 0 - (size.height/PTM_RATIO));
b2Vec2 lowerRight = b2Vec2(size.width/PTM_RATIO, 0 - (size.height/PTM_RATIO));
b2Vec2 upperRight = b2Vec2(size.width/PTM_RATIO, size.height/PTM_RATIO);
b2Vec2 upperLeft = b2Vec2(0 - (size.width/PTM_RATIO), size.height/PTM_RATIO);

b2EdgeShape groundBox;

// bottom
groundBox.Set(lowerLeft, lowerRight);
body->CreateFixture(&groundBox,0);

// top
groundBox.Set(upperRight, upperLeft);
body->CreateFixture(&groundBox,0);

// left
groundBox.Set(upperLeft, lowerLeft);
body->CreateFixture(&groundBox,0);

// right
groundBox.Set(lowerRight, upperRight);
body->CreateFixture(&groundBox,0);

With this, I didn’t need to round the corners of the player or platforms. Some issues I had with the rounded corners rectangle were some undesired bounces back, and not falling in one-tile gaps.

February 20, 2012 at 10:53 pm #366231

chadwyk
Participant
@chadwyk

Did you upgrade your cocos2d to the 2.0 beta or did you manually upgrade your box2d version? b2EdgeShape isn’t in the box2d version with cocos2d 1.0.1

February 21, 2012 at 9:14 am #366232

itlgames
Moderator
@itlgames

Yes I upgraded to latest version of Box2D, I’m using cocos2d v1.1

August 19, 2012 at 4:24 am #366233

rohin
@rohin

Switching to edges solved the problem for me too. Here’s the code I’m using:

void Level::createTileBodyAtIndex(int x, int y) {
bool hasLeftEdge = x > 0 && layer->tileGIDAt(ccp(x - 1, y)) == 0;
bool hasRightEdge = x < map->getMapSize().width - 1 && layer->tileGIDAt(ccp(x + 1, y)) == 0;
bool hasTopEdge = y > 0 && layer->tileGIDAt(ccp(x, y - 1)) == 0;
bool hasBottomEdge = y < map->getMapSize().height - 1 && layer->tileGIDAt(ccp(x, y + 1)) == 0;

if (hasLeftEdge || hasRightEdge || hasTopEdge || hasBottomEdge) {
static CCSize tileSize = this->map->getTileSize();
static float leftX = -((tileSize.width * 0.5) / PTM_RATIO);
static float rightX = (tileSize.width * 0.5) / PTM_RATIO;
static float topY = (tileSize.width * 0.5) / PTM_RATIO;
static float bottomY = -(tileSize.width * 0.5) / PTM_RATIO;

CCPoint p = layer->positionAt(ccp(x,y));

b2BodyDef bd;
bd.position.Set((p.x + tileSize.width * 0.5) / PTM_RATIO, (p.y + tileSize.height * 0.5) / PTM_RATIO);
b2Body* tileBody = world->CreateBody(&bd);

b2EdgeShape shape;
b2FixtureDef sd;
sd.shape = &shape;
sd.density = 0.0f;
sd.restitution = 0.0f;

if (hasLeftEdge) {
shape.Set(b2Vec2(leftX, bottomY), b2Vec2(leftX, topY));
tileBody->CreateFixture(&sd);
}

if (hasRightEdge) {
shape.Set(b2Vec2(rightX, bottomY), b2Vec2(rightX, topY));
tileBody->CreateFixture(&sd);
}

if (hasTopEdge) {
shape.Set(b2Vec2(leftX, topY), b2Vec2(rightX, topY));
tileBody->CreateFixture(&sd);
}

if (hasBottomEdge) {
shape.Set(b2Vec2(leftX, bottomY), b2Vec2(rightX, bottomY));
tileBody->CreateFixture(&sd);
}
}
}

Viewing 10 posts - 1 through 10 (of 10 total)

You must be logged in to reply to this topic.