Collision detection on iOS

I started developing plane for iOS recently. It’s a hacked up port of the original game I made when I was young. It was an excellent way to learn the iOS SDK and Objective-C.

Anyway, down to business… The initial collision detection I implemented was a very crude one that simply checks if the bounding boxes of the sprites intersect.

[objc]
-(void)checkCollision {
CGRect frame = sprite.frame;
if (frame.origin.y < -32 || frame.origin.y > 320) {
[parent collision];
}

NSMutableArray* baddies = parent.baddies;
UIImageView* object;
CGRect frame2;
for (object in baddies) {
frame2 = object.frame;
if (CGRectIntersectsRect(frame,frame2)) {
[parent collision];
}
}
}
[/objc]

Obviously it wasn’t very accurate and players would die before even hitting the objects – however, this was fast and simple. I tried to compensate for this by making the bounding box smaller – of course that didn’t work too well either.

There was no way around it, I had to use some more advanced collision checking solutions.

One solution I had was to draw a line around the edges of the sprite and have it check whether the lines intersect. But that would mean for every sprite, I had to somehow generate those lines. This was too complicated and too messy so I kept looking.

The solution I came to, albeit perhaps a bit slow, was to first get a bitmap and draw the two objects onto it with 0.5 alpha. Then, it’s simply just iterate through the bitmap and search for alpha values larger than 128. If there is one, it means a collision has occurred.

I dumped one such bitmap through the debugger and converted it to a PGM and it looks something like this:

There are 3 colors, black means an alpha value of 0, grey means an alpha value of less than 0.5 and white is an alpha value of more than 0.5. Obviously, no collision has occurred yet since there’s no white overlapping but you can see how the concept works.

Without further ado, here’s the code I used. You’ll have to make adjustments to make it work in your program but it’s here to demonstrate how it works. It’s also very bad code at the moment and constantly being optimized so watch out.

[objc]
-(void)checkCollision {
if (!doCollisionCheck) return;
CGRect frame = sprite.frame;
if (frame.origin.y < -32 || frame.origin.y > 320) {
[parent collision];
}

NSMutableArray* baddies = parent.baddies;
UIImageView* object;
CGRect frame2;
for (object in baddies) {
frame2 = object.frame;
if (CGRectIntersectsRect(frame,frame2)) {
[self checkCollisionExpensive:object withSpritePoints:frame.origin withOtherPoints:frame2.origin];
}
}
}
#define device_w 480
#define device_h 320
-(void)checkCollisionExpensive:(UIImageView*) image withSpritePoints:(CGPoint)spritePos withOtherPoints:(CGPoint)otherPos {
CGContextRef bitmap = CGBitmapContextCreate(NULL,
device_w,
device_h,
8,
device_w,
NULL,
kCGImageAlphaOnly);
if (!bitmap) { NSLog(@"Cannot alloc bitmap"); return; }
CGImageRef otherImageRef = image.image.CGImage;
CGImageRef selfImageRef = sprite.image.CGImage;
CGRect rect;

CGContextSetAlpha(bitmap, 0);
rect = CGRectMake(0, 0, device_w, device_h);
CGContextFillRect(bitmap, rect);

CGContextSetAlpha(bitmap, 0.5);

rect = CGRectMake(otherPos.x, device_h-otherPos.y-image.frame.size.height, image.frame.size.width, image.frame.size.height);
CGContextDrawImage(bitmap, rect, otherImageRef);
rect = CGRectMake(spritePos.x, device_h-spritePos.y-sprite.frame.size.height, sprite.frame.size.width, sprite.frame.size.height);
CGContextDrawImage(bitmap, rect, selfImageRef);

unsigned char* data = CGBitmapContextGetData(bitmap);
int collided = 0;
NSLog(@"%p",data);

for (size_t i = 0; i<device_w*device_h; i++) {
//NSLog(@"%x", (int)data[i]);
if (data[i] > 128) {
NSLog(@"collidepoint %d",(int)data[i]);
collided = 1;
break;
}
}

if (collided) [parent collision];
CGContextRelease(bitmap);

}
[/objc]

As the method name suggests, it’s a expensive process and calls to it should be reduced to a minimum. I used a combination of bounding box collision detection and the bitmapping to reduce calls.

Happy programming.

One thought on “Collision detection on iOS

  1. Thanks for this post. I have been programming a couple of years now but just started in the game area a couple of days ago. Had to wrap my head around Quartz framework today going through your code line by line. It’s not working yet but getting close.

    Question, if you still get these posts. Your original images you used, they must have had alpha channels embedded? my files are just png from photoshop. If I try and set my “kCGImageAlphaOnly” in the CGBitmapContextCreate I get errors. I think this approch is great, but I am still trying to figure out a few small details.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s