7/31/2009

iPhone Game Tutorial (Part 2)

Lets add more to this App.

Our Goals today:
We're going to make a few changes to our previous project. What we're going to be able to do with this app at the end of the tutorial will be:
  • Move in 3 directions (Up, Down, Right)
  • Fire (yes!)
  • Move to different stages
So lets start by modifieing our .h:
@interface AnimateViewController : UIViewController {
IBOutlet UIImageView *background;
IBOutlet UIButton *buttonUp;
IBOutlet UIButton *buttonDown;
IBOutlet UIButton *buttonRight;
IBOutlet UIButton *buttonFire;

UIImageView *player;
UIImageView *flash;
NSArray *walkImages;
NSArray *fireImages;
NSTimer *walkingTimer;
NSTimer *fireTimer;

NSUInteger lvl;
NSUInteger topLimit;
NSUInteger bottomLimit;
}

-(void)disableMovementButtons;
-(void)enableMovementButtons;

-(IBAction)walk;
-(IBAction)stopWalking;
-(IBAction)walkUp;
-(IBAction)stopWalkingUp;
-(IBAction)walkDown;
-(IBAction)stopWalkingDown;
-(IBAction)triggerPulled;
-(IBAction)triggerReleased;

-(void)startMovingForward;
-(void)moveForward;
-(void)startMovingUp;
-(void)moveUp;
-(void)startMovingDown;
-(void)moveDown;

-(void)startFireing;
-(void)checkHits;

-(void)checklvl;

@end
As you can see we have some new methods to fill with code, but I've also modified some of the existing ones, so watch for changes.
We create IBOutlets as we will be referring to the background to switch the image in it while we move on in the game, and refer to the buttons to change some properties of them.
We also create a new UIImageView called flash witch will help us animate the gun fire. We then also create an NSTimer to check for hits on the enemies (in future tutorials).
The NSUIntegers I created are to keep track of some numbers, like the level or stage we currently are at or the maximum vertical range we can let our little soldier move on the iPhones screen.
As for the methods, I think the names speak for them self, if not, you'll see when we right the actual code.

Changing the xib:
Open the xib in Interface Builder and make the changes so it looks like on the screenshot below.


You will also need:
iPhone Game Tutorial (Part 2)


Connect all the IBOutlets to its appropriate Element (buttons and background) and set the following methods:

buttonRight Touch Down => Walk
buttonRight Touch Up Inside => stopWalking

buttonUp Touch Down => walkUp
buttonUp Touch Up Inside => stopWalkingUp

buttonDown Touch Down => walkDown
buttonDown Touch Up Inside => stopWalkingDown

buttonFire Touch Down => triggerPulled
buttonFire Touch Up Inside => triggerReleased

we can also remove the image from our background as we'll set it later in the code.
And that's it for the xib. Save and close it.

Moving on to the .m:

I've done some changes to the viewDidLoad method
- (void)viewDidLoad {
[super viewDidLoad];
lvl = 1;
topLimit = 140;
bottomLimit = 260;

walkImages = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:@"w1.png"], [UIImage imageNamed:@"w2.png"],
[UIImage imageNamed:@"w3.png"], [UIImage imageNamed:@"w4.png"],
[UIImage imageNamed:@"w5.png"], [UIImage imageNamed:@"w6.png"], nil];

player = [[UIImageView alloc] initWithFrame:CGRectMake(100, 220, 30, 30)];
player.image = [UIImage imageNamed:@"stand.png"];
player.animationDuration = 1.5;
player.contentMode = UIViewContentModeBottomLeft;

fireImages = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:@"flash1.png"],
[UIImage imageNamed:@"flash2.png"], nil];

flash = [[UIImageView alloc] init];
flash.animationDuration = 0.18;
flash.contentMode = UIViewContentModeBottomLeft;


[self.view addSubview:player];
[self.view addSubview:flash];
[self checklvl];
}
As you can see, we've now filled up another array with 2 images and given the new UIImageView some instructions. BUT we haven't actually placed it on the iPhone screen yet (no frame yet).
#pragma mark - #pragma mark My Methods

-(void)disableMovementButtons {
buttonUp.enabled = NO;
buttonDown.enabled = NO;
buttonRight.enabled = NO;
}

