Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Interface 2, Advanced iOS
Mockup & Code Gen
($9.99)

Make your own iPhone apps
and run them live!
(free)

Pic Frame Dynamo: Photo Editing
($0.99)

Abiliator
($1.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Development

Reply
 
LinkBack Thread Tools Display Modes
Old 11-27-2010, 07:27 PM   #1 (permalink)
Cocoa Junkie
 
Duncan C's Avatar
 
Join Date: Dec 2008
Location: Northern Virginia
Posts: 6,003
Duncan C has a spectacular aura about
Default Animation sample code from our newest app

Our company just released a new app, a cartoon reader for the popular online cartoon Kevin & Kell. (in partnership with the cartoonist)

The app includes some fun animations, and I thought I could use one of them as a tutorial on how to put together animation sequences using Core Animation. It shows examples of several different types of animation, and shows how to string multiple animation steps together into a sequence. If you're really interested in the tutorial you might want to buy the Kevin & Kell app from the App store and try out the animation as you work through the tutorial. The code will make more sense if you see the animation work.

Kevin & Kell website
If you have't seen Kevin & Kell before, check it out. It's a great strip, and is the longest continuously running online comic ever, with over 15 years of weekly strips without a break:

As part of writing the cartoon reader, we decided it would be fun to add several animated "easter eggs" that relate to the characters and plot-lines of the strip. To explain the easter egg, you need a little background. The main character, Kevin Dewclaw, is a rabbit who's married to a wolf. Kevin's stepson, Rudy, is also a wolf. Kevin ends up playing the role of the Easter Bunny one year, and then through a very complex plot twist, Rudy winds up in the job, dressed as a rabbit. Rudy is a hit, and ends up keeping the job long term. So both Kevin and Rudy have a connection with Easter and the Easter bunny.

Anyway. On the main screen for the app is the tree the family lives in, with the characters standing around it.

The "easter egg" involves actual Easter Eggs. If you tap a hidden button on the door of the tree, it swings open, and a huge barrage of easter eggs comes arcing out and piles in front of Kevin and Rudy. After a few seconds, the eggs drop away, then the door swings shut.

Writing the animation was pretty straightforward. I had to use layer animations and create a CATransform3D to open the door on it's hinges, since view transforms can only rotate an object around it's center.

I set up an animation step counter and a big switch statement. The action on the hidden button that triggers the animation simply invokes the switch statement. The first time through, the counter is zero, so the case statement for the first step executes.

Step 0 first does some housekeeping like loading and preparing the sounds that will be used later, and disabling the hidden button that triggers the animation sequence. It then creates the animation that opens the door, makes the view controller the delegate for the animation, and adds the animation to the layer. The view controller has an animationDidStop:finished: method, which the animation calls when the animation is complete. In my case, the animationDidStop:finished: method just increments my step counter and calls my animation method again. Since we incremented the animation step counter, the next case in the switch statements gets executed.

In step 1, we simply increment the animation counter once more, and call the animation method again after a brief pause.

In step 2, we have a secondary loop that uses another counter, eggCount, to animate 1 egg UIImageView object onto the screen at a time. The code uses tags to find each egg image view. It creates a layer animation that uses a CGPath to make the eggs fly in an arc that is a decent approximation of a parabola. Once all the eggs animations have been started, step 2 just bumps the animation step counter and calls itself again after a pause.

In Step 3, I again run through all the egg objects one a time. This time I use a simple view animation to set their alpha to zero and use a scale transform to set their size to .01, .01 (which causes them to disappear into a point.)

Step 4 is another pause.

Step 5 does some cleanup so the egg objects are back in their original places for the next time the user triggers the action, then does the reverse of the door open animation to swing the door closed again.

Step 6 does the final cleanup so everything is back where it belongs, and re-enables the hidden button so the user can trigger the animation again.

The post was too long, so I will put the code in a second post, below.
__________________
Regards,

Duncan C
WareTo

Check out our apps in the Apple App store


Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.

See this tutorial on using UIView animations and layer animations:

See this thread on generating random, non-repeating text

Check out a very cool Macintosh Kaleidoscopes app called ScopeWorks that we released to the Mac App store.
Duncan C is offline   Reply With Quote
Old 11-27-2010, 07:28 PM   #2 (permalink)
Cocoa Junkie
 
Duncan C's Avatar
 
Join Date: Dec 2008
Location: Northern Virginia
Posts: 6,003
Duncan C has a spectacular aura about
Default Here's the code

Code:
//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 ]];
  }
           
}
__________________
Regards,

Duncan C
WareTo

Check out our apps in the Apple App store


Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.

See this tutorial on using UIView animations and layer animations:

See this thread on generating random, non-repeating text

Check out a very cool Macintosh Kaleidoscopes app called ScopeWorks that we released to the Mac App store.
Duncan C is offline   Reply With Quote
Old 11-28-2010, 12:34 PM   #3 (permalink)
Registered Member
 
Join Date: May 2010
Posts: 551
aldcorn@live.com is on a distinguished road
Default Thanks for the contribution Duncan

I appreciate your contribution and input on this site. Your responses are always credible and relevant.

Thanks,
Rob

Last edited by aldcorn@live.com; 11-28-2010 at 12:37 PM.
aldcorn@live.com is offline   Reply With Quote
Old 11-28-2010, 02:52 PM   #4 (permalink)
Cocoa Junkie
 
Duncan C's Avatar
 
Join Date: Dec 2008
Location: Northern Virginia
Posts: 6,003
Duncan C has a spectacular aura about
Default

Quote:
Originally Posted by aldcorn@live.com View Post
I appreciate your contribution and input on this site. Your responses are always credible and relevant.

Thanks,
Rob

Rob,

Thanks for the kind words. I wonder if others find this particular post helpful. It was a fair amount of work to write.
__________________
Regards,

Duncan C
WareTo

Check out our apps in the Apple App store


Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.

See this tutorial on using UIView animations and layer animations:

See this thread on generating random, non-repeating text

Check out a very cool Macintosh Kaleidoscopes app called ScopeWorks that we released to the Mac App store.
Duncan C is offline   Reply With Quote
Old 11-28-2010, 03:44 PM   #5 (permalink)
Registered Member
 
Join Date: Jan 2009
Posts: 184
VMan is on a distinguished road
Default

Quote:
Originally Posted by Duncan C View Post
Rob,

Thanks for the kind words. I wonder if others find this particular post helpful. It was a fair amount of work to write.
ALL of your forum posts have been among the most worthwhile of this entire site. Do you have a blog by chance?
VMan is offline   Reply With Quote
Old 11-28-2010, 08:09 PM   #6 (permalink)
Registered Member
 
Join Date: May 2010
Posts: 551
aldcorn@live.com is on a distinguished road
Default Keep contributing if you enjoy it

Hi Duncan,
I realize you can feel slightly USED when you help someone out on this site and then never hear so much as a thanks, but if you enjoy responding to the various question please continue to do so. There are a number of people reading the posts that you may never realize are learning from you.

I almost always read your posts and responses because I have no background in programming and I can pick up the odd thing in that area from you.

I originally posted the 'thank you' message just so you would not feel left out in the cold...

Take care,
Rob



Quote:
Originally Posted by Duncan C View Post
Rob,

Thanks for the kind words. I wonder if others find this particular post helpful. It was a fair amount of work to write.
aldcorn@live.com is offline   Reply With Quote
Old 11-29-2010, 11:24 AM   #7 (permalink)
Banned
 
Join Date: Jul 2009
Posts: 576
Not_Appy_At_All is on a distinguished road
Default

ditto Rob.

I am only signing in for one reason.

To thank Duncan....

Duncan, you are one of the most giving people on this board. And your posts are literally gold in how they explain, solve and clarify problems.

And you do it all year, even when it is not the Season of Giving.

Wishing you and your family a very blessed holiday season.

Last edited by Not_Appy_At_All; 11-30-2010 at 12:14 PM.
Not_Appy_At_All is offline   Reply With Quote
Old 12-04-2010, 12:47 PM   #8 (permalink)
Registered Member
 
Join Date: Jul 2010
Posts: 67
Ajaxx is on a distinguished road
Default

Duncan,

A BIG thank you for this post, i always read your posts. I will study this.

Cheers
Ajaxx is offline   Reply With Quote
Old 12-08-2010, 02:08 PM   #9 (permalink)
Registered Member
 
amit.wizkid's Avatar
 
Join Date: Aug 2009
Location: India
Posts: 83
amit.wizkid is on a distinguished road
Send a message via Yahoo to amit.wizkid
Default

you are doing good Duncan!
Your posts have been really informative and I've picked up some new things.
Thank you for those..
Please keep supporting the community by providing your valuable inputs to the guys who come to iPhonedevsdk to learn and share..

Keep posting!
__________________
If you believe you can fly
You will!

En Route HQ on the Web - share your trip no matter how you travel! It's Fun

En Route HQ on the App Store
amit.wizkid is offline   Reply With Quote
Old 12-28-2010, 06:22 PM   #10 (permalink)
Fly-by-night Innovator
 
