Box2D: Creating the b2BodyDef inside an object causes error - c++

I am using cocos2d with Box2D to create a simple iPhone game, and have made GameLevel objects which contains LevelObject objects.
I want to create level objects with the constructor
LevelObject(CGPoint position, b2BodyType type, b2Shape* shape, CCSprite *sprite);
as I believe this contains all the information I need to create the object on the screen.
LevelObject::LevelObject(CGPoint position, b2BodyType type, b2Shape* shape, CCSprite *sprite) : position(position), sprite(sprite)
{
sprite.position = position;
bodyDef = new b2BodyDef;
bodyDef->type = type;
bodyDef->position.Set(position.x/PTM_RATIO, position.y/PTM_RATIO);
bodyDef->userData = sprite;
fixtureDef = new b2FixtureDef;
fixtureDef->shape = shape;
}
The problem is that when I try to run this, I get a SIGABRT-error. But if I move this
bodyDef = new b2BodyDef;
bodyDef->type = type;
bodyDef->position.Set(position.x/PTM_RATIO, position.y/PTM_RATIO);
bodyDef->userData = sprite;
outside the constructor, and pass in the bodyDef in the constructor:
LevelObject::LevelObject(b2BodyDef* bodyDef, CGPoint position, b2BodyType type, b2Shape* shape, CCSprite *sprite) : bodyDef(bodyDef), position(position), sprite(sprite)
Everything works as intended.
What am I doing wrong? Is there any difference in creating the bodyDef = new b2BodyDef inside or outside the constructor?
EDIT: I cannot seem to edit the bodyDef object inside the constructor neither. If I create bodyDef outside, take it in as a parameter, then
bodyDef->position.Set(134/PTM_RATIO, 33/PTM_RATIO);
and so on inside the constructor doesn't change how the object looks on the screen.

Do not use new to create a b2BodyDef. In the Box2D API Reference you'll see that b2BodyDef is a struct, not a class.
This is how you should create a b2BodyDef and any other Box2D struct:
b2BodyDef bodyDef;
bodyDef.type = type;
bodyDef.position.Set(position.x/PTM_RATIO, position.y/PTM_RATIO);
bodyDef.userData = sprite;

Related

C++ How to copy pointer data ( and all of its systems ) to another pointer of the same type?

It's easier for me to explain this kind of stuff in videogame terms. I'll try to be as clear as possible please bear with me...
I have a Bullet class that's made of different components, such as a Sprite component and a Transform Component... It would look something like this:
class Bullet
{
public:
Bullet( texture2D texture, Rectangle sourceRectangle, Rectangle destinationRectangle )
Bullet();
~Bullet();
// Returns a pointer to its sprite component so that I can use it wherever I want in the scene:
Sprite* const Sprite() const{ return this->sprite; }
// Setters:
void SetAngle( float new_angle ){ this->angle = new_angle; }
void SetSpeed( float new_speed ){ this->speed = new_speed; }
void SetRadius( float new_radius ){ this->radius = new_radius; }
private:
// Sprite component:
Sprite* sprite;
private:
// Regular member data:
float angle;
float speed;
float radius;
};
The sprite component is simply another class that holds a texture, source rectangle, destination rectangle, and some member functions to manipulate it (Move, Rotate, SetTexture, etc ). Nothing really special. It gets initialized within the constructor
What I need to do is to be able to copy one pointer to a bullet object entirely to another new pointer to a bullet, including the sprite component. Something like this:
// These arguments will be "fed" into the sprite component
Bullet* bullet1 = new Bullet( texture, sourceRect, destRect );
Bullet* bullet2 = new Bullet(); // Using default constructor.
*bullet2 = *bullet1;
Technically, doing it this way works. However, only the regular member data gets copied I think, but not the sprite component. It only points to the first bullet's sprite component. At least that's what I think is happening.
Hopefully I was clear explaining this issue, Thanks for taking the time.

Box2D and ARC doubts

I'm trying to use Box2D in ARC environment. Below is how I pass ObjC pointer to non-ObjC space using __bridge. But it doesn't seems to me legal, since sprite var can be deallocated.
- (void)addBoxBodyForSprite:(CCSprite *)sprite
{
b2BodyDef spriteBodyDef;
...
spriteBodyDef.userData = (__bridge void*)sprite;
b2Body *spriteBody = _world->CreateBody(&spriteBodyDef);
...
spriteBody->CreateFixture(&spriteShapeDef);
}
This is how I transfer that same sprite from non-ObjC to ObjC space, this time using __bridge _transfer.
-(void)update:(ccTime)dt
{
...
CCSprite *sprite = (__bridge_transfer CCSprite *)b->GetUserData();
...
}
I also deallocate use DestroyBody(...) to deallocate body, which contains sprite reference and not specifically deleting userData, because I'm assuming that body live longer than sprite.
Question is whether using the bridges above is legal or not.
To store an Objective-C object in a stuct, use struct.val = CFBridgingRetain(val). when accessing the value, use id val = (__bridge id)struct.val. For releasing it, use CFRelease(struct.val).

API Design Flaw with Factory Pattern