-(void)enableMovementButtons {
buttonUp.enabled = YES;
buttonDown.enabled = YES;
buttonRight.enabled = YES;
}
When the player is sawing away bullets on hordes of enemies (which don't exist yet) we don't want him to be able to run around like Rambo... and screw around with our o so simple animation. That's why we'll use these two methods to simply dis- enable the buttons.
#pragma mark - #pragma mark IB Actions

-(IBAction)walk {
if(player.frame.origin.y > topLimit &&
player.frame.origin.y < bottomLimit) {
[self startMovingForward];
player.animationImages = walkImages;
[player startAnimating];

buttonUp.enabled = NO;
buttonDown.enabled = NO;
}
}

-(IBAction)stopWalking {
[player stopAnimating];
[walkingTimer invalidate];
buttonUp.enabled = YES;
buttonDown.enabled = YES;
}

-(IBAction)walkUp {
[self startMovingUp];
player.animationImages = walkImages;
[player startAnimating];
buttonRight.enabled = NO;
buttonDown.enabled = NO;
}

-(IBAction)stopWalkingUp {
[player stopAnimating];
[walkingTimer invalidate];
buttonRight.enabled = YES;
buttonDown.enabled = YES;
}

-(IBAction)walkDown {
[self startMovingDown];
player.animationImages = walkImages;
[player startAnimating];
buttonUp.enabled = NO;
buttonRight.enabled = NO;
}

-(IBAction)stopWalkingDown {
[player stopAnimating];
[walkingTimer invalidate];
buttonUp.enabled = YES;
buttonRight.enabled = YES;
}

-(IBAction)triggerPulled {
[self startFireing];
flash.animationImages = fireImages;
[flash startAnimating];
[self disableMovementButtons];
}

-(IBAction)triggerReleased {
[fireTimer invalidate];
[flash stopAnimating];
[self enableMovementButtons];
}
All fairly simple and similar to first part of the tutorial. However, we added a little IF to move to the next stage and reset our position when we reach the end of the iPhone screen.
#pragma mark Weapon use

-(void)startFireing {
flash.frame = CGRectMake((player.frame.origin.x)+30, (player.frame.origin.y)+10, 15, 10);
fireTimer = [NSTimer scheduledTimerWithTimeInterval:0.18
target:self
selector:@selector(checkHits)
userInfo:nil
repeats:YES];
}

-(void)checkHits {

}
Here comes the part you've been waiting for! We orientate on the origin of the player frame and displace the flash so that it aligns with the gun barrel. We will not check if we hit anything yet as there isn't anything we could shoot at but we'll get to that in the next tutorial.
#pragma mark -
#pragma mark world events

-(void)checklvl {
switch (lvl) {
case 1:
background.image = [UIImage imageNamed:@"bg1.png"];
break;
case 2:
background.image = [UIImage imageNamed:@"bg2.png"];
topLimit = 170;
break;
case 3:
background.image = [UIImage imageNamed:@"bg3.png"];
break;
case 4:
background.image = [UIImage imageNamed:@"bg4.png"];
break;
case 5:
background.image = [UIImage imageNamed:@"bg5.png"];
break;
case 6:
background.image = [UIImage imageNamed:@"bg6.png"];
break;
case 7:
background.image = [UIImage imageNamed:@"bg7.png"];
break;
case 8:
background.image = [UIImage imageNamed:@"bg8.png"];
topLimit = 140;
break;
}
}
Easy enough. Later on we can also change parameters like number of enemies or type of enemies etc etc depending on the stage. Cool, huh?
You'll find the backgrounds here:

Alright, I hope I didn't leave anything out. That should do it for today. Try running around and through all stages and don't forget to shoot here and there to make you look more dangerous.

PS: I think the editor for the post here might have swollowed some code or something. I did fix one part but incase you find something that looks weird, write a coment
Reblog this post [with Zemanta]

7/30/2009

iPhone Game Tutorial (Part 1)

I thought I could share my methods on how I animate and move stuff around on the iPhone for games with you.
As always, these are just my ways of doing it. I'm sure there are better ways but I'm also very sure that there are far worse ways as well.



First comes first:
What do we want to make this app do ?
As a starter I thought it would be cool having a little man being able to run across the screen in an animated fashion.
You'll need the sprites and the background so it looks nicer.

Sprites


Once downloaded we can move on.

Create the Project:
Easy enough. Create a View Based Application. Give it a name and move to the viewController.h.

ViewController.h:
We will need to add a few things here.
Our project is going to need a UIImageView to display our little soldier.
We are also going to need an array to hold our images for the walking animation.
For the movement I like using a timer, so we'll create that too.

As for the functions, we're going to use a button to make the little guy walk across the screen of our iPhone.
So we'll create two functions for that. The name explains itself, right?
The other two void functions will be used by the timer.
@interface AnimateViewController : UIViewController {
UIImageView *player;
NSArray *walkImages;
NSTimer *walkingTimer;
}

-(IBAction)walk;
-(IBAction)stopWalking;
-(void)startMovingForward;
-(void)moveForward;

Moving on the ViewController.m:
First we're going to create our little world for the little guy to walk around on.

Make the application load in Landscape mode

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

Interface Builder:
Now open the ViewController.xib and click on the gray arrow in the top corner of the view. This will make the view rotate into landscape. Add a UIImageView, have it take the whole screen and display "wof028.png" in it and set the mode to aspect fit.
Don't forget to add a UIButton in the top right corner to make the soldier walk.
Go to the Button Connections and assign the function "Walk" to "Touch Down" and "StopWalking" to "Touch Up Inside".
Save and close the Interface Builder.

Back to .m:
Insert the following in the viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];

walkImages = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:@"w1.png"], [UIImage imageNamed:@"w2.png"],
[UIImage imageNamed:@"w3.png"], [UIImage imageNamed:@"w4.png"],
[UIImage imageNamed:@"w5.png"], [UIImage imageNamed:@"w6.png"], nil];

