Created
January 7, 2012 20:44
-
-
Save codeswimmer/1575980 to your computer and use it in GitHub Desktop.
iOS: Core Animation Example: eggs falling out of a tree
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Core Animation Example: eggs falling out of a tree | |
// This was glommed from iphonedevsdk: http://www.iphonedevsdk.com/forum/iphone-sdk-development/65632-animation-sample-code-our-newest-app.html | |
// This is the main animation routine. | |
- (IBAction) doorEasterEggAction; | |
{ | |
//treeDoorImageView | |
CATransform3D theTransform; | |
UIImageView* anEgg; | |
CABasicAnimation *rotateAnimation; | |
switch (animationStep) | |
{ | |
case 0: | |
animationStep++; | |
//----------------------- | |
//Create 2 sounds players so we can alternate between them and keep up with | |
//the pace of egg launching | |
self.popSoundPlayer1 = [Utils audioPlayerFromFilenameInBundle: @"pop sound" | |
ofType: @"mp3"]; | |
self.popSoundPlayer2 = [Utils audioPlayerFromFilenameInBundle: @"pop sound" | |
ofType: @"mp3"]; | |
[self.popSoundPlayer1 prepareToPlay]; | |
[self.popSoundPlayer2 prepareToPlay]; | |
//--------------------- | |
treeDoorButton.enabled = FALSE; //Disable the hidden button during the animation. | |
//Open the door. | |
rotateAnimation = [CABasicAnimation animation]; | |
rotateAnimation.keyPath = @"transform"; | |
rotateAnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; | |
//Pivot on the right edge (y axis rotation) | |
theTransform = CATransform3DRotate(CATransform3DIdentity, degreesToRadians(70), 0, 1, 0); | |
rotateAnimation.toValue = [NSValue valueWithCATransform3D:theTransform]; | |
rotateAnimation.duration = 0.5; | |
// leaves presentation layer in final state; preventing snap-back to original state | |
rotateAnimation.removedOnCompletion = NO; | |
rotateAnimation.fillMode = kCAFillModeBoth; | |
rotateAnimation.repeatCount = 0; | |
rotateAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; | |
rotateAnimation.delegate = self; | |
[treeDoorImageView.layer addAnimation:rotateAnimation forKey:@"transform"]; | |
break; | |
case 1: | |
//Pause briefly after the door opens. | |
animationStep++; | |
eggCount = 101; | |
[self performSelector: @selector(doorEasterEggAction) withObject: nil afterDelay: 0.2]; | |
break; | |
case 2: | |
//Move each egg onto the screen. | |
if (eggCount <= 134) | |
{ | |
[self animateEgg]; | |
eggCount++; | |
} | |
else | |
{ | |
//After we've started the last egg moving, pause to let them all finish animating | |
animationStep++; | |
eggCount--; | |
[self performSelector: @selector(doorEasterEggAction) withObject: nil afterDelay: 1.5]; | |
} | |
break; | |
case 3: | |
//Now make the eggs go away one at a time. | |
anEgg = (UIImageView*)[self.view viewWithTag: eggCount]; | |
if (anEgg && [anEgg isMemberOfClass: [UIImageView class]]) | |
{ | |
[UIView beginAnimations: [NSString stringWithFormat: @"Egg %d", eggCount] context: nil]; | |
[UIView setAnimationDuration: .2]; | |
anEgg.alpha = 0; | |
anEgg.transform = CGAffineTransformMakeScale(.01, .01); | |
[UIView commitAnimations]; | |
[self performSelector: @selector(doorEasterEggAction) withObject: nil afterDelay: .05]; | |
eggCount--; | |
if (eggCount < 101) | |
animationStep++; | |
} | |
break; | |
case 4: | |
//Pause briefly after the last egg has gone away. | |
animationStep++; | |
[self performSelector: @selector(doorEasterEggAction) withObject: nil afterDelay: 0.5]; | |
break; | |
case 5: | |
animationStep++; | |
//First restore all the eggs to their starting state | |
for (eggCount = 101; eggCount <= 134; eggCount++) | |
{ | |
anEgg = (UIImageView*)[self.view viewWithTag: eggCount]; | |
if (anEgg && [anEgg isMemberOfClass: [UIImageView class]]) | |
{ | |
anEgg.alpha = 1.0; | |
anEgg.transform = CGAffineTransformIdentity; | |
anEgg.hidden = TRUE; | |
} | |
} | |
//Now close the door. | |
rotateAnimation = [CABasicAnimation animation]; | |
rotateAnimation.keyPath = @"transform"; | |
//Pivot on the right edge (y axis rotation) | |
// CGFloat width = treeDoorImageView.frame.size.width / 2; | |
// theTransform = CATransform3DTranslate(theTransform, width, 0, 0); | |
theTransform = CATransform3DRotate(CATransform3DIdentity, degreesToRadians(70), 0, 1, 0); | |
rotateAnimation.fromValue = [NSValue valueWithCATransform3D:theTransform]; | |
rotateAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; | |
rotateAnimation.duration = 0.5; | |
rotateAnimation.removedOnCompletion = YES; | |
// leaves presentation layer in final state; preventing snap-back to original state | |
rotateAnimation.fillMode = kCAFillModeBoth; | |
rotateAnimation.repeatCount = 0; | |
rotateAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; | |
rotateAnimation.delegate = self; | |
[treeDoorImageView.layer addAnimation:rotateAnimation forKey:@"transform"]; | |
break; | |
case 6: | |
//Finally, restore everything to it's starting state and renable the hidden button. | |
[treeDoorImageView.layer removeAllAnimations]; | |
treeDoorButton.enabled = TRUE; | |
animationStep = 0; | |
self.popSoundPlayer1 = nil; | |
self.popSoundPlayer2 = nil; | |
break; | |
} | |
} | |
//This is the CAAnimation delegate method that gets called once the "open the door" animation completes. | |
/It simply calls the main animation method again. | |
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag | |
{ | |
[self doorEasterEggAction]; | |
} | |
//This is the code that animates a single egg moving in an arc from the open door to it's final position. | |
- (void) animateEgg; | |
{ | |
CGPoint endPoint; | |
UIImageView* anEgg; | |
CGMutablePathRef aPath; | |
CGFloat arcTop = 185; | |
CGFloat duration = 0.75; | |
//Use the egg count as a tag to find the egg's UIImageView in it's superview | |
anEgg = (UIImageView*)[self.view viewWithTag: eggCount]; | |
if (anEgg && [anEgg isMemberOfClass: [UIImageView class]]) | |
{ | |
//Get the egg's position and save it as the end point for the animation. | |
endPoint = anEgg.center; | |
//Create a CGPath that will describe the arc for this egg. | |
aPath = CGPathCreateMutable(); | |
anEgg.hidden = FALSE; | |
//Start each animation at the same point, the door of the tree. | |
CGPathMoveToPoint(aPath, NULL, 170, 275); | |
CGPathAddCurveToPoint(aPath, NULL, 170, arcTop, endPoint.x, arcTop, endPoint.x, endPoint.y); | |
CAKeyframeAnimation* arcAnimation = [CAKeyframeAnimation animationWithKeyPath: @"position"]; | |
[arcAnimation setDuration: duration]; | |
[arcAnimation setAutoreverses: NO]; | |
arcAnimation.removedOnCompletion = NO; | |
arcAnimation.fillMode = kCAFillModeBoth; | |
[arcAnimation setPath: aPath]; | |
CFRelease(aPath); | |
//Alternate between 2 sound players so they can keep up with the rapid-fire egg launching | |
if (eggCount %2 == 0) | |
[self.popSoundPlayer1 play]; | |
else | |
[self.popSoundPlayer2 play]; | |
[anEgg.layer addAnimation: arcAnimation forKey: @"position"]; | |
anEgg.transform = CGAffineTransformMakeScale(.2, .2); | |
[UIView beginAnimations: [NSString stringWithFormat: @"Egg %d", eggCount] context: nil]; | |
[UIView setAnimationDuration: duration]; | |
anEgg.transform = CGAffineTransformIdentity; | |
[UIView commitAnimations]; | |
[self performSelector: @selector(doorEasterEggAction) withObject: nil | |
afterDelay: 0.07 + [Utils randomFloatPlusOrMinus: .03 ]]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment