Friday, December 18, 2009

Simple Ball Animation

It has been a while since I last wrote any tutorial, so here is one more. This tutorial is inspired by a noobie's post in the iphonedevsdk.com forum. I know how hard it can be to start learning to code in XCode, especially if you are new to Obj-C and also new to Mac (like I was 2 months ago). Most of tutorials that exist in the web few months ago (that I could google anyway), are mostly too simple, like a Hello World app. That just not good enough. Sometimes, a bit more variety of the Hello World app could help much more to noobies, right? So that is why I created this tutorial blog - to help noobies get further from just displaying Hello World in their app. =p




Enough ramblings, lets get started. Here is how the app will look like. Immediately upon startup, you will see a small ball moving around randomly.


Let's plan our code according to what we want to do with the app.

1. We want a ball - so we need a UIImageView AND a ball image.
2. We want it to move around  - so we need to figure out how the ball is going to move, and to which location. This will involve a little Maths.

First, lets declare the ball in the header file:


 UIImageView *myball; // ball declaration
...
@property (nonatomic, retain) IBOutlet UIImageView *myball; // ball declaration


Secondly, let's declare a method to move the ball.


 -(void)movetheball;


Now we have these two things set up, we can now able to reference the ball so that we can change its coordinate, via the method.

Before we go on to write the code in the main file (.m file), it is better we connect the ball (ie, myball) to the corresponding UIImageView in Interface Builder. Im assuming you already know how to do that, so just connect it to the File's Owner and you select the myball label appeared in the list.

Once it is connected, you can add a ball image to your resource folder. This image can be any name, but preferably of type PNG. Adding the image to your project is very easy - you just drag the image from Finder into the XCode left pane under "Resources" folder. A confirmation box will pop up and you just click Add. Once you added the image to your project, you need to display it in the UIImageView that you just placed in IB. So, in IB, select the UIImageView and goto the first tab (with a slider icon on it), and select your image from the drop down list of Image. That's all for setting up the interface side!

Now, we come to writing the code. Open up .m file of the project, and synthesize the ball, by typing:

 @synthesize myball;


Then, we need a global variable to store the coordinates of the ball, as follows (put this under @synthesize is good).

 int ballx, bally;


Note: Something about the iPhone screen/display: In portrait mode, its size is 320pixel wide and 480pixel high. A coordinate of 0,0 is at the top left hand corner (origin).

Now, in this app, we will make the ball start moving immediately after the app is loaded, so we make use the viewdidload method. Write the code as below:


 // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
 
 ballx = arc4random() % 320; // this will create a random number from 0-320
 bally = arc4random() % 480; // this will create a random number from 0-480
        [self movetheball];
 [super viewDidLoad];
}


What the code above is doing is:
1. set x-coordinate to be a random position between 0 and 319 horizontally.
2. set y-coordinate to be a random position between 0 and 479 vertically.
3. call the movetheball method (custom method that we need to write).

Next, lets write the movetheball custom method. This method needs to do:
1. Take the UIImageView myball,
2. do animation movement on it within 1 second period.

I comment the method's code for the description.

 -(void)movetheball {
        // tell the app we are making animation. The name MovingTheBallAround is arbitrary.
 [UIView beginAnimations: @"MovingTheBallAround" context: nil]; 
        // set the delegate to self - otherwise the delegate method wont be called!
 [UIView setAnimationDelegate: self]; 
        // this line set the animation length in seconds.
 [UIView setAnimationDuration: 1.0];
        // this line specify the type of animation. EaseInOut, EaseIn, EaseOut and Linear are the options.
        // try to change it and see the effect.
 [UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
 
        // just before calling commitAnimations below, you write the code to make the changes of the
        // imageview and XCode will do the rest. It is that simple.
        // In this case, we are setting coordinates of the image to ballx and bally.
 myball.frame =  CGRectMake(ballx, bally,myball.frame.size.width,myball.frame.size.height);
 
 [UIView commitAnimations]; 
}

Next, since we want the ball to move forever, we need to move the ball again after it has finished the movement/translation. So, how do we know when the ball has finished moving? Here comes the animationdidStop DELEGATE method. Delegate method is something like a public method for a certain actions - in this case for the animation action. Whenever any animation stop, this method will be called. All you need to do is handle the messages the app sent to it.

So in the delegate method, we need to re-set the ball coordinate to another random value and then, call the movetheball method again to animate it to a new position.


 - (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(SEL)aSelector {
 if (finished) {
  // set new coordinate for ballx and bally
  ballx = arc4random() % 320; // this will create a random number from 0-320
  bally = arc4random() % 480; // this will create a random number from 0-480
   // then recall the move ball method
  [self movetheball];
 }
}

Do note that delegate methods' name are pretty much fixed. You must write the name as it is, in this case animationDidStop. Do not spell it wrongly (which is a common mistake among new coders).

Play around with the values and see what happens.