Avoiding parallel arrays with Objective-C and C++ - c++

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.

Related

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).

How to copy instances of an extended CCSprite?

I'm planning to extend the CCSprite class in order to create a Block class, which are the basic building blocks of my game. There may be a number of "archblocks" - prototypes on which individual blocks are to be based. In particular, I want to create a palette, from which the user can pick her building blocks which are to be placed on the game board. Once placed on the board, the building blocks takes on an identity of it's own.
Here's what I have so far:
class Block : public CCSprite {
private:
int _id = 0;
int _type = 0;
public:
Block* CopyBlock();
}
Once a user selects a Block and drops it on the game board, CopyBlock is going to be invoked and the prototype be safely returned to the palette, leaving the newly minted Block living a life of its own on the game board.
I've noticed that CCObject "implements" a Copy method, but as far as I can tell this just refers to a CopyWithZone(0) for CCObject that isn't implemented. The Copy method isn't virtual, though, so I'm a little unsure if I'm able to override this. (I'm not super strong in C++ but I do have a good grasp on OOP, so I'm up for the details if anyone care to share.)
Question:
1) Does this design make sense? Should I go with overriding Copy and/or CopyWithZone instead?
2) How can I implement CopyBlock (or Copy and/or CopyWithZone) so that both CCSprite stuff and members like _type are copied to the new Block?
Thanks!
Unless your block sprite contains children. You can easily create a copy constructor, creating the same sprite and copying the block's attributes (and maybe some needed sprite attributes) by yourself :
class Block : public CCSprite {
private:
int _id = 0;
int _type = 0;
public:
Block (Block &otherBlock);
}
Implementation file :
Block::Block (Block &otherBlock) {
this->initWithTexture(otherBlock.getTexture());
// If your sprite contains children then this is the place to iterate all children
// sprites, create and add them to this block. (do not forget to copy their position as well.)
this->_id = otherBlock._id;
this->_type = otherBlock._type;
}
Note that since initWithTexture does not copy the texture, if you tweak the texture it will be visible on all copies of blocks but if you don't have texture tweaking needs then this should work for you.

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.

C++ persistence of objects declared within a block, memory leakage possibility?

First of all let me prefix this question with the following points:
1) I have searched Stackexchange for this issue, most of the code presented was difficult enough for me to follow in order to warrant Asking a new Question/Opening a new Thread about this. The closest i could find was this Creating multiple class objects with the same name? c++ and unfortunately this is way past my scope of understanding
2) http://www.cplusplus.com/doc/tutorial/classes/ has not really discussed this or i have missed it.
Now that this is out of the way:
Rectangle Class code:
class Rectangle {
private:
int lineNumber;
float valueMax;
float valueMin;
public:
Rectangle(SCStudyInterfaceRef sc, int lineNumber, float valueMax, float valueMin);
int getLineNumber(); // member function of class
float getValueMax(); // member function of class Rectangle
float getValueMin(); // member function of class Rectangle
};
Rectangle::Rectangle(SCStudyInterfaceRef sc, int lineNumber0, float value1, float value2) {
lineNumber = lineNumber0;
int value2_greater_than_value1 = sc.FormattedEvaluate(value2, sc.BaseGraphValueFormat, GREATER_OPERATOR, value1, sc.BaseGraphValueFormat);
if (value2_greater_than_value1 == 1) {
valueMax = value2;
valueMin = value1;
} else {
valueMax = value1;
valueMin = value2;
}
}
int Rectangle::getLineNumber() {
return lineNumber;
}
float Rectangle::getValueMax() {
return valueMax;
}
float Rectangle::getValueMin() {
return valueMin;
}
And here is the more important part, this code is running pretty much in a loop and will repeat everytime a certain event triggers it:
bool xxx = Conditions here
if (xxx) {
// Draw new rectangle using plattforms code
code here
// Save rectangle information in the list:
Rectangle rect(sc, linenumbr + indexvalue, high, low);
(*p_LowRectanglesList).push_back(rect);
}
bool yyy = conditions here
if (Short) {
// Draw new rectangle using plattforms code
code here
// Save rectangle information in the list:
Rectangle rect(sc, linenumber + indexvalue, high, low);
(*p_HighRectanglesList).push_back(rect);
}
So the question is the following:
Since this is looped everytime an event triggers the second part of the code is going to be run, the bool condition is going to be checked, if its true its going to use plattform integrated code to draw a rectangle. Once it has drawn it this information is going to be passed to a new rectangle object/instance based on the Rectangle Class in the first part of the code using the: Rectangle rect(sc, linenumber + indexvalue, high, low); part and then save that information in a list which is in a different part of the code for now and irrelevant.
What exactly happens when there is a new Bool = True condition and the code gets executed after it has already been executed? Will the old rectangle object be simply replaced with a new rectangle object with the same name and using the new parameters (since they change on every instance due to the way the code is written)? Or are there now two objects of the Rectangle Class using the same name "rect" ?
It's technically speaking not even that important to me since the information of the parameters should be pushed into a list anyways using the (*p_HighRectanglesList).push_back(rect); part of the code
So TL;DR:
Does "rect" get destroyed/overwritten or are there now potentially limitless amounts of Rectangle Objects/Instances called "rect" floating around?
My Apologies for the wall of text but being a complete noob i thought it would be best to outline my thought process so that it will be easier for you to correct me on where I'm wrong.
Kind regards,
Orbital
Yes, rect is destroyed and recreated every loop. In C++, the scope of any variable declared in a block (in this case an if() statement) is limited to that block. Every time your program iterates, you get a new rect, and the old rect is gone.
To add, whenever you call NEW, you are basically allocating memory and creating Rectangle objects. NEW will allocate address to each instance. The pointer *rect will be pointing to the current memory address, and when you call rect with NEW again, now rect will be pointing to the new memory address the previous address becomes a NULL reference. However in C++ you have to worry about memory leaks unlike Java where you have a garbage collector.

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?