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).
Related
The best example I can give is with the Three.js library in javascript :
function createMesh(){
var geometry = new THREE.SphereGeometry(10, 5, 5);
var material = new THREE.MeshPhongMaterial();
var mesh = new Mesh(geometry, material);
return mesh;
}
This translates in C++ to :
Mesh* createMesh(){
SphereGeometry* geometry = new SphereGeometry(10, 5, 5);
MeshPhongMaterial* material = new MeshPhongMaterial;
Mesh* mesh = new Mesh(geometry, material);
return mesh;
}
Now, who should have the responsability to delete these 3 pointers. Should it be the user of the library? Or should the geometry and the material be destroyed in the destructor of Mesh, and the user should just delete the Mesh pointer? And if this is the case, how will the player know to not delete his pointers and avoid a double deletion?
Also, what if this happens :
SphereGeometry geometry(10, 5, 5);
MeshPhongMaterial material;
Mesh* mesh = new Mesh(&geometry, &material);
Thanks.
With smart pointer, ownership is clear:
std::unique_ptr<Mesh> createMesh(){
auto geometry = std::make_unique<SphereGeometry>(10, 5, 5);
auto material = std::make_unique<MeshPhongMaterial>();
return std::make_unique<Mesh>(std::move(geometry), std::move(material));
}
Should it be the user of the library?
The library lacks reliable information on when to delete these objects, so it must be the user. He does not need to do it manually, though (see the point at the end regarding smart pointers).
Or should the geometry and the material be destroyed in the destructor of Mesh, and the user should just delete the Mesh pointer?
Transferring ownership in a constructor is a viable alternative. It also lets you "fold" the code into something shorter, which would not be possible with separate deletions:
Mesh* mesh = new Mesh(new SphereGeometry(10, 5, 5), new MeshPhongMaterial);
And if this is the case, how will the player know to not delete his pointers and avoid a double deletion?
By reading documentation.
Also, what if this happens :
Mesh* mesh = new Mesh(&geometry, &material);
As long as you do not make mesh available outside the scope of geometry and material, nothing happens.
A better approach is to avoid using raw pointers, if at all possible. Use objects instead of pointers to objects everywhere where it is practical. Use collections when dynamic sizing is needed. Use smart pointers when you must have a pointer.
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.
Some context: I am writing a 2D Destructible terrain library for Cocos2D/Box2D which involves a hybrid of C++ and Objective-C. I recently encountered a situation that has stumped me where I can't think of a solution that doesn't involve parallel arrays.
In order for the physics boundaries to be defined around the terrain, an initial trace must be made of the terrain border. I make a function call to trace all isolated bodies of pixels within a texture and cache them. This creates the following data structures
An NSMutableDictionary "borderPixels" with the key being equal to an CGPoint wrapped in an NSValue which is equal to the pixel's unique location. This holds all traced pixels.
A circular linked lists with TerPixels pointing to their next neighbor pixel
An NSMutableArray "traceBodyPoints" which holds a single TerPixel representing a 'start' point of a terrain body. I only store TerPixel *'s here where I need to trace a physics body. So, if a terrain body has been modified, I insert any individual TerPixel * from the modified body into this array. I can then reference each of these and traverse the linked list to trace the physics body.
Here is some code to help paint a better picture of the situation:
-(void)traverseBoundaryPoints:(CGPoint)startPt {
if (!borderPixels) borderPixels = [[NSMutableDictionary alloc] init]; // Temp
if (!traceBodyPoints) traceBodyPoints = [[NSMutableArray alloc] init]; // Temp
TerPixel * start = [[TerPixel alloc] initWithCoords:startPt.x ypt:startPt.y prevx:-1 prevy:0];
TerPixel * next = start;
//CCLOG(#"Start of traverseBoundary next.x and next.y %d, %d", next.x, next.y);
TerPixel * old;
while (true) {
old = next;
next = [self findNextBoundaryPixel:next];
[next setNSP:[old subTerPixel:next]];
old.nextBorderPixel = next;
if (next.x == start.x && next.y == start.y) {
CCLOG(#"SUCCESS :: start = next");
next.nextBorderPixel = start; // Make the linked list circular
NSValue * pixLocVal = [next getAsValueWithPoint];
[borderPixels setObject:next forKey:pixLocVal];
// Add the pixel to the tracePoints array to be traversed/traced later
[traceBodyPoints addObject:start];
break;
} // end if
// Connect the linked list components
NSValue * pixLocVal = [next getAsValueWithPoint];
[borderPixels setObject:next forKey:pixLocVal];
} // end while
} // end traverse function
Here is where I can't find a solution. I need to relate each TerPixel * in the traceBodyPoints array to a Box2D b2Body which will be created and added to the physics world. In my library, each isolated body of pixels within a texture corresponds to a Box2D body. So, when an event happens that destroys a chunk of the terrain, I need to destroy the body associated the the destroyed pixels and retrace ONLY the altered bodies. This means I need a way to associate any given TerPixel * to a Box2D body *.
In Objective-C with ARC, to my knowledge, I cannot include C++ objects/pointers in Objective-C containers without bridge casting to void *'s. Problem is these operations need to be incredibly performant and engaging in bridge casting is very costly. Also, I don't want to include a pointer to a Box2D body in every single TerPixel. This would be a nightmare to ensure there are no dangling pointers and require pointless iteration to nil pointers out.
Here is my logic for creating physics boundaries
-(void)createPhysicsBoundaries {
if ([self->traceBodyPoints count] == 0) {
CCLOG(#"createPhysicsBoundaries-> No bodies to trace");
return;
}
// NEED LOGIC HERE TO DELETE ALTERED BODIES
// NEED TO DELETE EXISTING BOX2D BODY AND RE-TRACE A NEW ONE
// For each body that has been altered, traverse linked list to trace the body
for (TerPixel * startPixel in self->traceBodyPoints) {
TerPixel * tracePixel = startPixel.nextBorderPixel;
b2BodyDef tDef;
tDef.position.Set(0, 0);
b2Body * b = self->world->CreateBody(&tDef);
self->groundBodies->push_back(b);
b->SetUserData((__bridge void*) self);
b2EdgeShape edgeShape;
CCLOG(#"StartPixel %d, %d", startPixel.x, startPixel.y);
while (tracePixel != startPixel) {
b2Vec2 start = b2Vec2(tracePixel.x/PTM_RATIO, tracePixel.y/PTM_RATIO);
//CCLOG(#"TracePixel BEFORE %d, %d", tracePixel.x, tracePixel.y);
tracePixel = tracePixel.nextBorderPixel;
//CCLOG(#"TracePixel AFTER %d, %d", tracePixel.x, tracePixel.y);
b2Vec2 end = b2Vec2(tracePixel.x/PTM_RATIO, tracePixel.y/PTM_RATIO);
edgeShape.Set(start,end);
b->CreateFixture(&edgeShape, 0);
} // end while
} // end for
} // end createPhysicsBoundaries
Hopefully this makes sense. If you need a visual of what is happening, here is a video. http://www.youtube.com/watch?v=IUsgjYLr6e0&feature=youtu.be where the green boundaries are physics boundaries.
engaging in bridge casting is very costly
Says who? It's still just a cast and essentially free/negligible. A bridge transfer or retain cast adds the corresponding reference counting method calls, but you don't need that here.
The solution to your problem is really simple. You have traceBodyPoints array containing instances of the TerPixel class.
You simply need a wrapper class for this array, let's call it TerrainBlob. The TerrainBlob class contains as property your NSMutableArray traceBodyPoints and another property for the b2Body:
#interface TerrainBlob : NSObject
#property NSMutableArray* traceBodyPoints;
#property b2Body* body;
#end
You can improve TerPixel to contain a back reference to the TerrainBlob, which must be weak to avoid retain cycles. That way each pixel can access the b2Body. You could also add a method in TerrainBlob that adds a TerPixel and properly sets the terrainBlob property for convenience.
#interface TerPixel : NSObject
...
#property (weak) TerrainBlob* terrainBlob;
#end
You can then access the b2Body from within a TerPixel:
b2Body* body = _terrainBlob.body;
if (body)
{
// do something with body
}
Now you only need to update body in one location, and each TerPixel needs to check whether the body is nil before using it.
Finally, it is worth mentioning that destructible terrain on pixel basis is overkill, especially on Retina devices. Unless you're already doing that, look into creating approximate line shapes spanning multiple pixels because you don't really need pixel-perfect accuracy for the physics simulation.
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;
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?