Join Date: Jun 2010
Posts: 364
musicwind95 is on a distinguished road
Default

Thanks so much, Duncan! It's actually a good primer for Core Animation!
__________________
If I have helped you, please consider donating. I use PayPal. It would mean a lot to me!


For more iOS Development, check out my blog—Cups of Cocoa. All visitors welcome, but especially beginners!

Hope I have helped!

Please check out IceFall, a new action game available in the App Store!
musicwind95 is offline   Reply With Quote
Old 12-28-2010, 07:44 PM   #11 (permalink)
Use [code] tags please
 
Join Date: Jun 2009
Location: Jacksonville, FL
Posts: 410
timle8n1 is on a distinguished road
Default

Good stuff Duncan.

Question - does the door have thickness? That is does the edge of door get thicker and thicker as it rotates into view until that is all you see? If so how?

I've never done anything with the animation now it doesn't seem as much black magic.
Thanks
timle8n1 is offline   Reply With Quote
Old 01-03-2011, 06:08 PM   #12 (permalink)
Cocoa Junkie
 
Duncan C's Avatar
 
Join Date: Dec 2008
Location: Northern Virginia
Posts: 6,003
Duncan C has a spectacular aura about
Default

Quote:
Originally Posted by timle8n1 View Post
Good stuff Duncan.

Question - does the door have thickness? That is does the edge of door get thicker and thicker as it rotates into view until that is all you see? If so how?

I've never done anything with the animation now it doesn't seem as much black magic.
Thanks
Tim,

No, the door does not have thickness. That would mean creating a 3D shape, which is much more involved. Instead, I did a 3D animation of a flat object. That's simpler.

If I was going to do 3D animation I would probably use OpenGL. That's a more ambitious task. (OpenGL almost made my head explode when I first studied it.)
__________________
Regards,

Duncan C
WareTo

Check out our apps in the Apple App store


Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.

See this tutorial on using UIView animations and layer animations:

See this thread on generating random, non-repeating text

Check out a very cool Macintosh Kaleidoscopes app called ScopeWorks that we released to the Mac App store.
Duncan C is offline   Reply With Quote
Old 01-03-2011, 06:16 PM   #13 (permalink)
Use [code] tags please
 
Join Date: Jun 2009
Location: Jacksonville, FL
Posts: 410
timle8n1 is on a distinguished road
Default

Quote:
Originally Posted by Duncan C View Post
Tim,

No, the door does not have thickness. That would mean creating a 3D shape, which is much more involved. Instead, I did a 3D animation of a flat object. That's simpler.
Thanks for the reply - I figured as much - and OpenGL makes my head explode too.
timle8n1 is offline   Reply With Quote
Old 01-03-2011, 06:44 PM   #14 (permalink)
Cocoa Junkie
 
Duncan C's Avatar
 
Join Date: Dec 2008
Location: Northern Virginia
Posts: 6,003
Duncan C has a spectacular aura about
Default

Quote:
Originally Posted by timle8n1 View Post
Thanks for the reply - I figured as much - and OpenGL makes my head explode too.
I managed to get up to speed on OpenGL without a fatal brain-explosion, but it was touch-and-go.

I wrote a fractal renderer for Mac called FractalWorks that uses OpenGL to create shaded 3D renderings of fractal images. You can download it here: FractalWorks download page.

It can create images like this:


It even supports rotating, panning, and zooming the fractal images on screen in real time, which is cool.

It's currently free, although my company is getting ready to sell an updated version in the Apple Mac App store.

Sorry, that's a bit off-topic on an iOS development board, but since we were talking about OpenGL...
__________________
Regards,

Duncan C
WareTo

Check out our apps in the Apple App store


Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.

See this tutorial on using UIView animations and layer animations:

See this thread on generating random, non-repeating text

Check out a very cool Macintosh Kaleidoscopes app called ScopeWorks that we released to the Mac App store.
Duncan C is offline   Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



» Advertisements
» Online Users: 326
15 members and 311 guests
akphyo, alexP, cgokey, EXOPTENDAELAX, flamingliquid, guusleijsten, mariano_donati, ohmniac, Paul Slocum, PavelSea, SLIC, Sloshmonster, Sonuye857, v1n2e7t
Most users ever online was 1,387, 04-10-2012 at 04:21 AM.
» Stats
Members: 175,653
Threads: 94,115
Posts: 402,888
Top Poster: BrianSlick (7,990)
Welcome to our newest member, ohmniac
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 10:32 PM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.0