Skip to content

Instantly share code, notes, and snippets.

@codeswimmer
Created January 7, 2012 20:44
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save codeswimmer/1575980 to your computer and use it in GitHub Desktop.
Save codeswimmer/1575980 to your computer and use it in GitHub Desktop.
iOS: Core Animation Example: eggs falling out of a tree
// 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