player = [[UIImageView alloc] initWithFrame:CGRectMake(100, 220, 30, 30)];
player.image = [UIImage imageNamed:@"stand.png"];
player.animationDuration = 1.5;
player.contentMode = UIViewContentModeBottomLeft;
[self.view addSubview:player];

}

Here we simply assigned the images to the array. We could do it with a loop too (which is recommendable if you have more than just a few files) but for this example I wanted to show it like this to make it clearer.

We also initiate our ImageView "player" with a frame (CGRect). A frame is just that. A frame that holds the position of our image. Much like a picture frame in real life. If you don't understand the numbers of CGRectMake try altering them and see what happens.
We also assign a standard "standing" pose with the "stand.png" to the player.

The animation duration number is the number of seconds it need to cycle through the whole animation. You'll need to try and see what works good for you. For this example I use 1.5.

The ContentMode sets where the images will be placed every time in the frame. This is important when the sprites are of different sizes. In our case, not so much.

Last, we add the image to our view.

Taking care of the rest:
Add the following:

#pragma mark -
#pragma mark IB Actions

-(IBAction)walk {
[self startMovingForward];
player.animationImages = walkImages;
[player startAnimating];
}

-(IBAction)stopWalking {
[player stopAnimating];
[walkingTimer invalidate];
}

#pragma mark Move it

-(void)startMovingForward {
walkingTimer = [NSTimer scheduledTimerWithTimeInterval:0.125 target:self selector:@selector(moveForward) userInfo:nil repeats:YES];
}

-(void)moveForward {
player.frame = CGRectMake(((player.frame.origin.x)+5), 220, 30, 30);
}

Pragma Mark ??
Pragma Mark can help you organize your code for when it gets very long. Copy the code above and then click on the two arrows pointing up and down at the top back above your code. This will open an index of your methods and the pragma mark text will help you find what you need.

When we tap on the button we'll start the "walk" function. The walk function starts the "moveForward" function, assigns the array walkImages to the property animationImages of our player ImageView and tells the program to start Animating "player".

startMovingForward will just start the timer. We give it an interval to work with and in the selector we tell it to activate "moveForward" on every interval. Don't forget to tell the timer to repeat itself.

moveForward will finally take care of the actual moving of the little soldier. We assign a new frame to player which is the same as the current one but we add 5 pixel to its x axis.

When we lift our finger from the Walking button, the animation and the timer will be stopped.

Build and run the application. See how it goes.
Reblog this post [with Zemanta]

7/01/2009

[iPhone] Quartz 2D

Quartz ComposerImage via Wikipedia

The last week I've been fighting to get some stuff working in Quartz. Actually I've been trying to get Quartz itself to work.
I've now managed and thought I could share:

Open your viewController.xib and add a view inside your view. Size it and move it the way you want it. This is the view that you will use like a tv screen, showing all your Quartz drawing.
(This is the way I am doing it for a specific app. I'm sure you'll find your way that fits your app the most.)

Select the view and press ⌘4 and change the class to, lets say, "QuartzView".
Select File>Write Class File and check the box to create the .h file too.

Once created, the files will be in your project.
in the QuartzView.h:
@interface QuartzView : UIView {
UIColor *color;
}
@end
Switch over to the .m file.
The drawRect method is the one where we'll do all the drawing. The drawing code has to be in this method as far as I know.

Lets start filling in some code in the drawRect method then and try to draw a line.
First, we set the color for our line and retrieve the context. The context is like your canvas where you'll be drawing. All the drawing is done in a context. As we'll only have one context, I'll call it (who would have guessed) "context" :

color = [UIColor redColor];
CGContextRef context = UIGraphicsGetCurrentContext();

Then, we set some properties of the line we're going to draw. They are pretty self explanatory. You always define the context (which we cleverly called "context") and the specific attribute of the property.

CGContextSetLineWidth(context, 2.0); // We set a 2px thick line.
CGContextSetStrokeColorWithColor(context, color.CGColor);
CGContextSetFillColorWithColor(context, color.CGColor);
//This settings want a CGColor and not a UIColor. Good for us, UIColor has a property that returns the color as a CGColor.
Now that we've set the properties of the line we're about to draw, lets prepare the actual movement required to draw a line.

We'll create 2 CGPoints which basically just group an X & Y coordinate of the screen in one variable.

CGPoint startingPoint = CGPointMake(20.0, 20.0);
CGPoint finishingPoint = CGPointMake(80.0, 80.0);

Now, we move our virtual drawing hand (with the pencil we've defined earlier) to the starting point and then make it move to the finishing point. We then just have to say to actually draw that line and to update our view. 4 lines of code.

CGContextMoveToPoint(context, startingPoint.x, startingPoint.y);
CGContextAddLineToPoint(context, finishingPoint.x, finishingPoint.y);
CGContextStrokePath(context);
[self setNeedsDisplay];
Right, so that's the basics. I'll probably go into more details once I've figured it out better myself soon.
Reblog this post [with Zemanta]