• Editor
  • Help With Box2d body attachments

Hey everyone,

I'm having a problem properly creating Box2d bodies on my animation. I've followed the Java tutorial but, and this is probably me, but I'm clearly losing something in translation.

As you can see from the screenshot I've attached above, the bodies aren't in the right spot and don't reflect the shape of the animation. Below is the code I'm using to set up the bodies.

for (int i = 0; i < this->skeleton->slotCount; i++) {
		Slot* slot = this->skeleton->slots[i];
		if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
		
	RegionAttachment* attachment = (RegionAttachment*)slot->attachment;
	
	CCLog("Adding body shape: %s, width: %f, height: %f", attachment->super.name, attachment->width * attachment->scaleX, attachment->height * attachment->scaleY);
	
	b2PolygonShape boxPoly;
	boxPoly.SetAsBox(attachment->regionWidth / PTM_RATIO,
					 attachment->regionHeight / PTM_RATIO,
					 b2Vec2((attachment->x + attachment->regionOffsetX) / PTM_RATIO, (attachment->y + attachment->regionOffsetY) / PTM_RATIO),
					 attachment->rotation*3.14159265/180);
	
	
	b2BodyDef boxBodyDef;
	b2Body *box = world->CreateBody(&boxBodyDef);
	box->CreateFixture(&boxPoly, 1);
}

The screen shot below shows the actual attachments with debugSlots set to true.

Can anyone help with this? I've been beating my head against this for a couple of days now and this is the closest I've gotten to having anything. Any help would be extremely appreciated.

Related Discussions
...

The attachment (blue boxes) are in the right place, so he's calling updateWorldTransform. Actually, maybe he isn't calling updateWorldTransform until after positioning the box2d bodies?

I would suggest a simpler skeleton with just a single box and attachment. Get that working, then move on to a more complex skeleton.

Thanks for your replies, guys. I've actually decided to go a much simpler route for physics because, honestly, I don't need every attachment to be a a physical structure.

If you look at the screenshot below, you can see how I've built the new body and added a couple of sensors (for punching collisions).

Essentially, I subclassed CCSkeletonAnimation and added a weak reference to the b2Body (among other things) and a method which sets up the body for being added to the world.

If anyone's interested, I can post the code. But the result is what's below.

I'm interested in the code if you're still up to uploading it. I'm experimenting with Box2D integration at the moment as well and the more code I can see and play with the better. Glad you got your problem solved though!

Sure thing. It's not perfect yet, but this is basically how I put together the body and fixtures. Basically, I subclassed CCSKeletonAnimation and added the method setBody(). The left and right sensors match up with where his fists are when punching and, if his "punching" boolean is false, then I just ignore contacts there. Or... at least that's the idea.

void Hero::setBody(b2World *world) {
        b2PolygonShape boxPoly;
	boxPoly.SetAsBox((40 * CC_CONTENT_SCALE_FACTOR()) / PTM_RATIO, (100 * CC_CONTENT_SCALE_FACTOR()) / PTM_RATIO);
	

b2BodyDef boxBodyDef;
boxBodyDef.userData = this;
boxBodyDef.type = b2_dynamicBody;
boxBodyDef.fixedRotation = true;
boxBodyDef.allowSleep = true;
float tmpX = this->getPositionX() / PTM_RATIO;
float tmpY = this->getPositionY() / PTM_RATIO;

boxBodyDef.position.Set(tmpX, tmpY);
b2Body *box = world->CreateBody(&boxBodyDef);

box->CreateFixture(&boxPoly, 1);

float leftRightBoxSize = (10 * CC_CONTENT_SCALE_FACTOR()) / PTM_RATIO;
b2PolygonShape rightSensorShape;
rightSensorShape.SetAsBox(leftRightBoxSize, leftRightBoxSize, b2Vec2(1.9, 0.8), 0);

b2FixtureDef rightSensorDef;
rightSensorDef.isSensor = true;
rightSensorDef.shape = &rightSensorShape;

b2Fixture *rightSensor = box->CreateFixture(&rightSensorDef);

b2PolygonShape leftSensorShape;
leftSensorShape.SetAsBox(leftRightBoxSize, leftRightBoxSize, b2Vec2(-1.9, 0.8), 0);

b2FixtureDef leftSensorDef;
leftSensorDef.isSensor = true;
leftSensorDef.shape = &leftSensorShape;

b2Fixture *leftSensor = box->CreateFixture(&leftSensorDef);
}

