Move Chipmunk Body to Sprite position - cocos2d-iphone

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?

Related

SFML: How to check if a point is contained in a group of transformed drawables

Context
I have a class representing a text box. the text box contains a header, some text and a rectangle to enclose the box. It only displays itself (for now):
struct Textbox : public sf::Drawable, public sf::Transformable{
sf::Text header;
sf::Text text;
sf::RectangleShape border;
Textbox(){
// set relative locations of the members
header.setPosition(0,0);
auto header_bounds = header.getGlobalBounds();
// the text should be just below the header
text.setPosition(0, header_bounds.top + header_bounds.height);
auto source_bounds = text.getGlobalBounds();
// this function just returns a rectangle enclosing two rectangles
sf::FloatRect rect = enclosing_rect(header_bounds, source_bounds);
// this function sets the position, width and length of border to be equal to rect's.
setRectParams(border, rect);
}
void draw(sf::RenderTarget& target, sf::RenderStates states){
states.transform = getTransform();
target.draw(header,states);
target.draw(text,states);
target.draw(border,states);
};
The Problem
What I want
I want to add a contains method. It should return true if coor is inside the border of the box. Here is my naive implementation:
bool Textbox::contains(sf::Vector2i coor) const {
return border.getGlobalBounds().contains(coor.x, coor.y);
}
Why this implementation doesn't work
This implementation breaks when I move the Textbox via the Transformable non-virtual functions. The Textbox moves and it also draws the shapes as transformed. But! It does not actually transform them! it only displays them as transformed. So the border doesn't even know it has been moved.
Possible solutions
I can add all the functions of the Transformable API to this class, thus shadowing them and calling transform by myself on each of the members. I don;t like this because it make me write sooo much more code than I wanted. It also raises the question of how to tackle the double transforms (the one for the Textbox and the others for it's members).
I can write a completely different class Group that holds a vector of drawables and transformables and it has all that shadowing API mechanism. All that is left is to inherit from it. This doesn't actually sound that bad.
I heard about Entity System Component - it's just sound pretty overkill.
I can apply the transform when contains is called. The function is const - it's a query. Also, it's bad design to update your data on seemingly random calls.
just as before just that the transform applies to a function-local rectangle. This smells too - why do I call the transform functions on the whole Textbox just so it would apply them on every method call (so far just it's draw and contains but down the line who knows)
Make the members mutable and somehow transform them inside the draw method. This smell hackish.
The question
How do I group transformations onto multiple entities via an ergonomic API?
The only method that you really need to 'change', but to be fair add on your own is getGlobalBounds().
When you are inheriting from sf::Transformable, sf::Drawable you should treat the base class (your Textbox struct) as a shape itself therfore you just need to call myTextbox.getGlobalBounds().contains(x,y), where myTextbox is a Textbox.
Using your own code:
struct Textbox : public sf::Drawable, public sf::Transformable{
sf::Text header;
sf::Text text;
sf::RectangleShape border;
sf::FloatRect getGlobalBounds() const {
auto header_bounds = header.getGlobalBounds();
auto source_bounds = text.getGlobalBounds();
sf::FloatRect rect = enclosing_rect(header_bounds, source_bounds);
//Don't really know what it does but let say that it returns Top and Left as 0, and calculates Height, Width.
return sf::FloatRect(getPosition(), sf::Vector2f(rect.width,rect.height));
}
};
But you still have to manage the rotation, resizing,etc. when calculating globalBounds.
EDIT:
One way to implement rotation and scaling.
sf::FloatRect getGlobalBounds() const {
auto header_bounds = header.getGlobalBounds();
auto source_bounds = text.getGlobalBounds();
sf::FloatRect rect = enclosing_rect(header_bounds, source_bounds);
//Don't really know what it does but let say that it returns Top and Left as 0, and calculates Height, Width.
sf::RectangleShape textbox(sf::Vector2f(rect.width, rect.height));
//at this point textbox = globalBounds of Textbox without transformations
textbox.setOrigin(getOrigin());//setOrigin (point of transformation) before transforming
textbox.setScale(getScale());
textbox.setRotation(getRotation());
textbox.setPosition(getPosition());
//after transformation get the bounds
return textbox.getGlobalBounds();
}
The solution might be much more simple than you expect. Instead of applying all the transforms to the transformable children/members, just de-transform the point you want to check (take it to local space).
Try this:
bool Textbox::contains(sf::Vector2i coor) const {
// Get point in the local space of the rectangle
sf::Transform inverseTr = this->getInverseTransform();
sf::Vector2f pointAsLocal = inverseTr.transformPoint(coor.x, coor.y);
// Check if the point, now in local space, is containted in the rectangle
return border.getLocalBounds().contains(pointAsLocal);
// ^
// Important! Use local bounds here, not global
}
Why does this work?
Math!
When you work with transformation matrices, you can think of them as portals between spaces. You have a local space where no transformation have been applied, and you have a final space, where all transformations are applied.
The problem with global bounds of a transformable member is that they belong neither to the local space nor the final space. They are just a rectangle bounding the shape in a possibly intermediate space where this bounds doesn't even take rotation into account.
What we are doing here is taking the coordinates, that exist in the final space, and take them to the local space of the rectangle, thanks to the inverse transformation matrix. So no matter how many translations, rotations or scales (or even skews, if you have customized the matrix) you apply to the rectangle. The inverse matrix takes the point to a new space where you can just check if it belongs, as if no transformation have ever been applied.

Transformations igrnores sf::Sprite's origin

Transforming a sprite in SFML, does not regard it's new origin.
In my case sf::Sprite is rotating around the axis that is in the left top corner ({0,0}) regardless its origin. Setting new origin with .setOrigin() earlier takes no effect.
I am sure that sprite is getting the right origin position earlier which is center of rectangle.
My code:
In each of my Card class constructors I set the origin of my sprite.
card_sprite.setOrigin(Card::get_default_single_card_size().x*Game::get_scale()/2,Card::get_default_single_card_size().y*Game::get_scale()/2);
And then in my Deck class which behaves like std::stack of Cards I use function:
void Deck::push(const Card& crd)
{
push_back(crd);
..//
std::default_random_engine generator;
std::uniform_real_distribution<float> distributor(0,360);
top().setRotation(distributor(generator));
}
Card::setRotaion() looks like this, (which stil rotates card around top left corner) :
void Card::setRotation(float angle)
{
card_sprite.setRotation(angle);
}
Thanks for help in advance
Edit: Actually most methods in sf::Transform accept extra arguments to specify a center for the transformation, as per https://stackoverflow.com/users/7703024/super 's comment on my question on the same theme : How to "set the origin" of a Transform in sfml
I'm not too sure from your code, but I might've come up against a similar problem.
I "solved" it (in a very not ideal way) by replacing every call to a sfml drawing function with a call to a custom function when using sf::Transforms.
eg: instead of doing something like:
window.draw(thing, my_transform);
I had to do :
draw_transformed(thing, my_transform, window)
Where the code of draw_transformed looks like this:
void draw_transformed (sf::Shape const& thing, sf::Transform const& t, sf::RenderWindow& window) // cf note (1)
{
sf::Vector2f pos = thing.getPosition();
sf::Transform go_to_zero;
go_to_zero.translate(-pos);
sf::Transform go_back;
go_back.translate(pos);
sf::Transform conjugated_transform = go_back * t * go_to_zero ;
window.draw(thing, conjugated_transform);
}
(1) we can't use sf::Drawable as the type of thing because in sfml not all drawable things have a getPosition method, so we have to overload the function or do something "complicated" to go beyond this example.

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.

Avoiding parallel arrays with Objective-C and 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.