How To Make A Simple iPhone Game with Cocos2D 3.0 Tutorial

Let there be ninjas! In this Cocos2D 3.0 tutorial, you’ll learn how to make a simple iPhone game, even if you’re a complete beginner. By Martin Walsh.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

A Wild Monster Appears

Next you want to add some monsters into your scene. A static monster is of course no challenge to an experienced ninja, so to make things a bit more interesting you will add some movement to the monsters. You will create the monsters slightly off screen to the right and set up a CCAction for them, telling them to move from right to left.

Add the following code to HelloWorldScene.m:

- (void)addMonster:(CCTime)dt {
 
    CCSprite *monster = [CCSprite spriteWithImageNamed:@"monster.png"];
    
    // 1
    int minY = monster.contentSize.height / 2;
    int maxY = self.contentSize.height - monster.contentSize.height / 2;
    int rangeY = maxY - minY;
    int randomY = (arc4random() % rangeY) + minY;
    
    // 2
    monster.position = CGPointMake(self.contentSize.width + monster.contentSize.width/2, randomY);
    [self addChild:monster];
    
    // 3
    int minDuration = 2.0;
    int maxDuration = 4.0;
    int rangeDuration = maxDuration - minDuration;
    int randomDuration = (arc4random() % rangeDuration) + minDuration;
    
    // 4
    CCAction *actionMove = [CCActionMoveTo actionWithDuration:randomDuration position:CGPointMake(-monster.contentSize.width/2, randomY)];
    CCAction *actionRemove = [CCActionRemove action];
    [monster runAction:[CCActionSequence actionWithArray:@[actionMove,actionRemove]]];
}

Let’s go over this step-by-step:

  1. Define a vertical range for the monster to spawn. When you place a sprite, by default you are placing the center of the sprite. So here you take the screen height and reduce it by the monsters height, so the monster doesn’t end up being cut off.
  2. Position the monster slightly off screen to the right, take the screen width and add the monster’s width to ensure it’s just hidden off screen.
  3. Now you want to decide how long it takes (in seconds) for the monster to move across the screen, let’s randomise it to make the monsters less predictable.
  4. You will use the Cocos2D action CCActionMoveTo: to animate moving the monster from the starting point (slightly off screen right) to the target destination point (slightly off screen left) causing it to move quickly across the screen from right to left.

You have already seen actions in action with the spinning however Cocos2D provides a lot of extremely handy built-in actions, such as move actions, rotate actions, fade actions, animation actions and many more. Here you use three actions on the monster:

  • CCActionMoveTo: This action is used to control the movement of the monster, in this case moving across the screen from right to left. The duration of the action is also specified which controls how long it takes for the monster to move across the screen. The shorter the duration the faster the monster will appear to move. In this case you randomize the duration between 2 and 4 seconds.
  • CCActionRemove: Handy action that removes a node from its parent, effectively “deleting it” from the scene. You use this action to remove the monster from the scene when it is no longer visible (slightly off screen left). This is very important because otherwise you would eventually have tens of thousands of monsters trying to take over your iPhone and consume all device resources.
  • CCActionSequence: The sequence action allows you to chain together a sequence of actions that are performed in order, one at a time. This way you can have the CCActionMoveTo action perform first and once it is complete perform the next action CCActionRemove. This is a very powerful action allowing you to create complex animation sequences.

Great, so now you have a method to add a monster to your scene. However one monster is hardly a challenge for an experienced ninja, let’s create a timed monster spawn method.

Cocos2D features a scheduler that allows you to setup callbacks every X.X seconds, so you can setup a monsters spawn generator to add new monsters every X seconds.

Open up HelloWorldScene.m and add the following code just after [super onEnter]; in the onEnter method.

[self schedule:@selector(addMonster:) interval:1.5];

This will add a Cocos2D scheduler timer to call the previously added addMonster: method every 1.5 seconds.

Note that when you created the addMonster method, there was an additional dt parameter. This stands for delta time, and represents the time difference between the previous and the current frame. The scheduler requires that every method it calls takes this as a parameter, however you will not use it in this tutorial.

Before you see these monsters in action, you will make a couple of changes. Let’s bring everyone out of the shadows a little. Why not change the background color from a dark grey to a lighter grey?