I'm using a factory to create Shape instances for a physics engine. The size of each shape is not known until construction time, hence a factory being used in place of stack memory + cloning. A Shape is then supplied to the physics Scene to create a Body:
// Sphere derives from Shape
Sphere *s = Scene.CreateSphere( radius );
// Construct a rigid body with a certain shape
Body *b = Scene.CreateBody( s );
The issue: I wish for each Shape to be associated with only one Body at any given time. I need to disallow the user from doing this:
Body *b1 = scene.CreateBody( );
Body *b2 = scene.CreateBody( );
Shape *s = scene.CreateBox( 1.0f, 1.0f, 1.0f );
b1->AddShape( s );
b2->AddShape( s ); // bad
Additional info: Expensive performance checks for pointer uniqueness would be best to be avoided, as performance is important here. However in debug mode performance hits for error checking are acceptable.
It is important to be able to construct shapes separately from creating bodies, as multiple shapes can be apart of an aggregate rigid body:
Body *b = Scene.CreateBody( );
b->AddShape( shapePtr1 );
b->AddShape( shapePtr2 );
Shape instances should also be able to be transferred from one Body to another during run-time;
Body *b1, b2; // initialized elsewhere
Shape *s; // initialized elsewhere, is attached to b1
b1->RemoveShape( s );
b2->AddShape( s );
Perhaps I should go about a different api design? Perhaps cloning could be used somehow?
First, make all your Create*() functions take a Body parameter, as a form of dependency inversion.
Then you can only create a Shape for a single Body. You can also assert or otherwise error out if you try to create a Shape on a Body that already has a shape.
You can support the moving of Shape objects with the simple requirement that the destination Body does not already have an attached Shape. Do not have a DetachShape, which would allow "dangling" shapes, but rather simply a MoveShapeTo and a ReleaseShape. Alternatively, just use a smart pointer of some variety to ensure that "dangling" shapes are cleaned up properly, if that's your primary worry.
Make Body::AddShape(...) private, and remove the ctor that takes a Shape* argument.
void Body::AddSphere(float radius)
{
AddShape(Scene.CreateSphere(radius));
}
void Body::transferShape(Shape *s, Body &B2)
{
RemoveShape( s );
B2.AddShape( s );
}
// Construct a rigid body with no Shapes (yet)
Body *b = Scene.CreateBody();
// Give it a Sphere
b->AddSphere(radius);
// Transfer it to another body:
Body *b2 = Scene.CreateBody();
Shape *s = b->GetShapePointerSomehow();
b->transferShape(s, *b2);
Note that there is no way to add a preexisting Shape to a Body without removing it from another Body. No outside code can cause two Bodies to contain the same Shape.

What is wrong with the way I'm overriding this method?

I'm trying to build a ray tracer. I have a class called Shape which I'm extending to the class of Sphere (and other shapes as well, like triangles). Shape has the method
virtual bool intersect(Ray) =0;
And so I create the Sphere class by
class Sphere : public Shape{
public:
Sphere(){};
bool intersect(Ray){/*code*/};
};
I have a main class which I use to create a list of Shape pointers. I create a Sphere pointer and do the following:
Sphere* sph = &Sphere();
shapes.emplace_front(sph); //shapes is a list of Shape pointers
Then when I want to trace the ray in another class I do the following:
for (std::list<Shape*>::iterator iter=shapes.begin(); iter != shapes.end(); ++iter) {
Shape* s = *iter;
bool hit = (*s).intersect(ray);
}
But I get the error that I cannot call intersect on a the virtual class Shape, even though it should be that *s points to a Sphere type object. What am I doing wrong with inheritance?
One problem is this:
Sphere *sph = &Sphere();
It creates a temporary object of type Sphere, stores a pointer to that temporary, then destroys the temporary. The result is nonsense.
Change it to this:
Sphere *sph = new Sphere();
things will work much better.

Move Chipmunk Body to Sprite position

I have a Chipmunk shape, with a body, in a space. I am removing the body from the space so that I can position it and not have it fall due to gravity etc. I need to be able to make this body move, so I am not making it static.
I need the body to update it's position according to the position of a Cocos2D sprite in the scene + an offset.
I'm setting the bodies position with:
collShape->body->p = collSprite.position; - this seems to not work, not compile errors, it runs, but the collision shape doesn't move.
Is it possible to move a collision body based upon the position of a sprite in my tick method?
What you're doing should be possible.
Cleanest way is to create a new class that derives from CCSprite and then override the setPosition method to update the sprite's body.
The advantage of this, is that anytime the sprite's position is changed (either explicitly by you or by any animation sequence) the Chipmunk body will automatically get updated.
-(void) setPosition:(CGPoint) p{
[super setPosition:p];
if (self->body != nil) {
self->body->p.x = p.x;
self->body->p.y = p.y;
//Note: also call cpSpaceRehash to let Chipmunk know about the new position
}
}
When you call cpSpaceStep, a list of active shapes is created and cpShapeUpdateFunc is called for each. That function looks like:
void
cpShapeUpdateFunc(cpShape *shape, void *unused)
{
cpBody *body = shape->body;
cpShapeUpdate(shape, body->p, body->rot);
}
...which updates the shape to the body location and rotation it's attached to. If that's not happening maybe your shape has not been added to the space or has not been added to the body?