Create Box2D bodies with TMX Objects layer! Cocos2d-x 3.0

Create Box2D bodies with TMX Objects layer! Cocos2d-x 3.0
0

#1

Hello there,

I have made a class which allows you to create Box2D bodies for a object layer. I have made this because I have needed this myself and this would be a huge time saver for me and I hope for you also.

This class supports the following objects,

  • Rectangle
  • Circle (You can create it with any shape set “Type” parameter to “Circle” and it creates a Circle fixture based on width as diameter)
  • Polygon (Allowed only per 8 points, I you need more then you have to split it up)
  • Polyline

How it works:

In you tmx editor you have to create a layer called “Collision” and make all the objects in that layer.

Change in TiledBodyCreator.cpp
#define PTMRATIO 64
To your ptmratio

Then in the game code you have to include TiledBodyCreator.h and after you have created Tilemap and Box2d world you can add this code which will create a body with all objects as fixtures in it and add it to world.

TiledBodyCreator::initCollisionMap(map, world);

Here is a small preview of what I have tested
My tiled map in editor

My game with box2d debug

This is the code I have used

this->setAnchorPoint(Point::ZERO);

b2Vec2 gravity;
gravity.Set(0.0f, -10.0f);
auto world = new b2World(gravity);

world->SetAllowSleeping(false);


auto debugLayer = B2DebugDrawLayer::create(world, 64);
this->addChild(debugLayer, 9999);

auto map = TMXTiledMap::create("Test.tmx");
map->setAnchorPoint(Point::ZERO);
map->setPosition(0,0);

this->addChild(map, 3);

TiledBodyCreator::initCollisionMap(map, world);

this->setScale(0.2f);

I hope this helped you a lot. :slight_smile:
The classes are added to attachments of this post.


TiledPreview.PNG (147.8 KB)


GamePreview.PNG (37.7 KB)


TiledBodyCreator.zip (1.8 KB)

you can find the newer version of TiledBodyCreator here


#2

This is very useful. Thank you for sharing.


#3

Great! :slight_smile:


#4

Good Effort mate…

But cant create PolyLine Bodies with it…
Fails at this line in b2ChainSpae.cpp CreateChain method :
b2Assert(m_vertices == NULL && m_count == 0);

Check Screenshot for more Info on error :


#5

@rammehta

Hey, sorry for a late reaction.
Could you mayby check if your tiledmap contains empty polylines or mayby open your tmx file with a text editor and send me collision layer part of it. You can also try to replace createPolyline method in TiledBodyCrator.cpp with this and send me the log:

FixtureDef* TiledBodyCreator::createPolyline(ValueMap object)
{
	ValueVector pointsVector = object["polylinePoints"].asValueVector();
	auto position = Point(object["x"].asFloat() / PTMRATIO, object["y"].asFloat() / PTMRATIO);
	CCLOG("Size of pointsVector: %f", pointsVector.size());

	b2ChainShape *polylineshape = new b2ChainShape();
	float verticesSize = pointsVector.size()+ 1;
	b2Vec2 vertices[30];
	int vindex = 0;

	auto fix = new FixtureDef();

	for(Value point : pointsVector) {
		CCLOG("Initializing vector at index: %d", vindex);
		vertices[vindex].x = (point.asValueMap()["x"].asFloat() / PTMRATIO + position.x);
        vertices[vindex].y = (-point.asValueMap()["y"].asFloat() / PTMRATIO + position.y);
		vindex++;
	}

	polylineshape->CreateChain(vertices, vindex);
	fix->fixture.shape = polylineshape;

	return fix;
}

#6

GOT THE ANSWER…


#7

And verticesSize is never used…


#8

@rammehta
Oh, thats it a actually forgot to remove it. Good job :slight_smile:


#9

Thanks for this thread, it saves me tons of time >:D<

But I suggest you change method createPolyline() as below:

b2Vec2 vertices[30];

–>

int verticesCapacity=32;
b2Vec2* vertices = (b2Vec2*)calloc(verticesCapacity, sizeof(b2Vec2));

and

for(Value point : pointsVector) {
CCLOG(“Initializing vector at index: %d”, vindex);

–>

for(Value point : pointsVector) {
CCLOG(“Initializing vector at index: %d”, vindex);
if(vindex>=verticesCapacity)
{
verticesCapacity+=32;
vertices = (b2Vec2*)realloc(vertices, verticesCapacity*sizeof(b2Vec2));
}

so that you can use polylines which have more than 30 vertices (with origin method app will crash in this case).


Help me, Parallax Node and Box2D
#10

Thanks for this tweak. Here is the version with your changes I am sure it will help a lot of people :). I am also glad to hear its useful to you.TileBodyCreator.zip (1.8 KB)


#11

Hello.
if my tiled object with code

 <objectgroup name="Object" width="500" height="20">
  <object x="1976" y="310"/>
  <object x="3495" y="315"/>
  <object x="4716" y="311"/>
.....
 </objectgroup>

In function createRect(ValueMap object) , with and height will have value = 0 and an exception will occur. Please fix and thanks for sharing :smile:


#12

It works like a charm. Kudos!


#13

Where I can find this B2DebugDrawLayer?
I didn’t find it in Box2D library.
Please help


#14

no problem, I found it here.
B2DebugDrawLayer


#15

uhm…
it doesn’t display any debug draw order in 3.5

I added a log and I found it is not working.
It is considered as NULL.

void TiledBodyCreator::initCollisionMap(TMXTiledMap* map, b2World* world)
{
auto collisionGroup = map->getObjectGroup(“coll”);
cocos2d::ValueVector collisionObjects = collisionGroup->getObjects();

b2BodyDef bd;
auto collisionBody = world->CreateBody(&bd);
for(cocos2d::Value objectValue : collisionObjects)
{
    auto fixtureShape = createFixture(objectValue.asValueMap());
    if(fixtureShape != NULL) {
        collisionBody->CreateFixture(&fixtureShape->fixture);
        log("NULL here!");
    }
}

}


#16

no, problem.
it’s my fault.
your code is working, thank you @egordm

Does anyone know why does my box collision on bunny is not aligned with bunny?
I used PTM_RATIO 128.
And the bunny is shaking.
I used

bodyHero->SetLinearVelocity(b2Vec2(0.0f, -2.50f));

The bunny is 128 x 128 pixel.
The location is 640, 360.
I divided the location with PTM_RATIO 128, but still doesn’t match.
It doesn’t align with box2D rect.

Is there a bug in Box2D?

I updated its position:

auto sp = (Sprite *)body->GetUserData();
sp->setPosition(Vec2(body->GetPosition().x * PTM_RATIO, body->GetPosition().y * PTM_RATIO));
sp->setRotation(-1 * CC_RADIANS_TO_DEGREES(body->GetAngle()));
body->SetLinearVelocity(b2Vec2(0.0f, -1.0f));


#17

I know now. This is a bug.
When I tried to use circle, the circle aligns perfectly with the image (bunny).
Problem solved now.
If I used rectangle, I need to multiply the PTM_RATIO to match the body position.


#18

Hi,
I’m trying to use TileBodyCreator but it doesn’t work for me.
Anyone are using this class ?? with cocos2d-x 3.17, etc.
In my tiled map i created the object “Collision”, polylines, etc but i can’t detect the collisions by code…

edit: the problem was mine, it works!


Problems with tiled maps
Problems with tiled maps