The only problem with this code at the moment is that when I feed it's position data to the sprite, it's currently giving me the Y coord in the center of the box. I'm working on it and will post an update when I have it down.

Just an update with better code, in case anyone's interested. For my sprite, this fixture perfectly matches the general outline of my hero and all the coordinates match correctly.

void Hero::setBody(b2World *world) {
	float definedHeight = (100 * CC_CONTENT_SCALE_FACTOR()) / PTM_RATIO;
	b2PolygonShape boxPoly;
	boxPoly.SetAsBox((40 * CC_CONTENT_SCALE_FACTOR()) / PTM_RATIO,
					 definedHeight,
					 b2Vec2(0.0, definedHeight),
					 0.0f);
	

b2BodyDef boxBodyDef;
boxBodyDef.userData = this;
boxBodyDef.type = b2_dynamicBody;
boxBodyDef.fixedRotation = true;
boxBodyDef.allowSleep = true;
float tmpX = this->getPositionX() / PTM_RATIO;
float tmpY = this->getPositionY() / PTM_RATIO;

boxBodyDef.position.Set(tmpX, tmpY);
this->body = world->CreateBody(&boxBodyDef);

b2Fixture *mainBody = this->body->CreateFixture(&boxPoly, HERO_DENSITY);
mainBody->SetRestitution(0.0f);
CCLog("Estimated sprite size: W: %f, H: %f", width, height);


float leftRightBoxSize = (10 * CC_CONTENT_SCALE_FACTOR()) / PTM_RATIO;
b2PolygonShape rightSensorShape;
rightSensorShape.SetAsBox(leftRightBoxSize, leftRightBoxSize, b2Vec2(1.9, 0.8 + definedHeight), 0);

b2FixtureDef rightSensorDef;
rightSensorDef.isSensor = true;
rightSensorDef.shape = &rightSensorShape;
rightSensorDef.density = 0.0f;

b2Fixture *rightSensor = this->body->CreateFixture(&rightSensorDef);

b2PolygonShape leftSensorShape;
leftSensorShape.SetAsBox(leftRightBoxSize, leftRightBoxSize, b2Vec2(-1.9, 0.8 + definedHeight), 0);

b2FixtureDef leftSensorDef;
leftSensorDef.isSensor = true;
leftSensorDef.shape = &leftSensorShape;
leftSensorDef.density = 0.0f;

b2Fixture *leftSensor = this->body->CreateFixture(&leftSensorDef);
}

Just came back from a few days absence, thanks for putting up the code! I definitely appreciate it 🙂

Tetheta wrote

Just came back from a few days absence, thanks for putting up the code! I definitely appreciate it 🙂

No worries. Just one thing I found when device testing, ignore the stupid CC_CONTENT_SCALE_FACTOR() stuff. All it did was screw things up.

I hope if you make any discoveries you'll share too. We'll all be better off for it.

Will do, so far just trying to get everything I'm using to work together. Had everything working then started it up this morning and suddenly Cocos2D can't find any of my spritesheets so we'll see if I can get that figured out, odd errors everywhere haha.

1ヶ月 後

Hi spudworks, thanks for sharing your code and experience.

I am just getting started at integrating my own spine skeleton/animation into my box2d game and am pretty pumped at the possibilities. Is this still the best tutorial to work from before following your additional example?

https://github.com/EsotericSoftware/spi ... Box2D.java

Thanks for the help

Hey,

I am having similar issues as spudworks with the box2d fixtures being placed incorrectly.

