I have just started playing around with Chipmunk for Objective-C (not Objective-Chipmunk though). Let me just start by saying thank you to @slembcke for creating this great library and sharing it!
After having played with a bunch of different demos and tested the code I have encountered a really strange behavior. I have no idea why this is happening to me and after looking at the running demos in the App I can download from App Store I'm pretty sure it shouldn't happen this way either. My impacts are behaving like they know about the impact before they happen and slows down (decelerates really) to finaly softly settle on a static ground. A simple scenario where I drop box shapes onto a static ground shape and let the gravity pull it down makes it look like a little moonlander that brakes for impact a little bit before it hits the ground and then nicely parks the lander on the ground. The actual distance where it starts to slow down depends on the velocity of the falling body.
I'm convinced that it is something really trivial I have missed in my code and the answer will likely come back as 'dude, didn't you read the docs?' and I did, but I can't figure out what it is that I have missed so please if anyone can figure out what is wrong with my code I would be very greatful. I have reproduced the strange behavior in as simplified code as I could, simply using CALayers to draw the shapes and not relying on anything else in there.
Code: Select all
#import <QuartzCore/QuartzCore.h>
#import "chipmunk.h"
#define MAX_DT (1.0/15.0)
@interface CEPhysicsObject : NSObject{
CALayer *layer;
cpBody *body;
}
@property (nonatomic, strong) CALayer *layer;
@property (nonatomic) cpBody *body;
@end
@implementation CEPhysicsObject
@synthesize layer, body;
@end
@interface CEPhysicsView()
{
cpSpace *space;
NSTimer *gameTimer;
CADisplayLink *_displayLink;
double t;
double dt;
NSTimeInterval currentTime;
double accumulator;
NSMutableArray *rocks;
CALayer *groundLayer;
}
@end
@implementation CEPhysicsView
- (id)init
{
self = [super init];
if (self) {
[self initialize];
}
return self;
}
- (void)initialize
{
t = 0.0;
dt = 1.0f/60.0f;
accumulator = 0.0;
space = cpSpaceNew();
// Create gravity
space->gravity = cpv(0, -900);
space->iterations = 30;
// Create an empty space.
cpSpaceSetGravity(space, space->gravity);
// Create a ground shape
cpBody *body = cpSpaceGetStaticBody(space);
cpShape *ground = cpSegmentShapeNew(body, cpv(20, -400), cpv(180, -400), 10);
cpShapeSetFriction(ground, 1.0f);
cpShapeSetElasticity(ground, 1.0f);
cpSpaceAddShape(space, ground);
// Draw the ground shape
groundLayer = [CALayer layer];
groundLayer.backgroundColor = [UIColor blackColor].CGColor;
groundLayer.frame = CGRectMake(10, 390, 180, 20);
[self.layer addSublayer:groundLayer];
// Create rocks array
rocks = [NSMutableArray new];
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(tick:)];
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}
-(void)tick:(CADisplayLink *)displayLink
{
NSTimeInterval newTime = _displayLink.timestamp;
double frameTime = MIN(newTime - currentTime, MAX_DT);
currentTime = newTime;
accumulator += frameTime;
// Take steps at controlled framerate
while ( accumulator >= dt )
{
cpSpaceStep(space, dt);
t += dt;
accumulator -= dt;
}
// Print out the 'framerate'
NSLog(@"%f %f", 1.0f/dt, newTime);
// Update positions (i.e. render)
for (CEGameRock *rock in rocks)
{
rock.layer.position = CGPointMake(rock.body->p.x, -rock.body->p.y);
}
[self setNeedsDisplay];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CEPhysicsObject *rock = [CEPhysicsObject new];
// Create a rock
rock.layer = [CALayer layer];
rock.layer.backgroundColor = [UIColor grayColor].CGColor;
rock.layer.frame = CGRectMake(90, 0, 20, 20);
[self.layer addSublayer:rock.layer];
// Create a box
cpFloat mass = 1.0;
cpFloat moment = cpMomentForBox(mass, 20.0, 20.0);
rock.body = cpSpaceAddBody(space, cpBodyNew(mass, moment));
cpShape *boxShape = cpSpaceAddShape(space, cpBoxShapeNew(rock.body, 20.0, 20.0));
cpShapeSetFriction(boxShape, 1.0f);
cpShapeSetElasticity(boxShape, 0.0f);
cpBodySetPos(rock.body, cpv(90, 0));
rock.layer.position = CGPointMake(rock.body->p.x, -rock.body->p.y);
[rocks addObject:rock];
}
@end