How to use AutoGeometry

Official forum for the Chipmunk2D Physics Library.
csoul
Posts: 56
Joined: Mon Mar 25, 2013 11:57 pm
Contact:

How to use AutoGeometry

Post by csoul »

I'm fairly new to Chipmunk, but I chose it because of the Obj-C wrapper. I have been through all the example projects, and while there are a few that use AutoGeometry, I can't find any examples of what I want to do.

I am trying to figure out the workflow for creating physics objects from image files. With Box2d, the workflow was:

- import the image into PhysicsEditor
- trace the image, add vertexes if necessary
- save out a Box2d .plist file
- import the plist into Xcode
- use GB2ShapeCache to retrieve the physics data and assign it to a physics sprite

So what is the workflow in Obj-Chipmunk? I notice there is a Chipmunk PLIST output (BETA) in Physics Editor. Do I even need to use Physics Editor for AutoGeometry?

Say I have an image that looks like a star. I simply need to create a physics object in the shape of the star so that it has the correct physics body. I'm using Cocos2D.

Could someone please describe the process with specific code examples? I'm assuming that AutoGeometry makes this process simple (that's why we have to pay for it right?), but again, I can't find any clear examples on how to use it.
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: How to use AutoGeometry

Post by slembcke »

So there are two snippets from the examples that are apropos here.

The first was probably easily missed because it was just sort of tacked onto Space Patrol. The car's main shape was generated from the alpha of a PNG file at runtime here:
https://github.com/slembcke/SpacePatrol ... ggy.m#L107

The second is from Gemeralds Pinball. It uses the render buffer sampler class included in the project to get the geometry directly from the alpha of a Cocos2D sprite. It is a little bit slower though since it needs to render the sprite to an offscreen buffer in order to get at it's pixel data. This is useful though because it means that you can be using sprite atlases or a weird texture format that can't easily be loaded into a bitmap in memory.
https://github.com/slembcke/Gemeralds/b ... rySprite.m

