Hello Guyz today we will be starting with what we left in our previous post. For those who werent following: In our last post we made a bird shooting game named Kill 'em All. You can view the post here.
Today we will continue from the spot making the cannon rotate as we shoot the birds (high in the sky :D)
1. Adding and replacing some Resources
2. Keeping the track of our cannon and next Projectile
3. The main code
4. Tap....rotate.....bang.....veeeeEEeeee!!!!
iPhone Made Easy
Friday, December 3, 2010
Sunday, November 28, 2010
My first game - Kill 'em all! (Part I)
Hello guys.
It took me nearly a month to get my first simple game up on my device. So here I am writing this post for all my fellow iphone game beginners to make sure they get their first game up in less than 24 days. Seriously guys I do mean it!!!
So hitting the deck, things you will need :
1. XCode
2. iPhone SDK
3. Cocos2d
XCode+iPhone SDK is a big download and can be found in Apple's website. So I suggest you start downloading now. (You can download the both for free here but you need to sign up first).
Cocos2d is the world's most famous iphone game engine for 2d games. Most of the developers use Cocos2d for their games. Famous games like StickWars and Gorillaz that are on app store were created using cocos2d. Some of the famous games for inspirations written with cocos can be found here. So, what are you waiting for? Install the framework now (download page). For instructions on how to install the framework visit here.
If you are still with me and have followed the instructions on the page you should have now helloWorld scene running on your simulator/device. Before diving right into the code it is vital that you know about
1. Scenes
2. Layers
3. Directors
4. Sprites
A short and basic description about these can be found here
Now when everything is lined up lets get going with our new game. Its a bird shooting game where you will have to shoot the birds flying in the air. When we are completed our game will look something like this :
Hit build and go and you should see the hello world screen.
4. Kill 'em All-Time to shoot!
Yes peeps its time to shoot now. The cannon balls that we had in arsenals are about to get loose with the touch of your finger. So unlike the soldiers on the field get this line in your init function right at the start of the if block.
We have to do a little maths here. When we touch our screen we will get a point. Remember in CCMoveTo function we need two parameters: duration and destinationPoint. So the cannonball that will be released from our cannon needs duration and destination point both. They both will be calculated by maths as initially we dont know what they are. Refer to the picture for more detailed description:
Now we are going to shoot a cannon ball as soon as our touch ends, that is finger is raised from the screen. To do so, add the function -(void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event{} with following lines of codes:
Guess not. We need to add some collision detection for our compiler to know that the birds have been hit by the cannon. After the collision is detected we will remove both the bird and the cannon from the screen. Doing this is as easy as it sounds.
First of all we need to keep the count of the cannons as well as birds that are on the screen. We will do so by NSMutableArray .We will add the birds in the array as soon as they appear on the scrren. And delete them from the array as soon as they disappear or get hit by the cannon. Same goes for cannon balls. So in HelloWorldScene.h, declare two NSMutableArrays _cannonBalls and _birds.
Hit Build and Run!!! Smack That all on the floor,... lolz
Finally we almost have a working game.. You deserve a pat on the shoulders now... :)
The birds and cannons shall disappear after colliding.
Apart from the fact that our game is functional now, no game is complete without decent graphics and sounds. You will me amazed to see how easy cocos has made to add both of them in your game!!!
It took me nearly a month to get my first simple game up on my device. So here I am writing this post for all my fellow iphone game beginners to make sure they get their first game up in less than 24 days. Seriously guys I do mean it!!!
So hitting the deck, things you will need :
1. XCode
2. iPhone SDK
3. Cocos2d
XCode+iPhone SDK is a big download and can be found in Apple's website. So I suggest you start downloading now. (You can download the both for free here but you need to sign up first).
Cocos2d is the world's most famous iphone game engine for 2d games. Most of the developers use Cocos2d for their games. Famous games like StickWars and Gorillaz that are on app store were created using cocos2d. Some of the famous games for inspirations written with cocos can be found here. So, what are you waiting for? Install the framework now (download page). For instructions on how to install the framework visit here.
If you are still with me and have followed the instructions on the page you should have now helloWorld scene running on your simulator/device. Before diving right into the code it is vital that you know about
1. Scenes
2. Layers
3. Directors
4. Sprites
A short and basic description about these can be found here
Now when everything is lined up lets get going with our new game. Its a bird shooting game where you will have to shoot the birds flying in the air. When we are completed our game will look something like this :
Final Version of the game you are about to build |
1. Starting the new cocos project
Launch XCode and under files menu click New Project. Click on the first template (the most simplest one) cocos2d-application as shown in the figure. Name the project as "Kill Them All".
Click on the first template |
Screen that appears in the simulator |
2. Adding our cannon!
Now expand the classes folder and HelloWorldScene.m and find the function init, and remove everything inside the if (self=[super init]) block. Actually this is where our hello world label was being created. We will add our code to add some sprites over here. The new init will look something like this:
Before adding the new sprites let us add some resources onto our project. You can download the images that I made :
Download the images and drag them over to your resources folder. Check copy if necassary option if unchecked. Now we have all the resources we require for our game. Time to add them to our scene!
We will going to add the cannon first in the middle of the screen (horizontally) and at the bottom (vertically). We will do this by making a sprite with the cannon.png and setting its position to required co-ordinates. In HelloWorldScene.m find the init function and add these lines of code.
-(id) init{// always call "super" init// Apple recommends to re-assign "self" with the "super" return valueif( (self=[super init] )) {}return self;}
Before adding the new sprites let us add some resources onto our project. You can download the images that I made :
bird.png |
cannon.png |
cannonball.png |
We will going to add the cannon first in the middle of the screen (horizontally) and at the bottom (vertically). We will do this by making a sprite with the cannon.png and setting its position to required co-ordinates. In HelloWorldScene.m find the init function and add these lines of code.
-(id) init{// always call "super" init// Apple recommends to re-assign "self" with the "super" return valueif( (self=[super init] )) {CGSize winSize=[[CCDirector sharedDirector] winSize];
CCSprite * cannon = [CCSprite spriteWithFile:@"cannon.png" rect:CGRectMake(0, 0, 30, 40)];
First of all we ask the director (singleton object) for the size of the current scene. Our current scene is the size of the iphone screen (480*320) in landscaped position. Next we make a sprite using our cannon.png. Now for the important part, placing the cannon. ccp (cocos 2d point) takes (x,y) position. While programming in cocos framework our bottom left corner is (0,0). Value of x increases horizontally and y increases vertically. A sprite is always places according to its midpoint. Refer to the picture for more precise details.cannon.position=ccp(winSize.width/2,cannon.contentSize.height/2);[self addChild:cannon];}return self;}
Before adding birds let us change the color of our screen to white as the color of our birds is black. To do so open HelloWorldScene.h and change the parent class of HelloWorldScene from CCLayer to CCColorLayer
#import "cocos2d.h"
// HelloWorld Layer@interface HelloWorld : CCColorLayer{}
// returns a Scene that contains the HelloWorld as the only child+(id) scene;
@end
Now in the init function of the HelloWorldScene.m change within the if block so that the code looks like
if( (self=[super initWithColor:ccc4(255, 255, 255, 255)] )) {
Now you should have something like this :
iPhone Simulator |
3. Making the birds fly by!
Easy till now, eh ? Well be with me when I say the rest of the game is equally easy. Now first of all we select the region we want to get the birds fly. Refer to the picture for details. The shaded region shows the area where the birds will fly.
Easy till now, eh ? Well be with me when I say the rest of the game is equally easy. Now first of all we select the region we want to get the birds fly. Refer to the picture for details. The shaded region shows the area where the birds will fly.
If its a bit hard-to-get at the moment , do not worry too much for you will understand as soon as we write some code. First of all in HelloWorldScene.m open the init function and these lines of code right after you have added cannon.
This line tells the compiler that we want the function addBirds to be called after every 0.5 of a second. Next step is to add the function addBirds().[self schedule:@selector (addBirds:) interval:0.5];
First of all we initiate our sprite with bird.png. Then we calculate the range by setting min and max values of Y. After having placed our bird on the screen (a bit left from the main screen) we move towards the more pressing matter: moving the birds. After setting a duration in the same manner as we have set the range we look forward to three important functions:
-(void)addBirds:(ccTime) dt{
//Initing the sprite with the bird.pngCCSprite * bird=[CCSprite spriteWithFile:@"bird.png" rect:CGRectMake(0, 0, 29, 30)];//Setting min and max yCGSize winSize=[[CCDirector sharedDirector] winSize];int maxY=winSize.height-bird.contentSize.height/2;int minY=winSize.height/2;int rangeY=maxY-minY;int actualY=arc4random()%rangeY+minY;//Placing the birdbird.position=ccp(winSize.width+bird.contentSize.width/2,actualY);[self addChild:bird];//Moving the birdint minSpeed=2.0;int maxSpeed=4.0;int rangeSpeed=maxSpeed-minSpeed;int actualRange=arc4random()%rangeSpeed+minSpeed;int actualDestinationY=arc4random()%rangeY+minY;id moveTo=[CCMoveTo actionWithDuration:actualRange position:ccp(-bird.contentSize.width/2,actualDestinationY)];id removeFromScreen=[CCCallFuncN actionWithTarget:self selector:@selector(spriteMoveFinished:)];[bird runAction:[CCSequence actions:moveTo,removeFromScreen,nil]];}
- CCMoveTo
- CCCallFunc
- runAction
CCMove takes duration and point and moves the target towards that point. In this case we pass random duration b/w 2 and 4 we have set. We know destinationX is a bit right from screen while Y again is set random. CCCallFunc calls a function passing itself as argument. We pass it to spriteMoveFinished: (we will write it shortly to dispose off the sprite that have completed the move). Finally we run the action on our sprite with the stated sequence. Lets write spriteMoveFinished:
Hit build and run and vohoooooOOOoo . Now you have flying birds passing by :) . It must look something like this:-(void)spriteMoveFinished:(id)sender{CCSprite * sprite=(CCSprite *)sender;[self removeChild:sprite cleanup:YES];}
iPhone Simulator |
4. Kill 'em All-Time to shoot!
Yes peeps its time to shoot now. The cannon balls that we had in arsenals are about to get loose with the touch of your finger. So unlike the soldiers on the field get this line in your init function right at the start of the if block.
Guess dont have to explain that one, eh ? :)self.isTouchEnabled=YES;
We have to do a little maths here. When we touch our screen we will get a point. Remember in CCMoveTo function we need two parameters: duration and destinationPoint. So the cannonball that will be released from our cannon needs duration and destination point both. They both will be calculated by maths as initially we dont know what they are. Refer to the picture for more detailed description:
Explaination-I |
Explaination-II |
Now we are going to shoot a cannon ball as soon as our touch ends, that is finger is raised from the screen. To do so, add the function -(void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event{} with following lines of codes:
Remember from high school physics that s=vt. We need all the cannon balls to go uniformly. Thus we keep the v constant. We calculate S by pythagoras theorem for calculating length of the hypotenuse. Lastly we calculate time by t=s/v. Fairly simple! Hit build and go and now you should be able to shoot cannon balls!!!-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{//Choose one of the touchUITouch * touch = [touches anyObject];CGPoint location = [touch locationInView:[touch view]];location=[[CCDirector sharedDirector] convertToGL:location];//Setup initial position of the projectileCGSize winSize=[[CCDirector sharedDirector] winSize];CCSprite * cannonball = [CCSprite spriteWithFile:@"cannonball.png" rect:CGRectMake(0, 0, 20, 20)];cannonball.position=ccp(winSize.width/2,40);//Determining the offSet of the touch from projectileint offX= location.x-cannonball.position.x;int offY= location.y-cannonball.position.y;//Discard if touch's y<=0if (offY<=0) return;//Adding the projectile[self addChild:cannonball];//Determine where to shoot the projectile toint realY = winSize.height+cannonball.contentSize.height/2;float ratio=(float)offY/(float)offX;int realX=(realY/ratio)+cannonball.position.x;CGPoint realDestination = ccp(realX,realY);//Determining the lenght of how far we are shooting so as to to make the speed uniformint offRealX=realX-cannonball.position.x;int offRealY=realY-cannonball.position.y;float distance=sqrtf((offRealX*offRealX)+(offRealY*offRealY));float velocity=325;float duration=distance/velocity;//Move projectile[cannonball runAction:[CCSequence actions:[CCMoveTo actionWithDuration:duration position:realDestination],[CCCallFuncN actionWithTarget:self selector:@selector(spriteMoveFinished:)],nil]];}
iPhone Simulator |
4. What? Are they mortal?!?
First of all we need to keep the count of the cannons as well as birds that are on the screen. We will do so by NSMutableArray .We will add the birds in the array as soon as they appear on the scrren. And delete them from the array as soon as they disappear or get hit by the cannon. Same goes for cannon balls. So in HelloWorldScene.h, declare two NSMutableArrays _cannonBalls and _birds.
And initiatate the arrays in init@interface HelloWorld : CCColorLayer{NSMutableArray * _birds;NSMutableArray * _cannonBalls;}
Also release them in the dealloc funciton in HelloWorldScene.m_birds=[[NSMutableArray alloc] init];_cannonBalls=[[NSMutableArray alloc] init];
Now as soon as the birds enter the scene add and tag them. You will see why tagging is being done in a moment. In the addBirds: function add these lines at the end.- (void) dealloc{[_birds release];[_cannonBalls release];[super dealloc];}
And in the touchend method where the cannon balls are being created add these lines at the endbird.tag=1;[_birds addObject:bird];
Now remove them from the array as soon as the move is finished otherwise memory leak issues will arrise. This is done in the spriteMoveFinished method:cannonball.tag=2;[_cannonBalls addObject:cannonball];
Now when we have the count for the cannonballs and the birds lets proceed towards the collision detection. For the purpose open the HelloWordScene.m file and in the init add these lines right after [self schedule:@selector (addBirds:) interval:2.0];if (sprite.tag==1) {[_birds removeObject:sprite];}else if (sprite.tag==2) {[_cannonBalls removeObject:sprite];}
Note that unlike adding the birds in which we called addBirds: after 2.0 seconds, we dont pass any duration period here. This is because we want update method to be called as soon as possible. Now for adding the update method.[self schedule:@selector (update:)];
The logic of the update function is that of a bubble sort or in simple words two nested for loops. For every cannonball we will check every bird that is on the screen. We do so by making a cannonRectangle with the help of cannonBall and a birdRect with the help of bird. Finally we check for the intersection of the two rects. If found we add the objects in birds-to-delete and cannonBallstoDelete array. Note that we cannot directly remove objects from _birds and _cannonBalls because during iteration you cannot do so in NSMutableArrays.-(void)update:(ccTime)dt{NSMutableArray * cannonBallsToDelete=[[NSMutableArray alloc]init];for(CCSprite * ball in _cannonBalls) {CGRect ballRect = CGRectMake(ball.position.x-ball.contentSize.width/2,ball.position.y-ball.contentSize.height/2,ball.contentSize.width,ball.contentSize.height);NSMutableArray * birdsToDelete=[[NSMutableArray alloc] init];for (CCSprite * bird in _birds) {CGRect birdRect = CGRectMake (bird.position.x - (bird.contentSize.width/2),bird.position.y - (bird.contentSize.height/2),bird.contentSize.width,bird.contentSize.height);if (CGRectIntersectsRect(birdRect,ballRect)) {[birdsToDelete addObject:bird];}}for (CCSprite * bird in birdsToDelete) {[_birds removeObject:bird];[self removeChild:bird cleanup:YES];}if (birdsToDelete.count>0) {[cannonBallsToDelete addObject:ball];}[birdsToDelete release];}for (CCSprite *ball in cannonBallsToDelete) {[_cannonBalls removeObject:ball];[self removeChild:ball cleanup:YES];}
[cannonBallsToDelete release];}
Hit Build and Run!!! Smack That all on the floor,... lolz
Finally we almost have a working game.. You deserve a pat on the shoulders now... :)
The birds and cannons shall disappear after colliding.
5. Adding a decent background
We will start by adding a background. Now professionally you would add a different layer for the background but for beginners we will add a new sprite with a background on the same layer. We will make sure the background sprite is beneath all of the other sprites otherwise all of the birds, cannonballs and our cannon will become invisible under the bg.
You can use this background that I made. Save this to your disk and drag'n'drop to your resources folder.
Save this bg and add to your resources folder of xcode |
Now open HelloWorldScene.m and make sure you add the lines of code BEFORE you add the cannon otherwise cannon will hide.
My whole init function uptill now looks something like this
-(id) init{// always call "super" init// Apple recommends to re-assign "self" with the "super" return valueif( (self=[super initWithColor:ccc4(255, 255, 255, 255)] )) {self.isTouchEnabled=YES;_birds=[[NSMutableArray alloc] init];_cannonBalls=[[NSMutableArray alloc] init];CGSize winSize=[[CCDirector sharedDirector] winSize];
CCSprite * background = [CCSprite spriteWithFile:@"background.png" rect:CGRectMake(0, 0, 480, 320)];background.position=ccp(winSize.width/2,winSize.height/2);[self addChild:background];CCSprite * cannon = [CCSprite spriteWithFile:@"cannon.png" rect:CGRectMake(0, 0, 30, 40)];cannon.position=ccp(winSize.width/2,cannon.contentSize.height/2);[self addChild:cannon];[self schedule:@selector (addBirds:) interval:0.7];[self schedule:@selector (update:)];}return self;}
Add the bold lines to the game.
5. Chime Time!
Now for adding the sound. We will use three sounds in our game. One for the background, one for cannon ball shoot and the last one for killing the birds.
You can get the background sound from here. (This music is a property of Raywenderlich and only due to the fact that he has marked his link as a free download I am pasting the link here.) Its licensed as free or you may use any other sound you like (of the type .aiff,.caf,.wav). Just download and add into your resources folder.
In HelloWorldScene.h import SimpleAudioEngine.h
Now for the other two sounds, I have choosen this(click.wav).
Download and add it as well to the resources folder of your project.
Add this line in your cctouchesended function :
Select the classes folder and hit opt-N or select new file from File menu. Make a class with name GameOverScene and make sure .h option is selected.
Now for telling the HelloWorldScene when to display this scene. We will make our game logic as:
1. Game over if 3 birds pass by.
2. You win if you kill 10 birds.
So add these ints to HelloWorldScene.h
Add the bolded lines :
Build hit and go and enjoy your own ready made challenging game!!!
Final game should look like this
You can get the background sound from here. (This music is a property of Raywenderlich and only due to the fact that he has marked his link as a free download I am pasting the link here.) Its licensed as free or you may use any other sound you like (of the type .aiff,.caf,.wav). Just download and add into your resources folder.
In HelloWorldScene.h import SimpleAudioEngine.h
and in the HelloWorldScene.m in the init function get the audio engine to play the background music.#import "SimpleAudioEngine.h"
Simple, aint it ?[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"raywenderlich"];
Now for the other two sounds, I have choosen this(click.wav).
Download and add it as well to the resources folder of your project.
Add this line in your cctouchesended function :
and in the update: method where you are detecting the collision, that is the if block of the intersection check[[SimpleAudioEngine sharedEngine] playEffect:@"click.wav"];
if (CGRectIntersectsRect(birdRect,ballRect)) {
[birdsToDelete addObject:bird];
[[SimpleAudioEngine sharedEngine] playEffect:@"click.wav"];
}}
Hit build and go and you will start to like the game even more :) 6. This is a game and it gets over, you know :/
Now lastly for adding the game over and the win scene.
Once made open GameOverScene.h and replace the contents with these lines of code here
and replace the contents of the GameOverScene.m with these lines#import "cocos2d.h"
@interface GameOverLayer : CCColorLayer {CCLabel * _label;}@property (nonatomic, retain) CCLabel *label;@end
@interface GameOverScene : CCScene {GameOverLayer *_layer;}@property (nonatomic, retain) GameOverLayer *layer;@end
#import "GameOverScene.h"#import "HelloWorldScene.h"
@implementation GameOverScene@synthesize layer = _layer;
- (id)init {if ((self = [super init])) {self.layer = [GameOverLayer node];[self addChild:_layer];}return self;}
- (void)dealloc {[_layer release];_layer = nil;[super dealloc];}
@end
@implementation GameOverLayer@synthesize label = _label;
-(id) init{if( (self=[super initWithColor:ccc4(255,255,255,255)] )) {CGSize winSize = [[CCDirector sharedDirector] winSize];CCSprite * background = [CCSprite spriteWithFile:@"background.png" rect:CGRectMake(0, 0, 480, 320)];background.position=ccp(winSize.width/2,winSize.height/2);[self addChild:background];self.label = [CCLabel labelWithString:@"" fontName:@"Arial" fontSize:32];_label.color = ccc3(0,0,0);_label.position = ccp(winSize.width/2, winSize.height/2);[self addChild:_label];[self runAction:[CCSequence actions:[CCDelayTime actionWithDuration:3],[CCCallFunc actionWithTarget:self selector:@selector(gameOverDone)],nil]];}return self;}
- (void)gameOverDone {[[CCDirector sharedDirector] replaceScene:[HelloWorld scene]];}
- (void)dealloc {[_label release];_label = nil;[super dealloc];}
@end
I am sure up till now these lines have become self explanatory!!!
Now for telling the HelloWorldScene when to display this scene. We will make our game logic as:
1. Game over if 3 birds pass by.
2. You win if you kill 10 birds.
So add these ints to HelloWorldScene.h
After addingint birdsKill;int birdsPass;
#import "GameOverScene.h"
in HelloWorldScene.m add these lines to your spriteMoveFinished function. The lines will go inside the if (sprite.tag==1) because this is the place where we know our bird has flown by:
Code to display the you win tag will go in the if (intersectionRect) block of the update because that is where we see if we have shot any bird.if (sprite.tag==1) {[_birds removeObject:sprite];NSLog(@"bird removed");birdsPass++;if (birdsPass==3) {birdsPass=0;GameOverScene *gameOverScene = [GameOverScene node];[gameOverScene.layer.label setString:@"You Lose :["];[[CCDirector sharedDirector] replaceScene:gameOverScene];}
Add the bolded lines :
if (CGRectIntersectsRect(birdRect,ballRect)) {[birdsToDelete addObject:bird];[[SimpleAudioEngine sharedEngine] playEffect:@"click.wav"];if (birdsKill==10) {birdsKill=0;GameOverScene *gameOverScene = [GameOverScene node];[gameOverScene.layer.label setString:@"You Lose :["];[[CCDirector sharedDirector] replaceScene:gameOverScene];
}
Build hit and go and enjoy your own ready made challenging game!!!
Final game should look like this
iPhone Simulator |
7. Show me the Codeeeee!!!!
Congratz..... *hand shake* you have successfully completed your first simpe full working game in no time! You can find the code of this whole game here. Also see the next post where we put some animations into this game to make it more realistic!!! Till thn... Audios
Subscribe to:
Posts (Atom)