[spoiler]

// 2
CCNodeColor *background = [CCNodeColor nodeWithColor:[CCColor colorWithRed:0.6f green:0.6f blue:0.6f alpha:1.0f]];

[/spoiler]

Your ninja’s head must be spinning by now, can you stop him spinning and also move him over to the left a bit so he can prepare himself for the oncoming frontal assault?

[spoiler]

Disable the head spinning CCActionRotateBy action.

// 6
//CCActionRotateBy* actionSpin = [CCActionRotateBy actionWithDuration:1.5f angle:360];
//[_player runAction:[CCActionRepeatForever actionWithAction:actionSpin]];

Change the position of the Ninja.

_player.position  = ccp(self.contentSize.width/8,self.contentSize.height/2);

You may wonder why you are dividing the width by 8 (1/8th of the screen). This is because it’s often handy to avoid hardcoding absolute positions, since different devices have different screen sizes and would require you to have different absolute positions per device.

If you are interested to learn more, have a look at the CCButton position, notice that it uses a different positionType that uses a normalized resolution of 0..1, 0..1 across all devices.

[/spoiler]

Build and run, and you should now see monsters fly across the screen!

Monsters Attack

Hadouken

Unfortunately your ninja is still not at a high enough level to cast a fireball, so you will need to rely on your expert throwing skills to defeat those evil (or possibly just misunderstood) monsters.

Grab yourself a shuriken and let’s add some projectile action.

You will be using the CCActionMoveTo: again, it’s not however quite as simple as moving to the touch point and starting from the _player.position. You want to throw the projectile across the screen in the direction of the touch. So you have to use a little math.

You have a smaller triangle created by the x and y offset from the origin point to the touch point. You just need to make a big triangle with the same ratio – and you know you want one of the endpoints to be off the screen.

To perform these calculations, it really helps if you have some basic vector math routines available (like methods to easily add and subtract vectors). Cocos2D includes a handy set of vector manipulation functions such as ccpAdd and ccpSub vectors.

If you’re unsure about any of the following calculations, check out this quick vector math explanation. I would personally recommend the excellent Khan Academy video tutorials on the subject.

You got the touch!

The HelloWorldScene templates already comes touch enabled as you saw in the init method.

// 3
self.userInteractionEnabled = YES;

To handle these touches you typically need to create a touchBegan: method however the default template kindly comes with a simple touchBegan method example.

Open HelloWorldScene.m and replace the current touchBegan: method with the following snippet:

- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
    // 1
    CGPoint touchLocation = [touch locationInNode:self];

    // 2
    CGPoint offset    = ccpSub(touchLocation, _player.position);
    float   ratio     = offset.y/offset.x;
    int     targetX   = _player.contentSize.width/2 + self.contentSize.width;
    int     targetY   = (targetX*ratio) + _player.position.y;
    CGPoint targetPosition = ccp(targetX,targetY);
    
    // 3
    CCSprite *projectile = [CCSprite spriteWithImageNamed:@"projectile.png"];
    projectile.position = _player.position;
    [self addChild:projectile ];
    
    // 4
    CCActionMoveTo *actionMove   = [CCActionMoveTo actionWithDuration:1.5f position:targetPosition];
    CCActionRemove *actionRemove = [CCActionRemove action];
    [projectile runAction:[CCActionSequence actionWithArray:@[actionMove,actionRemove]]];
}

Let’s go over this step-by-step:

  1. You need to translate the screen touch into the scene’s coordinate system. There is a handy Cocos2D category on UITouch with locationInNode: that will do this.
  2. So as you can see, you have a small triangle created by the x and y offset from the origin point to the touch point. You just need to make a big triangle with the same ratio – and you know you want one of the endpoints to be off the screen.
  3. Create the projectile sprite and set it to start at the same position as the player. This is why you made _player a private instance variable so you could access it easily later.
  4. You should now be more familiar with the CCActionMoveTo now. You have the previously calculated target point and the duration is the time taken for the projectile to reach this point, so the lower it is, the faster your projectile will travel.

Build and run, and fire at will!

Attack the monsters.

Arggghhh these monsters are too strong, why wont they just die already!

Martin Walsh

Contributors

Martin Walsh

Author

Over 300 content creators. Join our team.