// This code was written by Lucas Newman and is released into the public domain. #import "FlipACoinApp.h" #import "FCCoinView.h" @implementation FlipACoinApp // UIApplication - (void)applicationDidFinishLaunching:(GSEventRef)event; { // create the content view window = [[UIWindow alloc] initWithContentRect:[UIHardware fullScreenApplicationContentRect]]; [window setContentView:[[UIView alloc] initWithFrame:[window bounds]]]; [[window contentView] setBackgroundColor:(CGColorRef)[(id)GSColorCreateWithDeviceWhite(0.0, 1.0) autorelease]]; // enable perspective transforms LKTransform sublayerTransform = LKTransformIdentity; sublayerTransform.m34 = 1.0 / -420.0; [[(UIView *)[window contentView] _layer] setSublayerTransform:sublayerTransform]; // create the coin view coinView = [[[FCCoinView alloc] initWithFrame:CGRectInset([window bounds], 60.0, 60.0)] autorelease]; [coinView setBackgroundColor:(CGColorRef)[(id)GSColorCreateWithDeviceWhite(0.0, 0.0) autorelease]]; [[window contentView] addSubview:coinView]; [window orderFront:nil]; [window makeKey:nil]; // create heads and tails images for animating CGContextRef bitmapContext = (CGContextRef)[(id)CGBitmapContextCreate(NULL, CGRectGetWidth([coinView bounds]), CGRectGetHeight([coinView bounds]), 8, 0, (CGColorSpaceRef)[(id)CGColorSpaceCreateDeviceRGB() autorelease], kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst) autorelease]; [self drawCoinInRect:CGContextGetClipBoundingBox(bitmapContext) context:bitmapContext heads:YES]; headsImage = CGBitmapContextCreateImage(bitmapContext); CGContextClearRect(bitmapContext, CGContextGetClipBoundingBox(bitmapContext)); [self drawCoinInRect:CGContextGetClipBoundingBox(bitmapContext) context:bitmapContext heads:NO]; tailsImage = CGBitmapContextCreateImage(bitmapContext); // add sunbeams layer ahead of time, make it invisible for now static id sunbeamsImageRef; if (!sunbeamsImageRef) sunbeamsImageRef = [(id)[[UIImage applicationImageNamed:@"sunbeams.png"] imageRef] retain]; sunbeamsView = [[[UIView alloc] initWithFrame:CGRectMake(-(600.0 - CGRectGetWidth([window bounds])) / 2.0, -(600.0 - CGRectGetHeight([window bounds])) / 2.0, 600, 600)] autorelease]; // retained by superview [[sunbeamsView _layer] setContents:sunbeamsImageRef]; [[sunbeamsView _layer] setDelegate:self]; [[sunbeamsView _layer] setOpacity:0.0]; [[window contentView] addSubview:sunbeamsView]; } - (void)applicationWillTerminate; { [stablizedDate release]; CFRelease(headsImage); CFRelease(tailsImage); [window release]; } - (void)acceleratedInX:(float)x Y:(float)y Z:(float)z; { float xRotationAngle = asinf(z / sqrtf(y * y + z * z)); // -M_PI / 2.0 to M_PI / 2.0 if (!isStabilized && xRotationAngle < 0.0 && fabsf(xRotationAngle + (M_PI / 2.0)) < (20.0 / 180.0 * M_PI)) { // within 20 degrees of flat if (!stablizedDate) stablizedDate = [[NSDate date] retain]; else if ([[NSDate date] timeIntervalSinceDate:stablizedDate] > 0.25) isStabilized = YES; } else if (!isStabilized) { [stablizedDate autorelease]; stablizedDate = nil; } else if (isStabilized && (xRotationAngle > 0.0 || fabsf(xRotationAngle + (M_PI / 2.0)) > (20.0 / 180.0 * M_PI))) { isStabilized = NO; if (fabsf(xRotationAngle) < (70.0 / 180.0 * M_PI)) // within 70 degrees of straight up [coinView flip]; } } // NSObject (LKLayerDelegate) - (id)actionForLayer:(LKLayer *)layer forKey:(NSString *)key; { if ([key isEqualToString:@"opacity"]) { LKBasicAnimation *opacityAnimation = [LKBasicAnimation animationWithKeyPath:key]; [opacityAnimation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]]; [opacityAnimation setDuration:1.0]; return opacityAnimation; } else if ([key isEqualToString:@"transform"]) { LKBasicAnimation *transformAnimation = [LKBasicAnimation animationWithKeyPath:key]; [transformAnimation setTimingFunction:[LKTimingFunction functionWithName:@"easeInEaseOut"]]; [transformAnimation setDuration:1.0]; return transformAnimation; } else return (id)[NSNull null]; // we aren't an NSView subclass } // API - (void)drawCoinInRect:(CGRect)rect context:(CGContextRef)context heads:(BOOL)heads; { CGRect coinRect = CGRectInset(rect, 0.0, (CGRectGetHeight(rect) - CGRectGetWidth(rect)) / 2.0); // draw coin body CGContextSetCMYKFillColor(context, 0.0, 0.0, 1.0, 0.3, 1.0); CGContextFillEllipseInRect(context, coinRect); CGContextSetLineWidth(context, 6.0); CGContextSetCMYKStrokeColor(context, 0.0, 0.0, 1.0, 0.0, 1.0); CGContextStrokeEllipseInRect(context, CGRectInset(coinRect, 3.0, 3.0)); CGContextSetRGBStrokeColor(context, 153.0 / 255.0, 145.0 / 255.0, 22.0 / 265.0, 1.0); CGContextStrokeEllipseInRect(context, CGRectOffset(CGRectInset(coinRect, 3.0, 3.0), 0.0, 3.0)); // draw heads or tails label UIPushContext(context); UITextLabel *textLabel = [[[UITextLabel alloc] initWithFrame:CGRectInset(coinRect, 20.0, 50.0)] autorelease]; [textLabel setText:(heads ? @"Heads" : @"Tails")]; [textLabel setFont:(GSFontRef)[(id)GSFontCreateWithName("Marker Felt", kGSFontTraitBold, 50.0) autorelease]]; [textLabel setColor:(CGColorRef)[(id)GSColorCreateColorWithDeviceRGBA(228.0 / 255.0, 211.0 / 255.0, 26.0 / 265.0, 1.0) autorelease]]; [textLabel setShadowColor:(CGColorRef)[(id)GSColorCreateColorWithDeviceRGBA(153.0 / 255.0, 145.0 / 255.0, 22.0 / 265.0, 1.0) autorelease]]; [textLabel setShadowOffset:CGSizeMake(0, 3)]; [textLabel setCentersHorizontally:YES]; [textLabel drawContentsInRect:CGContextGetClipBoundingBox(context)]; UIPopContext(context); } - (CGImageRef)headsImage; { return headsImage; } - (CGImageRef)tailsImage; { return tailsImage; } - (UIView *)sunbeamsView; { return sunbeamsView; } @end