I am trying to use a single body with each spine region attachment added a box2d fixture to that body.
This is what it looks like for just the first attachment.

HTTPS をサポートしていないため、画像は非表示になっています。 | まだ表示する

That is the lower left leg, and the rotation is incorrect. I am not sure if I need to account for the slot's rotation and/or the bone rotation/worldRotation

I am working in cocos2d-x, but the code should be self explanatory:

float angle = CC_DEGREES_TO_RADIANS(attachment->rotation);
...
shape.SetAsBox(w, h, *center, angle);

I am trying to copy the logic from here:
https://github.com/EsotericSoftware/spine-workshop/blob/master/src/com/esotericsoftware/spine/workshop/I_Box2D.java

Though in that example, each region is added as a separate body in box2d, whereas I would like a single body with multiple fixtures.

Any help appreciated
Thanks

I think the problem with setting each attachment as a fixture is that you can't set positions on fixtures like you can on bodies. I was just playing with the code and wasn't finding an immediate way to manipulate a fixture in this way.

As to your previous post, yeah, I think that's still the best tutorial. When Spine (and the development community around it) grows a bit more, hopefully we'll get something a little clearer and without all the Java specific stuff. Personally, I find it easier to see something in C and turn it into Java than the other way around.

Hey,

yeah I think you are right. I know you can set the position of fixtures at creation time, but hadn't thought of changing their positions later as the skeleton animates. It sounds like multiple bodies instead of fixtures is the way to go. This game happens to work that way:
http://box2d.org/forum/viewtopic.php?f=6&t=9314

Again, this one, http://www.iforce2d.net/blog/2011-08-28, demoing a boxing concept was constructed using joints to connect the bodies.

So it sounds like the multiples fixtures was going down the wrong path. I'll try it out using multiple bodies

Another related question I had was... does it matter where the root bone is positioned? The Spineboy example has the root bone at the bottom of the skeleton, basically below his feet. I created mine with the root bone basically at the same spot as the hip pelvis

Am I correct in thinking the only thing that this will affect is the adjustment I need to make to position the sprite in my game? In the cocos2d-x runtime, sprites are anchored at the center of their node by default which means making my root bone anchored at the centered of my skeleton more consistent.

The origin in Spine is 0,0. This is the reference point used at runtime to position the skeleton. The root bone is a bone like any other (except it has no parent) and is place relative to 0,0.

Ok, thanks Nate.

I have it implemented successfully now, with the box2d bodies positioned at each skeleton region and animated along with them. My original issue was simply that I was trying to verify one step at a time, and the bodies weren't properly rotated until the transformations in the update() method in the java example.

I do have another issue now, and that is with flipping the character horizontally. I've used

skeleton->flipX

to flip the animation. As I understand it though, there is no easy translation in box2d, as there are only transforms. Thus my bodies are messed up as soon as my character walks left.

I've read a couple suggested options, and that is to destroy and recreate the box2d bodies/shapes when changing direction, or maintain two separate body structures (one for right and one for left animations) and swap them in and out when necessary. I don't really like either and it is starting to seem I am fighting against the physics sim rather than working with it. For one, using static bodies for each region part was already less than ideal.

I think I am starting to settle on the same solution spudworks gave, and that is a much simpler dynamic body structure with minimal added fixtures/sensors for other body parts I want to interact with specifically (the head perhaps). If anyone had tips on using the more complex body structure, that would also be appreciated.

This is turning into more of a box2d specific discussion than Spine related, so I'll try to post only Spine related questions further in this thread should I encounter any.

Thanks for the help

Aye, using a box2d body per image is probably overkill. When bounding boxes are done, you could use those for box2d bodies. For now you could use a transparent images with a special prefix so you don't draw them, only use it for box2d bodies. You'll still have an issue with flip, probably using a whole body setup in each direction is the way to go.

1年 後

hello...i have problem in spine...
i try to get boundingBox(for collosin) make in spine.. under skin as in spineboy jeson file.
but every time i face errors.. to access it.
plz help me... thanks