Both of them generate a single convex hull, but you can use toConvexHulls_BETA: instead of toConvexHull if you want to decompose a concave poly for you. (Note that the method is "beta" because it doesn't yet handle self intersecting polygons.) Let me know if either of those are what you are looking for.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
csoul
Posts: 56
Joined: Mon Mar 25, 2013 11:57 pm
Contact:

Re: How to use AutoGeometry

Post by csoul »

The GeometrySprite example would be great if it was a standalone class that wasn't so coupled with the project. It has a lot of extraneous code specific to Gemeralds and CocosBuilder. What would be perfect is a generic GeometrySprite class where you could instantiate a physics object from any sprite, with it's geometry automatically traced out.

Since I don't know Chipmunk well enough to do that yet, I'm trying to use the Space Patrol example. I've never seen PSD files used as resources in Xcode before so this is a bit confusing:

Code: Select all

NSURL *url = [[NSBundle mainBundle] URLForResource:@"ChassisOutline" withExtension:@"png"];
ChipmunkBitmapSampler *sampler = [ChipmunkImageSampler samplerWithImageFile:url isMask:FALSE];
There is no ChassisOutline.png file, only ChassisOutline.psd, so I'm not sure how the png resource is getting loaded, and I don't see how to handle retina/non-retina images when using the ChipmunkBitmapSampler.
csoul
Posts: 56
Joined: Mon Mar 25, 2013 11:57 pm
Contact:

Re: How to use AutoGeometry

Post by csoul »

Here is a weak attempt at a generic GeometrySprite class. It doesn't work. The sprite image gets added to the screen, but it has no physics properties and other objects do not interact with it. Any help fixing this class would be appreciated.

CMGeometrySprite.h:

Code: Select all

#import "ObjectiveChipmunk.h"

@interface CMGeometrySprite : NSObject <ChipmunkObject>

@property(nonatomic, assign) cpVect pos;
@property(nonatomic, strong) ChipmunkShape *shape;
@property(nonatomic, strong) NSArray *sprites;
@property(nonatomic, strong) NSArray *chipmunkObjects;
@property(nonatomic, strong) ChipmunkBody *physicsBody;

+(id)physicsObjectFromResource:(NSString*)filename;

@end
CMGeometrySprite.m:

Code: Select all

#import "CMGeometrySprite.h"
#import "ChipmunkAutoGeometry.h"

@implementation CMGeometrySprite

-(cpVect)pos
{
	return self.physicsBody.pos;
}

-(void)setPos:(cpVect)pos
{
	self.physicsBody.pos = pos;
}

-(id) initWithResource:(NSString*)filename
{
	if((self = [super init])){
		
        NSURL *url = [[NSBundle mainBundle] URLForResource:filename withExtension:@"png"];
		ChipmunkBitmapSampler *sampler = [ChipmunkImageSampler samplerWithImageFile:url isMask:FALSE];
		// Set a border of 0.0 to ensure the outline will be closed even if the pixels butt up against the image edge.
		[sampler setBorderValue:0.0];
        
        // March the image and grab the outline.
		ChipmunkPolylineSet *lines = [sampler marchAllWithBorder:TRUE hard:FALSE];
		ChipmunkPolyline *line = [lines lineAtIndex:0];
		// Double check that we only have one and that it has the correct winding.
		// You can handle multiple outlines easily enough, but will need to change the moment calculation so that it's properly area weighted.
		NSAssert(lines.count == 1 && line.area > 0.0, @"Degenerate image hull.");
        
        
        CCSprite *sprite = [CCSprite spriteWithFile:[NSString stringWithFormat:@"%@.png", filename]];

		// Calculate the moment of inertia from the polyline.
		// The center of gravity of the body will match up with the sprite's anchor point, so use that as the offset.
		cpFloat moment = [line momentForMass:1.0 offset:cpvneg(sprite.anchorPointInPoints)];
        
		self.physicsBody = [ChipmunkBody bodyWithMass:1.0 andMoment:moment];
        
		// Simplify the outline and make a convex hull out of it.
		ChipmunkPolyline *hull = [[line simplifyCurves:1.0] toConvexHull:1.0];
		self.shape = [hull asChipmunkPolyShapeWithBody:self.physicsBody offset:cpvneg(sprite.anchorPointInPoints)];
		self.shape.friction = 0.3;
		//shape.group = PhysicsIdentifier(BUGGY);
		//shape.layers = COLLISION_LAYERS_BUGGY;
       
		self.chipmunkObjects = @[self.physicsBody, self.shape];
                self.sprites = @[sprite];
	}
	
	return self;
}

+(id)physicsObjectFromResource:(NSString*)filename
{
    return [[self alloc] initWithResource:filename];
}

@end
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: How to use AutoGeometry

Post by slembcke »

Looks fine as far as I can tell. Can you post the code where you are adding it to your scene?

edit: Also, try putting a logging statement or breakpoint to check the number of vertexes in the convex hull it's generating.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
csoul
Posts: 56
Joined: Mon Mar 25, 2013 11:57 pm
Contact:

Re: How to use AutoGeometry

Post by csoul »

Actually I have it working if I do this:

Code: Select all

[self.space addStaticShape:myGeometrySprite.shape];
    for(CCNode *node in myGeometrySprite.sprites){
        [self addChild:node z:z_FOREGROUND];
    }
Is that the best way to add a static shape to a space? Seems cleaner to me to be able to set the shape as static and just do the usual space:add method but that doesn't seem possible.

Anyway, like you said though, it only creates a convex outline around the outermost points of an object. So if I have a star image it doesn't really work like I need it to. How exactly do I get a concave poly with toConvexHulls_BETA?

Code: Select all

ChipmunkPolylineSet *hull = [[line simplifyCurves:1.0] toConvexHulls_BETA:1.0];
How do I set this as the shape?
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: How to use AutoGeometry

Post by slembcke »

So that is the old deprecated way of working with static shapes. I guess I should add the deprecated attribute to the headers so it actually warns you.

When I added the sleeping algorithm back in 5.something I made it so that bodies were marked as static. Any shaped attached to a static body is static. You don't need to use a special add method anymore. You can either use the static body provided by the space as a convenience or make your own using one of the static body constructor methods of ChipmunkBody.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
csoul
Posts: 56
Joined: Mon Mar 25, 2013 11:57 pm
Contact:

Re: How to use AutoGeometry

Post by csoul »

So I tried this in CMGeometrySprite.m:

Code: Select all

        self.physicsBody = [ChipmunkBody staticBody];
Along with this in the main layer.m file:

Code: Select all

    [self.space add:myGeometrySprite];
And I get this error:

Code: Select all

Aborting due to Chipmunk error: Static bodies cannot be added to a space as they are not meant to be simulated.
	Failed condition: !cpBodyIsStatic(body)
Maybe I'm misunderstanding what a static body is. Sometimes I just need physics bodies to stay in the same place on the screen, and not be affected by gravity or other forces. Objects should just bounce off of them. I was thinking that's the definition of a static body (coming from box2d).

Also, any tips on my other question? I need to make a star shape for example.

Code: Select all

ChipmunkPolylineSet *hull = [[line simplifyCurves:1.0] toConvexHulls_BETA:1.0];
How do I set this as the shape?
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: How to use AutoGeometry

Post by slembcke »

So this is something that tends to confuse people about Chipmunk I guess. Adding a body to a space means that you want the body to be updated each frame (be affected by gravity, update it's position with it's velocity, etc). Since static bodies do not move, they cannot be added to a space to be simulated. This completely made sense to me when I was first writing Chipmunk, but it definitely confuses a lot of people. I've been pondering what I can do to make that more clear in the next major version of Chipmunk.

Anyway, what you are supposed to do is simply leave the static body out of your chipmunkObjects array since that is the Chipmunk objects that you want added to the space when adding your object.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
csoul
Posts: 56
Joined: Mon Mar 25, 2013 11:57 pm
Contact:

Re: How to use AutoGeometry

Post by csoul »

Thanks for the explanation on static bodies. Leaving the body out of the chipmunkObjects array works.

I still don't have a solution for my original question though, which was creating shapes from an image.

So far I can only create a convex outline around the outermost points of an object using this:

Code: Select all

ChipmunkPolyline *hull = [[line simplifyCurves:1.0] toConvexHull:1.0];
self.shape = [hull asChipmunkPolyShapeWithBody:self.physicsBody offset:cpvneg(sprite.anchorPointInPoints)];
So if I have a star image it doesn't really work like I need it to. How exactly do I get a concave poly with toConvexHulls_BETA?

Code: Select all

ChipmunkPolylineSet *hull = [[line simplifyCurves:1.0] toConvexHulls_BETA:1.0];
self.shape = ?????
Post Reply

Who is online

Users browsing this forum: No registered users and 12 guests