Quantcast
Channel: Kodeco | High quality programming tutorials: iOS, Android, Swift, Kotlin, Unity, and more
Viewing all 4374 articles
Browse latest View live

Video Tutorial: Table Views Moving Rows


Game Center Tutorial: How To Make A Simple Multiplayer Game with Sprite Kit: Part 2/2

$
0
0
Create a simple multiplayer game with Game Center and SpriteKit!

Create a simple multiplayer game with Game Center and SpriteKit!

Update 3/1/14: Updated for iOS 7 and Sprite Kit.

This is the second part of a two part Game Center tutorial series on creating a simple networked game with Game Center matchmaking.

In the first part of the Game Center tutorial series, you learned how to enable Game Center for your app and find matches with other players using the built-in GKMatchmakerViewController.

In this second and final part of the Game Center tutorial series, you’ll learn how to look up player aliases and how to send and receive data between devices.

In the end, you’ll have a fully functional (but simple) networked game that uses SpriteKit and Game Center that you can play with your friends!

Start by downloading the starter project for part 2 of this tutorial. Even though this tutorial is a continuation of the previous Game Center tutorial, I’ve built a slightly modified version of the final project of the last tutorial. Don’t worry, there are hardly any changes – just a few small things to keep the focus of the tutorial squarely on Game Center. I’ll describe the changes in more detail in the next section.

Multiplayer Starter Project

First things first – as soon as you open the starter project, open your target settings and update your Bundle Identifier to whatever you set last time. This is important, so it might be a good idea to open your old project, and double check it matches exactly. Then restart Xcode so the changes are sure to be applied.

Next, let’s take a moment and go through some of the changes I made to the project from the previous tutorial.

  • Open GameViewController.m: you will notice that this class no longer implements the GameKitHelperDelegate protocol.
  • In the GameKit group you will notice a new class i.e. MultiplayerNetworking. This class will contain all the networking code for the game. It will notify the game of important events through a delegate.
  • GameScene now implements the MultiplayerNetworkingProtocol.
  • Since the MultiplayerNetworking class is responsible for managing all networking activity, naturally it will implement the GameKitHelperDelegate protocol.

Those are all the changes to the final project of the last tutorial. Before you proceed make sure that you go through the code a couple of times, so that you’re comfortable with the changes.

Finally, run the project on two devices and tap “Play Now” to find a match. Verify that everything works as before, and that it finds a match and displays this in the console:

CatRaceStarter[3712:60b] Ready to start match!

Network Code Strategy: Picking Players

Let’s talk about the strategy you’re going to take with the network code, starting with how to pick players.

You have two players in this game: player 1 (the dog) and player 2 (the kid). The problem is, how do you decide who should be the dog and which the kid?

The strategy you’re going to take is each side will generate a random number on startup, and send it to the other side. Whichever side has the larger random number will be player 1, and the other side will be player 2.

In the rare event each side generates the same random number, you’ll just try again.

Whichever player is player 1 will get some special “privileges.” First, that side signals the game should start by sending a message to the other side. That side also is the one who is responsible for checking when the game ends, and sending a message to the other side when the game is over (and who won).

In other words, “player 1″ takes the role of the “server”. He’s the final authority on what goes on for this game.

Network Code Strategy: Player Aliases

Since it’s random which player is the dog and which is the kid, you need to have some way of showing the player which one he is.

For this game, you’ll just print the player’s alias right on top of the character they are, so they can tell who they are.

If you don’t know what a player alias is, it’s the nickname that you set up for your account in Game Center. When a match is made, you don’t get these automatically – you have to call a method so Game Center will send them to you.

Network Code Strategy: Game States

One of the challenges with making networked code is that things can happen in different orders than you might expect.

For example, one side may finish initializing the match and send the random number to the other side before the other side even finishes initializing the match!

So if you’re not careful, you can get into strange timing issues in your code that causes problems. One good way to keep things clean is to keep careful track of what state each side of the game is currently in.

The following diagram illustrates the states Cat Race will need:

Game states for this simple networked game

Let’s go through each of these:

  • Waiting for Match: The game is waiting for a match to be connected, and for the player aliases to be looked up. When both of these are complete, it checks to see if it’s received the random number from the other side yet, and advances to the next state appropriately.
  • Waiting for Random #: The game has a match and has the player aliases, but is still waiting to receive a random number from the other side.
  • Waiting for Start: The game is waiting for the other side to start the game (this occurs when the local player is player 2).
  • Active: The game is currently playing – no winner has been found yet. Every time a player moves, they will tell the other side that they’ve moved by sending a message.
  • Done: The game is over (player 1 has sent a message to player 2 to tell him that the game is over). No more messages are sent and the player can then restart the game.

OK now that you have a plan in mind, let’s move onto the first step, which is retrieving the player aliases!

Looking up Player Aliases

Switch to GameKitHelper.h and make the following changes:

// Add after @interface
@property (nonatomic, strong) NSMutableDictionary *playersDict;

This defines a property for a dictionary that will allow easy lookup of GKPlayer data (which includes the player’s alias) based on a player’s unique ID.

Then switch to GameKitHelper.m and make the following changes:

// Add new method after authenticateLocalPlayer
- (void)lookupPlayers {
 
    NSLog(@"Looking up %lu players...", (unsigned long)_match.playerIDs.count);
 
    [GKPlayer loadPlayersForIdentifiers:_match.playerIDs withCompletionHandler:^(NSArray *players, NSError *error) {
 
        if (error != nil) {
            NSLog(@"Error retrieving player info: %@", error.localizedDescription);
            _matchStarted = NO;
            [_delegate matchEnded];
        } else {
 
            // Populate players dict
            _playersDict = [NSMutableDictionary dictionaryWithCapacity:players.count];
            for (GKPlayer *player in players) {
                NSLog(@"Found player: %@", player.alias);
                [_playersDict setObject:player forKey:player.playerID];
            }
            [_playersDict setObject:[GKLocalPlayer localPlayer] forKey:[GKLocalPlayer localPlayer].playerID];
 
            // Notify delegate match can begin
            _matchStarted = YES;
            [_delegate matchStarted];
        }
    }];
}
 
// Add inside matchmakerViewController:didFindMatch, right after @"Ready to start match!":
[self lookupPlayers];
 
// Add inside match:player:didChangeState:, right after @"Ready to start match!":
[self lookupPlayers];

lookupPlayers is the main method here. This is called when the match is ready, and it looks up the info for all of the players currently in the match. It also adds the local player’s information to the dictionary.

Game Center will return a GKPlayer object for each player in the match as a result. To make things easier to access later, this code puts each GKPlayer object in a dictionary, keyed by player ID.

Finally, it marks the match as started and calls the game’s delegate so it can start the game.

Before you move onto that though, test it out! Compile and run your code on two devices, and this time when you examine your console output you should see the players looked up and the game ready to go:

2014-01-06 21:50:13.867 CatRaceStarter[787:60b] Ready to start match!
2014-01-06 21:50:13.874 CatRaceStarter[787:60b] Looking up 1 players...
2014-01-06 21:50:13.894 CatRaceStarter[787:60b] Found player: Olieh
2014-01-06 21:50:13.895 CatRaceStarter[787:60b] Match has started successfully

Adding Network Code

You have the match set up and the player names available, so now you’re on to the real meat of the project – adding the network code!

The first thing you need to do is define game states based on our diagram from earlier. Open up MultiplayerNetworking.m and add the following:

//Add to the top of the file
typedef NS_ENUM(NSUInteger, GameState) {
    kGameStateWaitingForMatch = 0,
    kGameStateWaitingForRandomNumber,
    kGameStateWaitingForStart,
    kGameStateActive,
    kGameStateDone
};

Next you need to define some structures for the messages you’ll be sending back and forth. So add the following to the top of the same file:

typedef NS_ENUM(NSUInteger, MessageType) {
    kMessageTypeRandomNumber = 0,
    kMessageTypeGameBegin,
    kMessageTypeMove,
    kMessageTypeGameOver
};
 
typedef struct {
    MessageType messageType;
} Message;
 
typedef struct {
    Message message;
    uint32_t randomNumber;
} MessageRandomNumber;
 
typedef struct {
    Message message;
} MessageGameBegin;
 
typedef struct {
    Message message;
} MessageMove;
 
typedef struct {
    Message message;
    BOOL player1Won;
} MessageGameOver;

Note that each message starts with a message type – this is so that you have a known number you can look at for each message to identify what type of message it is.

Finally add a few instance variables to the implementation section of the MutliplayerNetorking class:

@implementation MultiplayerNetworking {
  uint32_t _ourRandomNumber;
  GameState _gameState;
  BOOL _isPlayer1, _receivedAllRandomNumbers;
 
  NSMutableArray *_orderOfPlayers;
};

These will keep track of the random number for the local device, whether all the random numbers have been received and the order of players in the match. The order of the players will be decided on the random number each player generates, as per our strategy.

OK, now let’s start implementing the networking code. Modify the matchStarted method and also add two stubs methods as follows:

- (void)matchStarted
{
    NSLog(@"Match has started successfully");
    if (_receivedAllRandomNumbers) {
        _gameState = kGameStateWaitingForStart;
    } else {
        _gameState = kGameStateWaitingForRandomNumber;
    }
    [self sendRandomNumber];
    [self tryStartGame];
}
 
- (void)sendRandomNumber
{
 
}
 
- (void)tryStartGame
{
 
}

matchStarted first checks if the game has received random numbers from all players of the match. If it has, then it moves the game state to the “waiting for start” state.

Before you fill out the stub methods, you need to initialize the game state variable and generate a random number. Make the following changes to MultiplayerNetworking.m:

//Add to the top of the file
#define playerIdKey @"PlayerId"
#define randomNumberKey @"randomNumber"
 
//Add to implementation section
- (id)init
{
    if (self = [super init]) {
        _ourRandomNumber = arc4random();
        _gameState = kGameStateWaitingForMatch;
        _orderOfPlayers = [NSMutableArray array];
        [_orderOfPlayers addObject:@{playerIdKey : [GKLocalPlayer localPlayer].playerID,
                                     randomNumberKey : @(_ourRandomNumber)}];
    }
    return self;
}

Next, add a method to send data to all member of the match.

- (void)sendData:(NSData*)data
{
    NSError *error;
    GameKitHelper *gameKitHelper = [GameKitHelper sharedGameKitHelper];
 
    BOOL success = [gameKitHelper.match
                    sendDataToAllPlayers:data
                    withDataMode:GKMatchSendDataReliable
                    error:&error];
 
    if (!success) {
        NSLog(@"Error sending data:%@", error.localizedDescription);
        [self matchEnded];
    }
}

The sendData: method uses the sendDataToAllPlayers:withDataMode:error: of the GKMatch object to send data to all players of the match. Using GKMatchSendDataReliable ensures that the data sent will be received by all other players of the game. Of Course the players need to be connected to the network at all times for this to work, else the game would just end.

Armed with the power to send messages to other players, add the following code to the sendRandomNumber method.

MessageRandomNumber message;
message.message.messageType = kMessageTypeRandomNumber;
message.randomNumber = _ourRandomNumber;
NSData *data = [NSData dataWithBytes:&message length:sizeof(MessageRandomNumber)];
[self sendData:data];

The above code creates a new MessageRandomNumber structure, and sets the random number to the one that was generated in init. It then converts the structure into NSData to send to the other side.

Next, implement the tryStartGame method you referred to earlier. Make the following changes to MultiplayerNetworking.m:

// Add right after sendRandomNumber
- (void)sendGameBegin {
 
    MessageGameBegin message;
    message.message.messageType = kMessageTypeGameBegin;
    NSData *data = [NSData dataWithBytes:&message length:sizeof(MessageGameBegin)];    
    [self sendData:data];
 
}
 
// Fill the contents of tryStartGame as shown
- (void)tryStartGame {
    if (_isPlayer1 && _gameState == kGameStateWaitingForStart) {
        _gameState = kGameStateActive;
        [self sendGameBegin];
    }
}

This is quite simple – if it’s player 1 (who has the special privilege of acting like the “server”) and the game is ready to go, it sets the game to active, and tells the other side to do the same by sending a MessageGameBegin to the other side.

Build and run on two devices and create a match as you did before. If you everything goes well you should not see any errors on the console and have the following logs printed:

2014-01-06 23:13:19.846 CatRaceStarter[814:60b] Ready to start match!
2014-01-06 23:13:19.848 CatRaceStarter[814:60b] Looking up 1 players...
2014-01-06 23:13:19.873 CatRaceStarter[814:60b] Found player: Tapstudio
2014-01-06 23:13:19.874 CatRaceStarter[814:60b] Match has started successfully

OK – now for the code that handles receiving messages from the other side. Add the following stub methods to the MultiplayerNetworking.m file.

-(void)processReceivedRandomNumber:(NSDictionary*)randomNumberDetails {
 
}
 
- (BOOL)isLocalPlayerPlayer1
{
  return NO;
}

You will be filling these out in just a moment. Next, modify your match:didReceiveData:fromPlayer: method to handle the random number message:

- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID {
    //1
    Message *message = (Message*)[data bytes];
    if (message->messageType == kMessageTypeRandomNumber) {
        MessageRandomNumber *messageRandomNumber = (MessageRandomNumber*)[data bytes];
 
        NSLog(@"Received random number:%d", messageRandomNumber->randomNumber);
 
        BOOL tie = NO;
        if (messageRandomNumber->randomNumber == _ourRandomNumber) {
            //2
            NSLog(@"Tie");
            tie = YES;
            _ourRandomNumber = arc4random();
            [self sendRandomNumber];
        } else {
            //3
            NSDictionary *dictionary = @{playerIdKey : playerID,
                                         randomNumberKey : @(messageRandomNumber->randomNumber)};
            [self processReceivedRandomNumber:dictionary];
        }
 
        //4
        if (_receivedAllRandomNumbers) {
            _isPlayer1 = [self isLocalPlayerPlayer1];
        }
 
        if (!tie && _receivedAllRandomNumbers) {
            //5
            if (_gameState == kGameStateWaitingForRandomNumber) {
                _gameState = kGameStateWaitingForStart;
            }
            [self tryStartGame];
        }
    }
}

This method casts the incoming data as a Message structure (which always works, because you’ve set up each structure to begin with a Message structure). It can then look at the message type to see which type of message it actually is. Let’s go through it step by step.

  1. The received data is first cast into a MessageStruct.
  2. The received number is compared with the locally generated number. In case there is a tie you regenerate the random number and send again.
  3. If the random number received is not the same as the locally generated one, the method creates a dictionary that stores the player id and the random number it generated.
  4. When all random numbers are received and the order of players has been determined the _receivedAllRandomNumbers variable will be true. In this case you check if the local player is player 1.
  5. Finally if it wasn’t a tie and the local player is player 1 you initiate the game. Else you move the game state to “waiting for start”.

You now have all the code in place to receive and send the random number message. However, you still need to process the incoming random number an arrange the players in order. The players will be arranged on the basis on the random number they generate. The one that has the highest is player 1, the one next in line is player 2 and so on. Fill the processReceivedRandomNumber: method with the following code:

//1
if([_orderOfPlayers containsObject:randomNumberDetails]) {
  [_orderOfPlayers removeObjectAtIndex:
    [_orderOfPlayers indexOfObject:randomNumberDetails]];
}
//2
[_orderOfPlayers addObject:randomNumberDetails];
 
//3    
NSSortDescriptor *sortByRandomNumber = 
  [NSSortDescriptor sortDescriptorWithKey:randomNumberKey   
    ascending:NO];
NSArray *sortDescriptors = @[sortByRandomNumber];
[_orderOfPlayers sortUsingDescriptors:sortDescriptors];
 
//4    
if ([self allRandomNumbersAreReceived]) {
  _receivedAllRandomNumbers = YES;
}

The above code is quite easy to understand so I won’t go into the details. All you’re doing here is storing the received data in an array and sorting that array based on the random number.

At this point Xcode will show an error. Thats because it can’t find the method named allRandomNumbersAreReceived. Let’s go ahead and add that in.

- (BOOL)allRandomNumbersAreReceived
{
    NSMutableArray *receivedRandomNumbers =
    [NSMutableArray array];
 
    for (NSDictionary *dict in _orderOfPlayers) {
        [receivedRandomNumbers addObject:dict[randomNumberKey]];
    }
 
    NSArray *arrayOfUniqueRandomNumbers = [[NSSet setWithArray:receivedRandomNumbers] allObjects];
 
    if (arrayOfUniqueRandomNumbers.count ==
        [GameKitHelper sharedGameKitHelper].match.playerIDs.count + 1) {
        return YES;
    }
    return NO;
}

The above method is just a helper method, it returns a boolean which is true when all random numbers have been received and are unique.

Remember the isLocalPlayerPlayer1 method you added before. Fill that out with the following lines of code:

NSDictionary *dictionary = _orderOfPlayers[0];
if ([dictionary[playerIdKey]
     isEqualToString:[GKLocalPlayer localPlayer].playerID]) {
    NSLog(@"I'm player 1");
    return YES;
}
return NO;

Build and run the game on two separate devices. You must know the drill by now. This time each device will send out a random number and one will be selected as player 1. Player 1′s device will show the following logs:

2014-01-07 00:35:10.774 CatRaceStarter[859:60b] Ready to start match!
2014-01-07 00:35:10.777 CatRaceStarter[859:60b] Looking up 1 players...
2014-01-07 00:35:10.808 CatRaceStarter[859:60b] Found player: Tapstudio
2014-01-07 00:35:10.809 CatRaceStarter[859:60b] Match has started successfully
2014-01-07 00:35:10.848 CatRaceStarter[859:60b] Received random number:-1453704186
2014-01-07 00:35:10.850 CatRaceStarter[859:60b] I'm player 1

Awesome! Your code can handle the random number message and decide the order or players. You still however need to handle the other types of messages. Append the following code to the match:didReceiveData:fromPlayer: method:

else if (message->messageType == kMessageTypeGameBegin) {
    NSLog(@"Begin game message received");
    _gameState = kGameStateActive;
} else if (message->messageType == kMessageTypeMove) {
    NSLog(@"Move message received");
    MessageMove *messageMove = (MessageMove*)[data bytes];
} else if(message->messageType == kMessageTypeGameOver) {
    NSLog(@"Game over message received");
}

Let’s pause for a moment and think about how these messages will be handled. Since the MultiplayerNetworking class is responsible for receiving and processing these messages and the GameScene is responsible for rendering the game, these two need to communicate with each other. Hence the MultiplayerNetworkingProtocol.

Add the following method to the MultiplayerNetworkingProtocol present in MultiplayerNetworking.h:

- (void)setCurrentPlayerIndex:(NSUInteger)index;

Next, switch to MultiplayerNetworking.m and add a call to the above method in the tryStartGame method:

- (void)tryStartGame {
  if (_isPlayer1 && _gameState == kGameStateWaitingForStart) {
    _gameState = kGameStateActive;
    [self sendGameBegin];
 
    //first player
    [self.delegate setCurrentPlayerIndex:0];
  }
}

Since the begin game message is only going to be sent by Player 1. The MultiplayerNetworking class can safely notify the GameScene that the local player is Player 1.

The above will work when the local player is player 1. What if the local player is not player 1, in that case you will need to find out the index of the player from the _orderOfPlayer array and notify the GameScene which player belongs to him/her.

Add the following helper methods to MultiplayerNetworking.m:

- (NSUInteger)indexForLocalPlayer
{
  NSString *playerId = [GKLocalPlayer localPlayer].playerID;
 
  return [self indexForPlayerWithId:playerId];
}
 
- (NSUInteger)indexForPlayerWithId:(NSString*)playerId
{
  __block NSUInteger index = -1;
  [_orderOfPlayers enumerateObjectsUsingBlock:^(NSDictionary      
    *obj, NSUInteger idx, BOOL *stop){
      NSString *pId = obj[playerIdKey];
      if ([pId isEqualToString:playerId]) {
        index = idx;
        *stop = YES;
    }
  }];
  return index;
}

The above methods simply finds the index of the local player based on their player ID. In case the local player is not Player 1, he/she will receive a begin game message. This is the right place to find of the index of the local player and inform the GameScene. Append the following code to the section in which the game begin message is handled in the match:didReceivedData:fromPlayer: method:

[self.delegate setCurrentPlayerIndex:[self indexForLocalPlayer]];

With all that in place, open GameScene.m and implement the setCurrentPlayerIndex: method:

- (void)setCurrentPlayerIndex:(NSUInteger)index {
    _currentPlayerIndex = index;
}

Build and run. Now when the game starts you’ll notice that each device is assigned a player, tap on the screen to move your player ahead. You’ll notice that as the local player moves ahead their position on the other player’s device does not change.

Player Selected

Now let’s add code to send a move message when the local player taps the screen. For this, add the following method to MultiplayerNetworking.m:

- (void)sendMove {
    MessageMove messageMove;
    messageMove.message.messageType = kMessageTypeMove;
    NSData *data = [NSData dataWithBytes:&messageMove
                                  length:sizeof(MessageMove)];
    [self sendData:data];
}

Define the above method in the MultiplayerNetworking interface in MultiplayerNetworking.h as shown below:

- (void)sendMove;

Now that you can send a move message, switch to GameScene.m and add a call to the above method in the touchesBegan:withEvent: method as shown below:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if (_currentPlayerIndex == -1) {
        return;
    }
    [_players[_currentPlayerIndex] moveForward];
    [_networkingEngine sendMove];
}

This will handle the sending part of the equation, however you still need to add code to receive the message and take an appropriate action. For this add the following method declaration to the MultiplayerNetworkingProtocol in MultiplayerNetworking.h:

- (void)movePlayerAtIndex:(NSUInteger)index;

Next, add a call to the above method at the end of the section that handles “move messages” in the match:didReceiveData:fromPlayer:.

[self.delegate movePlayerAtIndex:[self indexForPlayerWithId:playerID]];

Open GameScene.m and add the implementation of the above method at the end of the file as shown below:

- (void)movePlayerAtIndex:(NSUInteger)index {
    [_players[index] moveForward];
}

Build and run. As you tap the screen you will notice that your player moves forward not only on your device but on your opponent’s as well.

Ending the Match

At this point you can play the game on two devices however you have not added any end condition. Your game needs to be in a position to end the game and determine a winner. To do this make the following changes to the MultiplayerNetworking class.

//Add to MultiplayerNetworking.m
- (void)sendGameEnd:(BOOL)player1Won {
    MessageGameOver message;
    message.message.messageType = kMessageTypeGameOver;
    message.player1Won = player1Won;
    NSData *data = [NSData dataWithBytes:&message length:sizeof(MessageGameOver)];
    [self sendData:data];
}
 
//Declare the above method in MultiplayerNetworking.h
- (void)sendGameEnd:(BOOL)player1Won;

Switch to GameScene.m and make the following changes to the update: method:

-(void)update:(CFTimeInterval)currentTime {
    if (self.paused && _currentPlayerIndex == -1) {
        return;
    }
    //Only Player 1 will check for game over condition
    if (_currentPlayerIndex == 0) { // Here!
      [_players enumerateObjectsUsingBlock:^(PlayerSprite *playerSprite, NSUInteger idx, BOOL *stop) {
          if(playerSprite.position.x + playerSprite.size.width/2 > _cat.position.x) {
              BOOL didWin = NO;
              if (idx == _currentPlayerIndex) {
                  NSLog(@"Won");
                  didWin = YES;
              } else {
                  //you lost
                  NSLog(@"Lost");
              }
              self.paused = YES;
              _currentPlayerIndex = -1;
              *stop = YES;
 
              [_networkingEngine sendGameEnd:didWin]; // Here!
              if (self.gameOverBlock) {
                  self.gameOverBlock(didWin);
              }
          }
      }];
    } // Here!
}

The way the above code works is that the game first checks if the local player is player1. If yes it enumerates through each player and checks to see if any player has crossed the cat. If a player has crossed the cat player 1 sends out the game over message.

Next you need add code to receive the game over message and show the user the game over view. To do this make the following changes:

// Add to MultiplayerNetworkingProtocol in MultiplayerNetworking.h
- (void)gameOver:(BOOL)player1Won;
 
// Add to the end of the section that handles the game over message in match:didReceiveData:fromPlayer: in MultiplayerNetworking.m
MessageGameOver * messageGameOver = (MessageGameOver *) [data bytes];
[self.delegate gameOver:messageGameOver->player1Won];
 
// Add the new method to GameScene.m
- (void)gameOver:(BOOL)player1Won {
    BOOL didLocalPlayerWin = YES;
    if (player1Won) {
        didLocalPlayerWin = NO;
    }
    if (self.gameOverBlock) {
        self.gameOverBlock(didLocalPlayerWin);
    }
}

Build and run. The game should now show you a game complete screen like the one shown below. Hurray! you now have a fully functional multiplayer networked game.

Game Over Screen

Displaying Player Names

At this point you have a functional game, but it’s kinda hard to tell which player you are, especially since it’s random.

So let’s fix this by displaying the player names for each player above their character. Make the following changes to PlayerSprite.m:

//Add to the top of the file
#define kPlayerAliasLabelName @"player_alias"
 
//modify the initWithType: method
- (instancetype)initWithType:(enum PlayerSpriteType)playerType {
 
    . . .
 
    self = [super initWithTexture:[gameAtlas textureNamed:textureName]];
    if (self) {
        . . .
 
        SKLabelNode *playerAlias = [[SKLabelNode alloc] initWithFontNamed:@"Arial"];
        playerAlias.fontSize = 20;
        playerAlias.fontColor = [SKColor redColor];
        playerAlias.position = CGPointMake(0, 40);
        playerAlias.name = kPlayerAliasLabelName;
        [self addChild:playerAlias];
 
        _moveAnimation = [SKAction repeatActionForever:[SKAction animateWithTextures:textures timePerFrame:0.1]];
    }
    return self;
}
 
//Add new method at the bottom
- (void)setPlayerAliasText:(NSString*)playerAlias; {
    SKLabelNode *playerAliasLabel = (SKLabelNode*)[self childNodeWithName:kPlayerAliasLabelName];
    playerAliasLabel.text = playerAlias;
}

Then open PlayerSprite.h and declare the new method as shown below:

- (void)setPlayerAliasText:(NSString*)playerAlias;

With the above code you have added a label to PlayerSprite which will be displayed above the character. Also you’ve added a convenience method to set the text on that label.

Next, make the following changes to the MultiplayerNetworking class as shown below:

//Add to MultiplayerNetworkingProtocol
- (void)setPlayerAliases:(NSArray*)playerAliases;
 
//Add to MultiplayerNetworking.m
- (void)processPlayerAliases {
    if ([self allRandomNumbersAreReceived]) {
        NSMutableArray *playerAliases = [NSMutableArray arrayWithCapacity:_orderOfPlayers.count];
        for (NSDictionary *playerDetails in _orderOfPlayers) {
            NSString *playerId = playerDetails[playerIdKey];
            [playerAliases addObject:((GKPlayer*)[GameKitHelper sharedGameKitHelper].playersDict[playerId]).alias];
        }
        if (playerAliases.count > 0) {
            [self.delegate setPlayerAliases:playerAliases];
        }
    }
}
 
//Modify the tryStartGame method
- (void)tryStartGame
{
    if (_isPlayer1 && _gameState == kGameStateWaitingForStart) {
        . . .
        [self processPlayerAliases];
    }
}
 
//Modify the case that handles the game begin message in match:didReceiveData:fromPLayer:
else if (message->messageType == kMessageTypeGameBegin) {
    . . .
    [self processPlayerAliases];
}

Basically when the game is transitioning to the Active state, you know for sure you’ve received the player names and the players have been ordered as per the random numbers they’ve generated. So that’s a good time to set up the tell the delegate to display player aliases.

You now need to implement the setPlayerAliases: method in the GameScene class. Add the following code to GameScene.m:

- (void)setPlayerAliases:(NSArray*)playerAliases {
    [playerAliases enumerateObjectsUsingBlock:^(NSString *playerAlias, NSUInteger idx, BOOL *stop) {
        [_players[idx] setPlayerAliasText:playerAlias];
    }];
}

Compile and run your code on two devices, and now you should see the label of each player’s name on top of their character!

Displaying player aliases for each character

Exercise: Supporting Invites

If you’ve got this far then you must have gotten the hang of how Game Center APIs work and how to design your game to work with them. As a last feature you’re going to add support for invites.

While working with the matchmaker view you must have noticed that it gives you an option to send an invite to a friend. Right now when you select this all that will happen is that a notification will be shown on your friend’s device, when he/she selects the notification it will simply launch the game and nothing else. Ideally the game should start and create a match with the player who sent the invite.

Doing this is very simple, hence you’re going to implement this on your own. I’ve listed the steps you need to follow to get this working:

  1. Implement the GKLocalPlayerListener protocol and set the GameKitHelper class as a delegate using the registerListener: method of GKLocalPlayer. This should be done as soon as the local player is authenticated.
  2. Implement the player:didAcceptInvite: method and the player:didRequestMatchWithPlayers: method of the GKLocalPlayerListener protocol.
  3. The methods mentioned in step 2 will be invoked when the user receives an invite. Store the details you receive here in an instance variable.
  4. Since you’ve store the details of the invite received, modify the findMatchWithMinPlayers:maxPlayers:viewController:delegate: method to use these details. Use the initWithInvite: method of the GKMatchMakerViewController to initiate a match with the player who sent the invite.

Where To Go From Here?

Here is the final project with the completed SpriteKit and Game Center multiplayer networked game you created in this tutorial series. I hope this tutorial gives you a good point to start in creating amazing multiplayer games.

If you’re implementing Game Center in your games, you might want to add Leaderboards and Achievements too. If you’re interested in learning about this, check out the chapters on Game Center in our book iOS Games by Tutorials.

If you have any questions, comments, or tips for using Game Center that you’ve learned while making your apps, please join in the forum discussion below!

Game Center Tutorial: How To Make A Simple Multiplayer Game with Sprite Kit: Part 2/2 is a post from: Ray Wenderlich

The post Game Center Tutorial: How To Make A Simple Multiplayer Game with Sprite Kit: Part 2/2 appeared first on Ray Wenderlich.

Introduction to C++ for iOS Developers: Part 1

$
0
0
Hello, C++!

Hello, C++!

Are you a master of Objective-C and looking for that next cool thing to learn? Try this article on for size; it introduces you to C++ for iOS developers.

As I’ll explain later, Objective-C works seamlessly with C and C++ code. Therefore, is very helpful for iOS developers to understand C++ for several reasons:

  • Sometimes you might want to use a library that was originally written in C++ in your app.
  • You might want to write part of your app’s code in C++, so it is more easily portable across platforms.
  • Having a good grounding of other languages helps you better understand programming in general.

This article is written for iOS developers who already understand Objective-C. It’s assumed that you already understand how to write Objective-C code and are familiar with basic C concepts such as types, pointers and functions.

Ready to learn some C++? Then dive right in!

Getting Started: A Brief History of Languages

C++ and Objective-C share some common ancestry: they both have their roots firmly planted in good old-fashioned C. This means that they are both “supersets” of the C language. Therefore, in both languages you can use C features alongside the additional features contained in each language.

If you’re familiar with Objective-C, you will likely have a rough understanding of the C++ code you encounter. For example, the scalar types such as int, float and char are present and behave in exactly the same way in both languages.

Both Objective-C and C++ add object-oriented features to C. If you’re unfamiliar with the term “object-oriented”, all you really need to understand is that it means data is represented by objects, which in turn are instances of classes. In fact, C++ was originally called “C with Classes”, which shows the underlying desire to make C++ object-oriented.

“So what about the differences, then?” I hear you ask. Well, the main difference is the approach to the object-oriented features. In C++, a lot of the action happens at compile time, whereas in Objective-C, much more happens at run time. You may already have dabbled with the Objective-C runtime to perform such trickery as method swizzling. In C++ this simply isn’t possible.

C++ also doesn’t have the plethora of introspection and reflection methods that Objective-C has. There’s no way to obtain the class of a C++ object as you would in Objective-C where you simply call the “class” method on an instance. Similarly there is no equivalent of isMemberOfClass or isKindOfClass in C++.

That’s a rough-and-ready introduction to C++ that shows the history and key differences between it and Obejctive-C. The history lesson is done — time to continue with some C++ language features! :]

C++ Classes

The first thing you need to know in any object-oriented language is how to define a class. In Objective-C, you create a header file and an implementation file to define a class. The exact same thing happens in C++; the syntax is also quite familar.

Here’s an example. The following is an Objective-C class:

// MyClass.h
 
#import <Foundation/Foundation.h>
 
@interface MyClass : NSObject
@end
 
// MyClass.m
 
#import “MyClass.h”
 
@implementation MyClass
@end

That should be clear to you as a seasoned iOS developer. But look at the equivalent in C++:

// MyClass.h
 
class MyClass {
};
 
// MyClass.cpp
 
#include “MyClass.h”
 
/* Nothing else in here */

There are a few distinct differences here. The first thing is that the implementation file in C++ doesn’t have anything in it. That’s because you’ve not declared any methods on the class. As well, an empty class doesn’t even need an @implemenation / @end block like Objective-C does.

In Objective-C, every class will almost always inherit from NSObject. You could create your own root class, which would mean that your class would have no superclass. But it’s unlikely you’ll ever do this unless you’re playing around with the runtime just for fun! This is in contrast to C++ where it’s quite common to create a class with no superclass as in the example above.

Another slight difference is #include versus #import. Objective-C adds the #import preprocessor directive to C. There is no equivalent in C++, so the standard, C-style, #include is used instead. Objective-C’s #import ensures that a file is only included once, but in C++ you must perform this check yourself.

Class Member Variables and Functions

Of course, there’s much more to a class than just declaring it. Just as in Objective-C, in C++ you can add instance variables and methods to a class. You might hear them termed differently in C++ though; they are more commonly called member variables and member functions.

Note: The term “method” is not really used in C++. The distinction is only used in Objective-C where a method is something called via a message dispatch. A function, on the other hand, is something called via a static C-style function call. I’ll explain more about static versus dynamic later in this article.

So how do you declare member variables and member functions then? Well, here’s an example:

class MyClass {
    int x;
    int y;
    float z;
 
    void foo();
    void bar();
};

Here there are three member variables and two member functions. But there’s a bit more to it than this in C++, as you can limit the scope of member variables and member functions in C++ and declare them as publicly or privately accessible. This can be used to limit what code can access each variable or function.

Consider the following example:

class MyClass {
  public:
    int x;
    int y;
    void foo();
 
  private:
    float z;
    void bar();
}

Here, x, y and foo are publicly accessible.This means they can be used outside of the MyClass class. However, z and bar are private. This means they can only be used from within MyClass itself. Member variables are private by default.

While this distinction does exist in Objective-C for instance variables, it’s rarely used. On the other hand, it is not possible in Objective-C to limit a method’s scope. Even if you only declare a method inside the implementation of a class, and don’t expose it in the interface, you technically could still call that method externally.

Methods in Objective-C are public or private only by convention. This is why a lot of developers choose to prefix a private method with something such as “p_” to document the distinction. This is in contrast to C++ where the compiler will throw an error if you try to call a private method from outside the class.

So how do you use a class? It’s very similar to Objective-C, really. You create an instance like so:

MyClass m;
m.x = 10;
m.y = 20;
m.foo();

Simple as that! This creates an instance of MyClass, sets x and y to 10 and 20 respectively and then calls foo on it.

Implementing Class Member Functions

You’ve seen how to define a class interface, but what about the functions? That’s quite simple, as it turns out. There’s a couple of ways you can do it.

The first way to implement a method is by defining it in the class’s implementation file — the .cpp file. You would do this as follows:

// MyClass.h
class MyClass {
    int x;
    int y;
    void foo();
};
 
// MyClass.cpp
#include “MyClass.h”
 
MyClass::foo() {
   // Do something
}

That’s the first way; it’s very similar to how you would do it in Objective-C. Notice the use of MyClass::; this is how you denote that the foo() function is being implemented as part of the MyClass class.

The second way to implement a method is something you can’t do in Objective-C. In C++ you can implement a method directly in the header file, like so:

// MyClass.h
class MyClass {
    int x;
    int y;
    void foo() {
        // Do something
    }
};

This might look quite odd to you if you’ve only ever used Objective-C. It is quite odd, but it can also be quite useful. When a function is declared in this way, the compiler can perform an optimisation called “inlining”. This means that when this function is called, instead of jumping to a new block of code, the entire function code is compiled inline at the call site.

While inlining can make code faster, it also increases the size of the compiled code because if the function is called more than once, the code will duplicated throughout the binary. If the function is quite large, or called a lot of times, then this can have a significant impact on the size of the binaries. This can cause a performance decrease because less code can fit in the cache, meaning there may be potentially more cache misses.

My goal here is to illustrate that C++ allows a lot of flexibility. It’s up to you as a developer to understand the trade-offs and make decisions based on this. Of course, the only way to really know which choice is right for you is to instrument your code!

pic1


Namespaces

The example you saw above introduced some new syntax that you haven’t encountered before — the double colon – ::. This is how you reference scope within C++; it’s used above to tell the compiler where it should look for the foo function.

Another time you’ll see the double colon is when using namespaces. Namespaces are a way to separate code so that naming clashes are less likely to occur.

For example, you might implement a class called Person in your own code, but a third party library may also implement a class called Person. Therefore, when writing C++ you will usually put all your code into a namespace to avoid these types of naming collisions.

It’s easy to do this; you just wrap everything with the following namespace declarations:

namespace MyNamespace {
    class Person {};
}
 
namespace LibraryNamespace {
    class Person {};
}

Now, when using either implementation of the Person class, you can disambiguate using the double colon, like so:

MyNamespace::Person pOne;
LibraryNamespace::Person pTwo;

Simple, isn’t it?

There is no equivalent to namespaces in Objective-C, other than by the convention of placing a prefix on your classes…you do name your classes like this, right? ;] Well if you don’t, then this is a perfect reason to start doing it straight away!

Note: There have been a few proposals for namespaces in Objective-C. One such proposal can be found here. I don’t know if we’ll ever see them in Objective-C, but I sure hope so myself!

Memory Management

Oh no… not that dreaded phrase! Memory management is one of the most important things to understand in any language. Java basically lets the garbage collector do its job. Objective-C requires that you understand reference counting and the role that ARC plays. In C++… well, C++ is a different beast once again.

First of all, to understand memory management in C++ you really need to understand the stack versus the heap. Even if you think you know about this, I suggest you carry on reading anyway; you’ll probably learn a thing or two.

  • The stack is a block of memory available to a running application. It’s a fixed size and is used by the application’s code to store data. The stack works on a push/pop basis; when a given function runs it pushes data onto the stack, and when a function finishes, it must pop off the same amount of data. Therefore, over time the stack usage will not grow.
  • The heap is also a block of memory available to a running application. It is not of any fixed size, and grows as the application runs. This is where applications tend to store data that’s used outside of a function’s scope. Also, large sets of data will usually be stored in the heap because storing it on the stack may overflow the stack — remember, the stack is a fixed size.

That’s a very brief overview of stack and heap theory; here’s some C code that shows the two in action:

int stackInt = 5;
int *heapInt = malloc(sizeof(int));
*heapInt = 5;
free(heapInt);

Here, stackInt is using stack space; after the function returns, the memory being used to store the value “5” is automatically freed.

Hoever, heapInt is using heap space. The call to malloc allocates enough space on the heap to store an int. But because heap has to be managed by you, the developer, there needs to be a call to free after you’ve finished with the data to ensure you’re not leaking memory.

In Objective-C, you can only create objects on the heap; you’ll receive a compiler error if you try to create an object on the stack. It simply won’t work.

Consider the following example:

NSString stackString;
// Untitled 32.m:5:18: error: interface type cannot be statically allocated
//         NSString stackString;
//                  ^
//                  *
// 1 error generated.

That’s why you see asterisks all over Objective-C code; all objects are created on the heap and you have pointers to those objects. This largely comes down to the way that Objective-C handles memory management. Reference counting is very much baked-in to Objective-C; objects need to be on the heap so that their lifetime can be tightly controlled.

In C++ you can decide to either store data on the stack or the heap; the choice is up to you as a developer. However, in C++ you also have to manage the memory all by yourself. Putting data on the stack is taken care of automatically, but when you start using the heap you have to handle the memory management yourself — or risk springing leaks all over the place.

C++ new and delete

C++ introduces a couple of keywords to help with memory management of heap objects; they’re used to create and destroy objects on the heap.

Creating an object is done like this:

Person *person = new Person();

When you are finished with the object, you can get rid of it like this:

delete person;

In fact, this even works for scalar types in C++:

int *x = new int();
*x = 5;
delete x;

You can think of these operations as equivalent to the initialization and destruction of objects in Objective-C. Initialization in C++, using new Person(), is equivalent to [[Person alloc] init] in Objective-C.

There is no specific equivalent to delete in Objective-C, though. As I’m sure you’re aware, deallocation of an Objective-C object is handled for you by the runtime when its retain count drops to zero. Remember, C++ doesn’t do reference counting for you. You’re in charge of deleting the object when you’ve finished with it.

You now have an overview of memory management in C++; the takeaway here is that it’s a lot more complex to manage memory in C++ than in Objective-C. You really need to think about what’s going on and keep track of all of your objects.

pic2

Accessing Members of Stack and Heap Objects

You’ve seen that objects can be created on either the stack or the heap in C++. However, there’s one subtle but important difference when using each type: the way you access member variables and member functions is slightly different.

When using stack objects, you need to use the dot operator (.). With heap objects, you need to dereference the pointer using the arrow operator (->), like so:

Person stackPerson;
stackPerson.name = “Bob Smith”; ///< Setting a member variable
stackPerson.doSomething(); ///< Calling a member function
 
Person *heapPerson = new Person();
heapPerson->name = “Bob Smith”; ///< Setting a member variable
heapPerson->doSomething(); ///< Calling a member function

The difference is subtle, but important to note.

You’ll also see the arrow operator used with the this pointer; it’s the same thing as the self pointer in Objective-C, and is used inside class member functions to access the current object.

The following C++ example shows the usage of the arrow operator:

Person::doSomething() {
    this->doSomethingElse();
}

This leads into a common gotcha with C++. In Objective-C, if you call a method on a nil pointer, your app will still run fine:

myPerson = nil;
[myPerson doSomething]; // does nothing

However, in C++ if you try to call a method or access an instance variable on a NULL pointer, your app will crash:

myPerson = NULL;
myPerson->doSomething(); // crash!

Therefore, you must be very careful in C++ to make sure you do not attempt to do work on NULL pointers.

References

When you pass an object to a function, you’re passing a copy of the object, not the obejct itself. For example, consider the following block of C++ code:

void changeValue(int x) {
    x = 5;
}
 
// …
 
int x = 1;
changeValue(x);
// x still equals 1

This is pretty straightforward and comes as no surprise. But look what happens when you do the same thing with a function that takes an object as a parameter:

class Foo {
  public:
    int x;
};
 
void changeValue(Foo foo) {
    foo.x = 5;
}
 
// …
 
Foo foo;
foo.x = 1;
changeValue(foo);
// foo.x still equals 1

Maybe that’s a little more surprising to you. If you think about it, it’s no different from the simple int case. What’s happening is a copy of the Foo object is made before passing it to the function.

Sometimes, though, you do want to pass the actual object. One way to do it would be to change the function to take a pointer to the object, rather than the object itself. But then that adds extra code whenever you call the function.

C++ adds a new concept which allows you to pass a variable “by reference”. This means that no copy is made; this is in contrast to the above examples which demonstrates passing “by value”.

It’s simple to change your calls to pass by reference; you simply use the address operator by adding an ampersand (&) in front of the variable in the function signature, like so:

void changeValue(Foo &foo) {
    foo.x = 5;
}
 
// …
 
Foo foo;
foo.x = 1;
changeValue(foo);
// foo.x equals 5

It also works for non-class variables:

void changeValue(int &x) {
    x = 5;
}
 
// …
 
int x = 1;
changeValue(x);
// x equals 5

Pass by reference can be very useful and can significantly improve performance. This is particularly true if making a copy of an object is extremely expensive, such as working with a huge list where creating a copy means performing a deep copy on the object.

Inheritance

An object-oriented language just wouldn’t be complete without inheritance, and C++ certainly doesn’t buck this trend. Consider the following two Objective-C classes where one inherits from the other:

@interface Person : NSObject
@end
 
@interface Employee : Person
@end

The same thing can be expressed in C++, in a very similar way:

class Person {
};
 
class Employee : public Person {
};

The only difference in C++ is the addition of the public keyword. Here, Employee inherits publicly from Person. This means that all the public members of Person remain public in Employee.

If you replaced public with private, then the public members of Person would become private in Employee. For more information about this topic, I suggest reading through a great article about inheritance and access specifiers here.

That’s the easy part about inheritance — now comes the hard bit. C++ is different from Objective-C in that it allows multiple inheritance. This lets a class inherit from two or more base classes. That might seem alien to you, especially if you haven’t used a language other than Objective-C.

Here is an example of multiple inheritance in C++:

class Player {
    void play();
};
 
class Manager {
    void manage();
};
 
class PlayerManager : public Player, public Manager {
};

In this example, there are two base classes and one class which inherits from both. This means that the PlayerManager has access to all of the member variables and functions of each base class. Neat, eh? As I’m sure you’re painfully aware, there is no way to do this in Objective-C.

Well…that’s not strictly true, is it?

The astute reader will notice that there is something similar in Objective-C: protocols. While not quite the same thing as multiple inheritance, both techniques aim to solve the same problem: providing a mechanism to link together classes that serve similar purposes.

Protocols are slightly different in that a protocol has no implementation; rather, it simply serves as a way to describe an interface to which a class must conform.

In Objective-C, the example above could be written as follows:

@protocol Player
- (void)play;
@end
 
@protocol Manager
- (void)manage;
@end
 
@interface Player : NSObject <Player>
@end
 
@interface Manager : NSObject <Manager>
@end
 
@interface PlayerManager : NSObject <Player, Manager>
@end

Of course, this is ever so slightly contrived, but you get the picture. In Objective-C you would have to implement both play and manage in the PlayerManager class, whereas in C++ you would just implement the method in each base class and then the PlayerManager class would automatically inherit each implementation.

In practice, though, multiple inheritance can sometimes lead to confusion and complication. It is often regarded among C++ developers as a dangerous tool to be avoided at all costs unless absolutely necessary.

Why? Consider what could happen if both base classes implemented a function with the same name and that accepted the same arguments — that is, both would have the same prototype. In this case, you’d need a way to disambiguate one from the other. For example, imagine both Player and Manager classes had a function named foo.

You would need to disambiguate like so:

PlayerManager p;
p.foo();          ///< Error! Which foo?
p.Player::foo();  ///< Call foo from Player
p.Manager::foo(); ///< Call foo from Manager

This is certainly doable, but it adds confusion and a layer of complexity which is best avoided. The decision is up to the user of PlayerManager. Using protocols leaves it up to the PlayerManager class to implement foo so that there’s only one implementation — and zero confusion.

Where to Go From Here?

In this first part of the series you’ve learned a brief history of C++, how to declare a class and how memory management works in C++. Of course, there is a lot more to the language than this!

In the second part of the series, you’ll learn about more advanced class features and templates before taking a look at the standard library and Objective-C++.

In the meantime, if you have any questions or comments about your adventures with C++, please join the discussion below!

Introduction to C++ for iOS Developers: Part 1 is a post from: Ray Wenderlich

The post Introduction to C++ for iOS Developers: Part 1 appeared first on Ray Wenderlich.

Video Tutorial: Table Views Custom Cells

Introduction to C++ for iOS Developers: Part 2

$
0
0
Hello, C++!

Hello, C++!

Welcome back to second part of the Introduction to C++ for iOS Developers series!

In the first part of this series, you learned about classes and memory management.

In this second second and final part of the series, you’ll dive deeper into classes and look at some more interesting features. You’ll see what a “template” is and then have a look at the Standard Template Library.

Finally, you’ll round it all off with learning about Objective-C++, which is a way to mix C++ into Objective-C.

Ready? Let’s get cracking!

Polymorphism

Polymorphism is not a parrot that changes shape, contrary to what it might sound like!

parrot_lion

Ok, I admit, that’s a terribly bad joke, :]

Put simply, polymorphism is the notion of overriding a function in a subclass. In Objective-C you probably have done this many times, for example when subclassing UIViewController and overriding viewDidLoad.

In C++, polymorphism goes quite a bit further than Objective-C. So stick with me while I explain this powerful feature.

To start with, here is an example of overriding a member function in a class:

class Foo {
  public:
    int value() { return 5; }
};
 
class Bar : public Foo {
  public:
    int value() { return 10; }
};

But look at what happens if you do the following:

Bar *b = new Bar();
Foo *f = (Foo*)b;
printf(%i”, f->value());
// Output = 5

Wow — that’s probably not the output you expected! I suspect you thought it would output 10, right? This is where C++ differs drastically from Objective-C.

In Objective-C, it doesn’t matter if you cast a subclass pointer to its base class pointer. When you send a message (i.e. call a method) to any object, it is the runtime which looks up the class of the object and calls the most derived method. Therefore in this scenario in Objective-C, the subclass method on Bar is called.

This highlights the compile-time versus run-time difference that I mentioned in the first half of this series.

When the compiler encounters the call to value() in the above example, its job is to work out what function needs to be called. Since the type of f is a pointer to a Foo, it emits code to jump to Foo::value(). The compiler knows nothing about the fact that f is actually a pointer to a Bar.

In this simple example you could be forgiven for thinking that the compiler could reason that f is a pointer to a Bar. But consider what would happen if f were actually the input to a function. In that case the compiler could have no way of knowing that it’s actually a pointer to a class derived from Foo.

Static Binding and Dynamic Binding

The above example illustrates perfectly the crucial difference between C++ and Objective-C; static versus dynamic binding. The behaviour seen above is an example of static binding. The compiler is responsible for resolving which function to call, and that behaviour is therefore baked in to the binary after compilation. There is no ability to change this behaviour at runtime.

This is in contrast to method calling in Objective-C, which is an example of dynamic binding. The runtime itself is responsible to decide which function should be called.

Dynamic binding is what makes Objective-C so very powerful. You may already be aware that it’s possible to add methods to a class at runtime, or swap method implementations. This could never be done in a statically bound language, where the calling behaviour is baked in at compile time.

But wait — there’s more to it than that in C++! While C++ is generally statically bound, there are mechanisms available to use dynamic binding; these are known as “virtual functions”.

Virtual Functions and the Virtual Table

Virtual functions provide a mechanism for dynamic binding. It defers the choice of which function is called until runtime through the use of a lookup table — one for each class. However, this does introduce a slight overhead cost at runtime when compared to static binding. The table lookup needs to happen in addition to calling the function. With static binding, only the calling of the function needs to be performed.

Using virtual functions is as simple as adding the “virtual” keyword to the function in question. Taking the previous example and using virtual functions instead would look like the following:

class Foo {
  public:
    virtual int value() { return 5; }
};
 
class Bar : public Foo {
  public:
    virtual int value() { return 10; }
};

Now consider what happens when you run the same code as before:

Bar *b = new Bar();
Foo *f = (Foo*)b;
printf(%i”, f->value());
// Output = 10

That’s better! That’s the output you presumably expected earlier, right? So dynamic binding can be done in C++, but you need to decide whether you want static or dynamic binding depending on the scenario you face.

This type of flexibility is commonplace in C++; it’s what makes C++ a multi-paradigm language. Objective-C largely forces you into strict patterns, especially if you are using the Cocoa framework. C++, on the other hand, leaves a lot of decisions up to the developer.

It’s now time to get dirty and look at how virtual functions work.

pic3

The Inner Workings of Virtual Functions

Before you can understand how virtual functions work, you need to understand how non-virtual functions work. Consider the following code:

MyClass a;
a.foo();

If foo() is non-virtual, then the compiler will convert this into code that jumps directly to the foo() function of MyClass.

But remember, this is where the problem with non-virtual functions lies. Recall from the previous example that if the class is polymorphic then the compiler can’t know the full type of the variable, and therefore can’t know which function it should jump to. There needs to be a way to lookup the correct function at runtime.

To accomplish this lookup, virtual functions make use of a concept known as the virtual table or v-table; this is a lookup table that maps functions to their implementations and each class has access to one. When the compiler sees a virtual function being called, it emits code that retrieves the object’s v-table and looks up the correct function.

Look back at the example from above to see how this works:

class Foo {
  public:
    virtual int value() { return 5; }
};
 
class Bar : public Foo {
  public:
    virtual int value() { return 10; }
};
 
Bar *b = new Bar();
Foo *f = (Foo*)b;
printf(%i”, f->value());
// Output = 10

When you create b, an instance of Bar, its v-table will be the v-table for Bar. When this variable is cast to a Foo pointer, it doesn’t alter the contents of the object. The v-table is still the v-table for Bar, not Foo. Therefore when the v-table is looked up for the call to value(), the result is Bar::value() which will be called.

Constructors and Destructors

Every object goes through two very important stages in its life: construction and destruction. C++ allows you to control both of these stages. The equivalent of these stages in Objective-C is the initializer method (i.e. init or any other method starting with init) and dealloc.

Constructors in C++ are defined by functions that share the same name as the class. You can have any number of them that you like, just as you can have any number of initializer methods in Objective-C.

For example, here is a class that has a couple of different constructors:

class Foo {
  private:
    int x;
 
  public:
    Foo() {
        x = 0;
    }
 
    Foo(int x) {
        this->x = x;
    }
};

Here there are three constructors. One is considered the default constructor: Foo(). The other takes a parameter to set the member variable.

If all you’re doing in the constructor is to set internal state, as in the above example, there’s a way to do that with less code. Instead of implementing the setting of the member variables yourself, you can use the following syntax:

class Foo {
  private:
    int x;
 
  public:
    Foo() : x(0) {
    }
 
    Foo(int x) : x(x) {
    }
};

Usually if you’re just setting member variables you would use this syntax. If, however, you need to perform some logic or call other functions, then you would implement the function body. You can also use a combination of the two.

When using inheritance, you need a way to call up to the super-class’s constructor. In Objective-C you do this by always calling the super-class’s designated initializer first.

In C++, you would do it as follows:

class Foo {
  private:
    int x;
 
  public:
    Foo() : x(0) {
    }
 
    Foo(int x) : x(x) {
    }
};
 
class Bar : public Foo {
  private:
    int y;
 
  public:
    Bar() : Foo(), y(0) {
    }
 
    Bar(int x) : Foo(x), y(0) {
    }
 
    Bar(int x, int y) : Foo(x), y(y) {
    }
};

The call to the super-class’s constructor is indicated by the first element in the list after the function signature. You can call through to any super-class constructor you want.

C++ code doesn’t tend to have a single designated initializer. Until recently, there was no way to call through to a constructor of the same class. In Objective-C, it’s common to have one designated initializer that every other initialiser calls, and only the designated initializer calls through to the super-class’s designated initializer. For example:

@interface Foo : NSObject
@end
 
@implementation Foo
 
- (id)init {
    if (self = [super init]) { ///< Call to super’s designated initialiser
    }
    return self;
}
 
- (id)initWithFoo:(id)foo {
    if (self = [self init]) { ///< Call to self’s designated initialiser
        // …
    }
    return self;
}
 
- (id)initWithBar:(id)bar {
    if (self = [self init]) { ///< Call to self’s designated initialiser
        // …
    }
    return self;
}
 
@end

In C++, while you can call through to a super-class’s constructor, until recently it was illegal to call through to one of your own constructors. Therefore the following workaround was quite common:

class Bar : public Foo {
  private:
    int y;
    void commonInit() {
        // Perform common initialisation
    }
 
  public:
    Bar() : Foo() {
        this->commonInit();
    }
 
    Bar(int y) : Foo(), y(y) {
        this->commonInit();
    }
};

However, this is rather cumbersome. Why can’t you just have Bar(int y) call through to Bar() and then have the contents of Bar::commonInit() in Bar()? That’s exactly how it works in Objective-C, after all.

In 2011, the latest C++ standard became a reality: C++11. In this updated standard it is indeed possible to do just this. There is still a lot of C++ code out there that hasn’t been updated for the C++11 standard, which is why it’s important to know both approaches. Any post-2011 C++ code will more likely do the following:

class Bar : public Foo {
  private:
    int y;
 
  public:
    Bar() : Foo() {
        // Perform common initialisation
    }
 
    Bar(int y) : Bar() {
        this->y = y;
    }
};

The only slight snag with this approach is that you can’t set member variables at the same time as calling a constructor from the same class. In the case above, the y member variable has to be set as part of the constructor body.

Note: C++11 became a full standard in 2011. It was originally called C++0x while being developed. This is because it was meant to mature sometime between 2000 and 2009, where the ‘x’ would be replaced by the last digit of the year. However it went on longer than expected and therefore ended up being called C++11! All modern compilers, including clang, now fully support C++11.

That covers construction, but what about destruction? That happens when an object is either deleted, if it’s a heap object, or goes out of scope, if it’s a stack object. In this function you’re required to perform any necessary cleanup of the object.

A destructor cannot take any arguments, because that wouldn’t make much sense if you think about it for a moment. dealloc cannot take any arguments in Objective-C for the same reason. Therefore there can only be one destructor for each class.

The name of the destructor is the class name prefixed by a tilde (~). Here’s an example destructor:

class Foo {
  public:
    ~Foo() {
        printf(“Foo destructor\n”);
    }
};

Take a look at what happens when you have a class hierarchy:

class Bar : public Foo {
  public:
    ~Bar() {
        printf(“Bar destructor\n”);
    }
};

If you were to leave the code like this, then something strange would happen if you deleted an instance of Bar via a Foo pointer, like so:

Bar *b = new Bar();
Foo *f = (Foo*)b;
delete f;
// Output:
// Foo destructor

Err, that doesn’t seem right, does it? It’s Bar that’s been deleted, so why has Foo’s destructor been called?

Recall that this same problem happened earlier and you used virtual functions to get around it. This is the exact same problem. The compiler sees that it’s a Foo that needs deleting, and since Foo’s destructor is not marked as virtual, it thinks that is the function to call.

The way to fix this is to mark the destructor as virtual, like so:

class Foo {
  public:
    virtual ~Foo() {
        printf(“Foo destructor\n”);
    }
};
 
class Bar : public Foo {
  public:
    virtual ~Bar() {
        printf(“Bar destructor\n”);
    }
};
 
Bar *b = new Bar();
Foo *f = (Foo*)b;
delete f;
// Output:
// Bar destructor
// Foo destructor

That’s closer to the desired outcome — but the end result is different than what happened when virtual was used previously. This time, both functions are called. First the destructor for Bar is called, then the destructor for Foo is called. What gives?

This is because destructors are special cases. The Bar destructor automatically calls the Foo destructor because that’s the super-class’s destructor.

This is exactly what’s required; just as in the pre-ARC days of Objective-C where you would call super’s dealloc.

I bet you’re thinking this:

pic4

You’d think that the compiler would just do this for you. Well, it could, but that wouldn’t be optimal in all cases.

For example, what if you never inherited from a certain class? If that destructor was virtual then there would be an indirection via the v-table every time an instance is deleted, and maybe you don’t want this indirection. C++ gives you the ability to make the decision yourself — yet another example of C++ being very powerful — but the developer really needs to keep on top of what’s going on.

Let this be a warning to you. Always make destructors virtual, unless you’re absolutely sure that you won’t inherit from that class!

Operator overloading

This next topic doesn’t exist at all in Objective-C, so you might find the concept a little bit daunting at first. But fear not, it’s really not that complicated after all!

An operator are entities such as the familiar +, -, *, or /. For example, you would use the + operator with standard scalars as such:

int x = 5;
int y = x + 5; ///< y = 10

The + here is obvious in what it does: it adds x to 5 and returns the result. It might not be obvious, but this is effectively a function which could have been written like this:

int x = 5;
int y = add(x, 5);

In our imaginary function, add(…) adds the two parameters and returns the result.

In C++ it’s possible to define what happens when you use an operator on any of your own classes. This can be extremely powerful. Of course it doesn’t always make sense. What would it mean to add a Person to a Person for example? Maybe they become married!? :]

Nevertheless, this feature can be extremely useful. Consider the following class:

class DoubleInt {
  private:
    int x;
    int y;
 
  public:
    DoubleInt(int x, int y) : x(x), y(y) {}
};

It might be nice to be able to do this:

DoubleInt a(1, 2);
DoubleInt b(3, 4);
DoubleInt c = a + b;

We want c to be equivalent to DoubleInt(4, 6) here – i.e., add x and y of each DoubleInt instance together. This is simple, it turns out! All you need to do is add a method to DoubleInt that looks like this:

DoubleInt operator+(const DoubleInt &rhs) {
    return DoubleInt(x + rhs.x, y + rhs.y);
}

The function called operator+ is special; it’s used whenever the compiler sees a DoubleInt on either side of a +. This function is called on the object on left hand side of the +, passing in the object on the right hand side as the parameter. That’s why the parameter is often named “rhs”, standing for “right hand side”.

The parameter to the function is a reference because taking a copy would be unnecessary and might alter the value, as it would be a new object being constructed. It’s also constant, because it’s illegal for the right hand side to change during the addition.

C++ can go even further than this. Maybe you don’t want to just add a DoubleInt to a DoubleInt. Maybe you want to be able to add an int to a DoubleInt. That’s possible as well!

To achieve this you would implement the following member function:

DoubleInt operator+(const int &rhs) {
    return DoubleInt(x + rhs, y + rhs);
}

Then you could do the following:

DoubleInt a(1, 2);
DoubleInt b = a + 10;
// b = DoubleInt(11, 12);

Super! And very powerful, I’m sure you’ll agree.

It doesn’t just stop at addition though. The same can be done with any operator. You can overload ++, --, +=, -=, *, ->, and many more. Going through all of them here would take far too long. I suggest if you want to read more about operator overloading then head on over to learncpp.com where there is a whole chapter dedicated to operator overloading.

Templates

Roll up your sleeves now. Here comes a rather interesting topic of C++.

How often have you written a function or a class and then found yourself writing the same function or class again — but with different types? As an example, consider a function to swap two values. You might write a function like this:

void swap(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
}

Note: Notice the use of pass by reference here so that the values that are passed in will actually be swapped. If the values were passed by value then it would be the function’s own copy of the values that would be swapped. This is another good example of a function that benefits from C++’s reference feature.

That works only on integers. If you want this to work for floats, then you would need to write another function:

void swap(float &a, float &b) {
    float temp = a;
    a = b;
    b = temp;
}

It’s a bit silly that you’ve had to duplicate the body of the function. C++ introduces syntax that allows you to effectively ignore the type. You can accomplish this via a feature known as templates. Instead of writing the two methods above, in C++, you can write the following:

template <typename T>
void swap(T a, T b) {
    T temp = a;
    a = b;
    b = temp;
}

Then, when you use swap with any type whatsoever, your function will swap them! You could call your function in any of the following ways:

int ix = 1, iy = 2;
swap(ix, iy);
 
float fx = 3.141, iy = 2.901;
swap(fx, fy);
 
Person px(“Matt Galloway”), py(“Ray Wenderlich”);
swap(px, py);

You need to be careful with templates, though; this approach only works if the implementation for the template function is in a header file. This is due to the way templates are compiled. When the compiler sees a template function being used, it compiles a version for that type if one doesn’t already exist.

Given that the compiler needs to see the template function implementation, you need to put the implementation in a header file and include that everywhere you use it.

Similarly, if you edit the implementation of a template function, every other file that uses that function needs to be recompiled. This is in contrast to editing a function or class member function implemented in an implementation file; in that case, only the one file needs to be recompiled.

For this reason, extensive use of templates can make an application cumbersome. But their power is extremely useful, so like many things in C++, it’s always a balancing act between power and simplicity.

Template Classes

Templates don’t stop at functions, however. It’s also possible to use templates with entire classes!

Imagine you want a class that holds a triplet of values — that is, three values that you’re going to use to hold some data. At first you want to use it with integers, so you write it like this:

class IntTriplet {
  private:
    int a, b, c;
 
  public:
    IntTriplet(int a, int b, int c) : a(a), b(b), c(c) {}
 
    int getA() { return a; }
    int getB() { return b; }
    int getC() { return c; }
};

But then you continue developing your application and realise that you need a triplet that stores floats. This time you write another class, like this:

class FloatTriplet {
  private:
    float a, b, c;
 
  public:
    FloatTriplet(float a, float b, float c) : a(a), b(b), c(c) {}
 
    float getA() { return a; }
    float getB() { return b; }
    float getC() { return c; }
};

It would appear that templates would be helpful here too — and it turns out that they are! In the same way that functions can use templates, so can entire classes. The syntax is identical. The above two classes could be rewritten like this:

template <typename T>
class Triplet {
  private:
    T a, b, c;
 
  public:
    Triplet(T a, T b, T c) : a(a), b(b), c(c) {}
 
    T getA() { return a; }
    T getB() { return b; }
    T getC() { return c; }
};

Using such a template class, however, requires slightly altering how you use the class. Template functions work without changing code, because the types of the arguments permit the compiler to infer what’s going on. However you need to tell the compiler which type you want a template class to use.

Fortunately, it’s very straightforward. Using the template class above is as easy as this:

Triplet<int> intTriplet(1, 2, 3);
Triplet<float> floatTriplet(3.141, 2.901, 10.5);
Triplet<Person> personTriplet(Person(“Matt”), Person(“Ray”), Person(“Bob”));

Powerful, isn’t it?

pic5

But wait! There’s more!

Template functions and classes are not limited to just a single unknown type. The Triplet class could be extended to support any three types, rather than each value having to be the same type.

To do this, it’s just a matter of extending the template definition to supply more types, like so:

template <typename TA, typename TB, typename TC>
class Triplet {
  private:
    TA a;
    TB b;
    TC c;
 
  public:
    Triplet(TA a, TB b, TC c) : a(a), b(b), c(c) {}
 
    TA getA() { return a; }
    TB getB() { return b; }
    TC getC() { return c; }
};

Three different types form the template above; each is then used in the appropriate place in the code.

Using such a template is also very easy, as shown below:

Triplet<int, float, Person> mixedTriplet(1, 3.141, Person(“Matt”));

So that’s it for templates! Now let’s take a look at a library that makes heavy use of this feature – the Standard Template Library.

Standard Template Library (STL)

Any self-respecting programming language has a standard library that contains commonly used data structures, algorithms and functions. In Objective-C you have Foundation. This contains NSArray, NSDictionary among other familiar and not-so-familiar members. In C++, it is the Standard Template Library — or STL, for short — that contains this standard code.

The reason it is called the Standard Template Library is that it makes extensive use of templates. Funny that, eh? :]

There are many things that are useful in the STL; covering all of them would take far too long, so I’m just going to cover the most important bits here.

Containers

Arrays, dictionaries, and sets: all of these are containers of other objects. In Objective-C, the Foundation framework contains implementations of the most commonly used containers. In C++, the STL contains these implementations. In fact, the STL contains quite a few more container classes than Foundation does.

In the STL there are a couple of different equivalents to NSArray. The first is called vector and the second is called list. Both of these can represent a sequence of objects, but each has its own benefits and downsides. Once again, it’s a matter of choosing from the range of options given to you by C++.

First of all, let’s look at vector, which is used like this:

#include <vector>
 
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);

Notice the use of std::; this is because most of the STL lies within the std namespace. The STL puts all of its classes inside its own namespace called “std” to avoid potential naming conflicts with other code.

In the above code, you first create a vector to store ints, then five ints are pushed onto the end of the vector. At the end of this operation, the vector will contain 1, 2, 3, 4 and 5 — in that order.

One thing to note here is that all containers are mutable; there are no mutable and immutable variants, like there are in Objective-C.

Accessing elements of a vector is done like so:

int first = v[1];
int outOfBounds = v.at(100);

Both of these are valid ways to access elements of a vector. The first notation uses the square brackets; this is how you index into a C-style array. It’s also how you are now able to index into an NSArray since subscripting was added to Objective-C.

The second line above uses the at() member function. This works the same as the square brackets, except it also checks if the index is within the bounds of the vector. If it’s not, then it throws an exception.

A vector is implemented as a single, contiguous, block of memory. Its size is therefore the size of the object being stored (so four or eight bytes for integers, depending on if you have 32-bit or 64-bit architecture in use) multiplied by the number of objects in the vector.

Adding elements to a vector is expensive, because a new block of memory needs to be allocated for the new size vector. However accessing a certain index is fast, because it’s a matter of simply reading the right number of bytes into the memory store.

std::list is quite similar to std::vector; however, a list is implemented slightly differently. Instead of being a contiguous block of memory, it is implemented as a doubly linked list. This means that each element of the list contains the data at that element, along with a pointer to the next and previous elements.

Because it is a doubly linked list, insertion and deletion operations are trivial. However accessing the n’th element in the list requires walking from the 0’th to the n’th.

That said, using a list is very similar to vectors:

#include <list>
 
std::list<int> l;
l.push_back(1);
l.push_back(2);
l.push_back(3);
l.push_back(4);
l.push_back(5);

Just like the vector example above, this creates a sequence 1, 2, 3, 4 and 5 in order. This time, however, you cannot use the square brackets or at() member function to access a certain element in the list. Instead you must use a concept known as iterators to walk through the list.

Here’s how you would loop through each item of a list:

std::list<int>::iterator i;
for (i = l.begin(); i != l.end(); i++) {
    int thisInt = *i;
    // Do something with thisInt
}

Most container classes have the concept of an iterator. The idea is that an iterator is an object that can move back and forth through the collection and points to a specific member. You increment the iterator to move it forward, or decrement it to move is back.

Obtaining the value at the current location of the iterator is as simple as using the dereference operator (*).

Note: In the above code, there are a couple of instances of operator overloading to be seen. The i++ is the iterator overloading the increment operator ++. *i overloads the dereference operator *. The STL makes heavy use of operator overloading like this.

In addition to vector and list, there are many other containers in C++. They all have different features. Just as in Objective-C there is a set, std::set, and a dictionary, std::map. Another commonly used container is std::pair which stores just two values.

Shared Pointers

To revisit memory management for a moment: recall that when you use heap objects in C++ you have to handle memory yourself; there is no reference counting. That’s certainly true of the language as a whole. But in C++11 a new class was added to the STL which adds reference counting. It’s called shared_ptr, meaning a “shared pointer”.

A shared pointer is an object which wraps a normal pointer and performs reference counting on the underlying pointer. It can be used in much the same way as you would use pointers to objects in Objective-C under ARC.

For example, the following shows how to use shared pointers to wrap a pointer to an integer:

std::shared_ptr<int> p1(new int(1));
std::shared_ptr<int> p2 = p1;
std::shared_ptr<int> p3 = p1;

After these three lines of code, the reference count of each of the shared pointers is 3. The reference count drops when each shared pointer is destroyed or is reset. Once the last shared pointer holding onto its underlying pointer is destroyed, the underlying pointer is deleted.

Since shared pointers are stack objects themselves, they will be destroyed when they go out of scope. Therefore they will behave in much the same way that pointers to objects do under ARC in Objective-C.

A full example showing shared pointers being created and destroyed is as follows:

std::shared_ptr<int> p1(new int(1)); ///< Use count = 1
 
if (doSomething) {
    std::shared_ptr<int> p2 = p1; ///< Use count = 2;
    // Do something with p2
}
 
// p2 has gone out of scope and destroyed, so use count = 1
 
p1.reset();
 
// p1 reset, so use count = 0
// The underlying int* is deleted

The assignment of p1 to p2 takes a copy of p1. Remember that when a function parameter is pass by value, it’s a copy of the parameter which is given to the function. This is useful because if you pass a shared pointer to a function, a new shared pointer is passed to the function. This will of course go out of scope at the end of the function and will be destroyed.

So for the lifetime of the function, the use count of the underlying pointer will be incremented by one. Exactly how reference counting works in Objective-C under ARC!

Of course, you need to be able to get at or use the underlying pointer; there’s two ways to do that. Both the dereference (*) and arrow (->) operators are overloaded so that a shared pointer works essentially the same as a normal pointer, like so:

std::shared_ptr<Person> p1(new Person(“Matt Galloway”));
 
Person *underlyingPointer = *p1; ///< Grab the underlying pointer
 
p1->doADance(); ///< Make Matt dance

Shared pointers are a great way to bring reference counting to C++. They of course add a small amount of overhead, but usually this overhead is worthwhile given the clear benefits.

Objective-C++

C++ is all well and good, but what does it have to do with Objective-C you may ask? Well, through the use of Objective-C++ it is possible to mix Objective-C and C++. The name simply comes from the fact that the two languages can be mixed; it’s not an entirely new language, but a combination of the two.

By mixing Objective-C and C++, you can use both sets of language features. It’s possible to mix and match by having C++ objects as instance data of Objective-C classes and vice versa. This can be extremely useful if you want to use a C++ library in an app.

It’s very easy to make the compiler understand a file as Objective-C++. All you need to do is change the filename from .m to .mm. When you do this, the compiler will consider this file differently and will allow you to use Objective-C++.

An example of how you can use one object in another is as follows:

// Forward declare so that everything works below
@class ObjcClass;
class CppClass;
 
// C++ class with an Objective-C member variable
class CppClass {
  public:
    ObjcClass *objcClass;
};
 
// Objective-C class with a C++ object as a property
@interface ObjcClass : NSObject
@property (nonatomic, assign) std::shared_ptr<CppClass> cppClass;
@end
 
@implementation ObjcClass
@end
 
// Using the two classes above
std::shared_ptr<CppClass> cppClass(new CppClass());
ObjcClass *objcClass = [[ObjcClass alloc] init];
 
cppClass->objcClass = objcClass;
objcClass.cppClass = cppClass;

It’s as simple as that! Note the property is declared as assign, as you cannot use strong or weak because these don’t make sense with non-Objective-C object types. The compiler cannot “retain” or “release” a C++ object type, because it’s not an Objective-C object.

The correct memory management will still happen with assign because you’ve used a shared pointer. You could use a raw pointer, but then you would need to write the setter yourself to delete the old instance and set the new value as appropriate.

Note: There are limitations with Objective-C++. It is not possible for a C++ class to inherit from an Objective-C class and vice versa. Exceptions are also an area to be careful with. Recent compilers and runtimes do allow C++ exceptions and Objective-C exceptions to co-exist, but care should be taken. Make sure to read the documentation if you use exceptions.

Objective-C++ can be extremely useful because sometimes the best library for the task is written in C++. Being able to use it without any issues in an iOS or Mac app can be invaluable.

It should be noted though that Objective-C++ does have its cautions. One is memory management. Remember that Objective-C objects are always on the heap, but C++ objects can be stack or heap allocated. A stack object as a member of an Objective-C class is therefore a bit strange. It will actually be on the heap, because the entire Objective-C object is on the heap.

The compiler ensures this happens by automatically adding in code to alloc and dealloc to construct and destruct “stack” C++ objects. It does this through creating two methods called .cxx_construct and .cxx_destruct for alloc and dealloc to call respectively. In these methods, all the relevant C++ handling is performed as necessary.

Note: ARC actually piggybacks on .cxx_destruct; it now creates one of these for all Objective-C classes to write all the automatic cleanup code.

This handles all stack based C++ objects, but you should remember that any heap based C++ objects would need creating and destroying as appropriate. You would create them in your designated initializer and then delete them in dealloc.

Another caution with Objective-C++ to be aware of is leaking the C++ dependency. This should be avoided as much as possible. To see why this is a problem, consider the following class which makes use of Objective-C++:

// MyClass.h
#import <Foundation/Foundation.h>
#include <list>
 
@interface MyClass : NSObject
 
@property (nonatomic, assign) std::list<int> listOfIntegers;
 
@end
 
// MyClass.mm
#import “MyClass.h”
 
@implementation MyClass
// …
@end

The implementation file for MyClass has to be a .mm file because it’s making use of C++. That’s fine, but consider what would happen if you wanted to use MyClass; you would need to import MyClass.h. But in doing so, you are importing a file that makes use of C++. Therefore that other file needs to be compiled as Objective-C++, even though it doesn’t want to use C++ itself.

Therefore it’s best to minimize the amount of C++ usage in your public headers if at all possible. You can use private properties or instance variables declared in the implementation to achieve this.

Where to Go From Here?

C++ is a great language to learn about. It has similar roots to Objective-C, but it’s chosen to do things in a very different way. Learning about C++ can give a good insight into object oriented programming in general. In turn, this helps you make better design decisions in your Objective-C code.

I encourage you to read more about C++ and try it out for yourself. There is a great resource over at learncpp.com if you want to read more about the language.

If you have any comments or questions on this, or C++ in general, come join the discussion below!

Introduction to C++ for iOS Developers: Part 2 is a post from: Ray Wenderlich

The post Introduction to C++ for iOS Developers: Part 2 appeared first on Ray Wenderlich.

Video Tutorial: Table Views Static Cells

Video Tutorial: Table Views Accessory Views

How to Set Up a LAMP server on Linode

$
0
0
Learn how to securely build your own web server!

Learn how to securely build your own web server!

Running your own web server is the ultimate level of technological freedom. Having a server to call your own allows you to do all kinds of things:

  • Keep all of your files backed up in the cloud
  • Host an email server
  • Open a remote connection to your home network
  • Run a private or public API
  • And so much more!

In this tutorial, you’ll get a CentOS server set up with Linode, a cloud hosting company similar to Rackspace or Amazon Web Services. You’ll configure your server with a few bells and whistles and implement some simple security measures to help minimize your risk to outside attackers.

Note that Linode is a paid service and you’ll need to sign up for an account and pay to provision a new server instance to continue.

Why Linode and CentOS?

In contrast to Amazon’s AWS, Linode is a straightforward, fixed-cost hosting package. It fills the need for people who just need a small server up and running in minutes. Contrast this to getting an AWS EC2 instance for computing coupled with an EBS instance for disk storage, configuring them to talk to each other, routing traffic correctly, securing them, and so forth.

And most importantly, Linode is faster for basic operations.

CentOS stands for “Community Enterprise Operating System” and is considered to be an Open Source alternative to the highly popular Red Hat Enterprise Linux distribution used in most large companies. It offers the robustness and scale of Red Hat with the user-friendly features and great out-of-the-box support that Fedora and Ubuntu are known for.

Getting Started

Head to linode.com and click Sign Up in the top right corner of the header bar below:

Linode_Signup

Fill out the standard account details, such as user name, address and credit card info.

Select the first plan available: Linode 1024. This base option is enough to power a simple web site and is enough to get you started for the purposes of this tutorial. You can always instantly upgrade later should you run out of storage or bandwidth.

Click Continue, agree to the Terms of Service – after reading them, of course :] – and complete your order!

Creating your account can happen instantly, or it may take up to 15 minutes, depending on the options you selected during set up. Once you are notified that your account is ready to go, log in to Linode again and you’ll be prompted to pick an initial setup for your server.

The first question you’ll come across is picking a Data Center. It’s important to pick a location that is relevant to your usage. Typically you’ll want a location close to your users or close to your office to get the best response times.

Click Place this Linode here on the location you prefer, as shown below:

Linode_Data_Center

If you can’t be troubled to decide, pick Dallas as it’s middle of the road in the USA!

Next you’re provided with several options for customizing your server. Pick CentOS 6.4 from the Distribution drop-down. Next, since you’re paying for this server, you want to get the most out of it to meet your needs so set the Swap Disk to 512MB and max out the remaining Deployment Disk Size as shown in the screenshot below:

Linode_Server_Setup

This configuration sets up your server with the most disk space possible for your configuration level.

Finally, create a root password for your server — make sure it’s a a good one! — then click Rebuild.

Note: Take care when choosing your root password; the root user has access and permission to everything on the server, so make sure the password is really strong. Here’s a handy web page to help you generate a strong password.

Your server is now being built to order! Watch the Host Job Queue section; once all of the tasks have completed with a “Success” result and the spinner dust settles, click the big Boot button in the Dashboard section shown below:

Linode boot button

You now have your very own piece of real estate on the Internet! :]

You’re now ready to configure the server to your liking, including connecting to it remotely, securing the system, setting up LAMP, and getting a basic webpage up and running.

Time to get to work!

Connecting to Your Server

Click on the Remote Access menu at the top of the page; under the Public Network section you’ll see a list of instructions on how to connect to your server. Fire up Terminal (on a Mac) or a program like PuTTy (on a PC) and type in the appropriate command shown in the SSH Access row.

Note: SSH stands for Secure Shell; it’s a protocol just like HTTP and FTP that’s used to securely connect to another computer. Typically, you’ll use Terminal and SSH to connect to other computers that don’t provide a visual interface to the OS.

Each time you connect to a server, SSH checks that the server’s key is the same as last time. Since this is the first time you’ve logged into your server, SSH prompts you to check the key and add it to its key database. Since you’re an expert computer user and nothing could possibly go wrong — famous last words, perhaps? — just type yes and hit Enter, like so:

Linode_First_Launch2

Now, simply enter the root password you created when you set up the server, and you’ll be sitting at the command prompt, as shown below:

Linode_First_Launch3

Naming Your Server

The first thing you need to do is give your server a meaningful name — like a newborn baby!

The name can be anything, but it should be unique. Many times servers are named after collection of things that are near and dear to the creator of the server – like planets, Roman or Greek gods, cities, or Pokemon characters.

In corporate environments, server names are typically more boring but their name serves a purpose as it usually includes the server location and function. For example, “prodweb01″ could mean “production web server #1″.

Choose a server name that has meaning to you. This tutorial pays homage to the lovable fallen planet, Pluto, so just replace ‘pluto’ with your server name in the examples that follow. There are three steps to set your server name — make sure you execute them in order and don’t skip one by mistake!

Enter the following command at your shell prompt:

echo "HOSTNAME=pluto" >> /etc/sysconfig/network

This above command updates a critical network file /etc/sysconfig/network on your server with your chosen server name.

Enter the second command as follows:

hostname "pluto"

This sends an alert to all processes listening for updates from the hostname process on the server that the servername has changed.

Finally, you’ll need to edit a configuration file on the server. Enter the third and final command as below:

nano /etc/hosts

This launches the nano text editor. /etc/hosts controls how Internet traffic is routed into and through your server.

Using the text editor, arrow down to the bottom of the file and add a new line. Enter the IP address of your server, hit the Tab key, then enter the name of your server. You can find your server’s IP address from the Linode dashboard (under the Remote Access tab).

For example, if your server’s IP is 192.168.99.42, enter 192.168.99.42 pluto in the hosts file. Hit Control-X (not Command-X) to exit the editor; press y to save your changes, then hit Enter to overwrite the existing hosts file.

Note: If your server will host a domain (like howtosetuplinode.com), then you’ll have to specify your servername in the hosts file as “server-name.domain-name.extension”. This is known as a fully qualified domain name, or FQDN. This tutorial does not require a FQDN, so if you don’t have a domain yet, don’t worry.

To test your new setup, exit your current SSH session:

exit

Then SSH back in again, using the same command you used earlier. Your prompt should now show your new server name, like so:

[root@pluto ~]#

Also try to ping your server like this:

ping pluto

It should ping your local machine, proving it works. Hit Ctrl-C to stop ping and return to your SSH session.

Final Server Setup

By default, the server timezone is set to GMT; it’s up to you to set your local time zone.

Enter the following command:

tzselect

This launches the following text-based Timezone Select Tool:

Linode_TZSelect2

Simply answer the questions about your location one by one, and at the end of the process the server prompts you to confirm that the time is setup correctly.

Of course, you’ll want to have the latest and greatest versions of all software packages installed on your shiny new system.

Run the following command and accept the updates one by one as the system prompts you for confirmation:

yum update

yum is the gateway to package management and installation on CentOS. You should run the update command on a weekly or monthly basis to keep your system safe by eliminating known vulnerabilities in installed software packages.

Creating a Second User

Up to this point, you’ve been using root to perform all changes on your server. root is the super-admin account on your server and has permission to do anything and everything/ This makes it really easy to configure your server, but it also makes it easy to do bad things and cause disaster down the road.

A tenet of good security is to use the lowest level of permissions possible for an action. This protects the system in case an account gets compromised. Hence, it’s a best practice to create a second user account for most tasks, and then to switch to the root user only when needed. This adds one more level of safety and security to your server.

AU1Tqxt

Enter the following command:

adduser remote_user

This creates a new user with the name remote_user.

Next, enter the following command:

passwd remote_user

The passwd program both unlocks and sets a new password for the user. Just as you did when setting the root password while creating the server, make sure this password is complicated and difficult to guess or crack.

User accounts that are allowed to act as root have what are known as sudo permissions. The name comes from the program of the same name, which performs a temporary upgrade to your permissions to perform an action, and then returns to your ordinary permissions when you’re done.

Enter the following command at the prompt to start the text editor:

nano /etc/sudoers

Go about two-thirds of the way down the page and find a line that looks like root ALL=(ALL) ALL. Add the following line below that:

remote_user ALL=(ALL) ALL

Your file should look like the following:

Linode_Root

Save and close the file by hitting Control-X.

It’s time to say goodbye to your omnipotent days of using root and embrace the loving embrace of your newest user: remote_user. Log out of the Linode server by typing exit in Terminal.

Securing Your Server Connections

The next step to a more secure server experience is setting up an SSH key pair. This means the SSH connection knows who you are based on your secret key. The key is also protected with a passphrase which you’ll need to unlock your key.

Ensure that you’ve logged out of your Linode server and that you’re back to your local machine in Terminal.

The good new is that you may already have a key if you use SSH, or use a key to push to services like GitHub.

You can find out if you already have a key by executing the following command:

ls ~/.ssh/id_rsa*

If you see id_rsa and id_rsa.pub listed, then you’re all set! You can skip the next step of creating a key pair.

However, if you don’t see any files listed or get a “No such file or directory” error – you’ll need to create your own key.

Enter the following command at the shell prompt:

ssh-keygen

Hit Enter to save the files in the default location provided and be sure to use a good passphrase. A passphrase is much like a password, but as the name suggests, can be a phrase or sentence for extra security.

The above command creates two files in a hidden directory on your file system in ~/.ssh named id_rsa and id_rsa.pub. id_rsa.pub is your public key and can be given out freely. id_rsa is your private or secret key and it’s critical that you not share this file with anyone! As an extra line of defence, the private key is secured with the passphrase.

Now that your keys are generated, the next step is to let your Linode server know about the public key.

Enter the following command:

scp ~/.ssh/id_rsa.pub remote_user@127.0.0.1:

Replace the IP address above with the IP address of your sever, and don’t forget about the colon at the end of the command. Usually after the colon you’d list the path to save the file, but if you leave it blank it will save the file in the user’s home directory.

scp stands for “secure copy” and copies the public key file to remote_user‘s home directory.

Now reconnect to your server, but as your new user this time:

ssh remote_user@127.0.0.1

Again, fill in your server’s actual IP address instead of 127.0.0.1 above.

Enter the following commands to set up your key file on the server:

mkdir .ssh
mv id_rsa.pub .ssh/authorized_keys

Just as the key files on your computer were in the .ssh folder, the key files on the server need to live in a matching directory. mkdir stands for “make directory” and creates a new .ssh folder on your server.

em moves the public key file from your computer into authorized_keys, which contains a list of all the public keys that can be used to log in as this user. You can add more keys here later to allow other other people to log in to this server.

Enter the command below:

chown -R remote_user:remote_user .ssh
chmod 700 .ssh
chmod 600 .ssh/authorized_keys

Here you ensure only the right people have access to the .ssh folder and its contents.

The first line uses chown (“change owner”) to recursively set the owner of all files in the .ssh folder to remote_user. The next two lines use chmod (“change mode”) to set the permissions on .ssh to only be accessible by remote_user, and likewise for the authorized_keys file.

Note: For more details on Linux file permissions, check out the official documentation from Linux.org.

We made it through that section alive - there's not much left to do!

We made it through that section alive – there’s not much left to do!

Okay — here’s the acid test. Type exit in Terminal and log back in: you should no longer be prompted for your server password! As an added bonus, Keychain can save your passphrase, so simply logging into your server as remote_user account will log you in automatically.

As you expand your server empire, you can just copy your public key to each server using the same method; that way, your single key and passphrase will give you access to all of your servers.

Lock Down Remote Access

Log back in to your Linode server. Enter this command at the prompt:

sudo nano /etc/ssh/sshd_config

This step makes it more difficult for malicious users to find your server and make their way in.
Notice the command in front: sudo. This tells the system you’d like to temporarily escalate your permission to execute this next command.

In this case, you’re opening a text editor to modify the SSH configuration file, which only the root user is allowed to do. Modify the file as instructed below:

  • Find the setting PasswordAuthentication and change it from yes to no. This disables password logins so everyone will need to log in with key pairs.
  • Find the setting #PermitRootLogin, remove the leading # character, then change the setting from yes to no. This prevents the root user from logging in to the server directly.
  • Find the line with #Port and remove the leading # character. Change the value from 22 to any value between 1025 and 65536; I chose 23456 as it’s easy to remember. This changes the default port to make it more difficult for strangers out there to find your server.
  • Go to the very bottom of the file and add the line AllowUsers remote_user. This explicitly tells the SSH service to let your user in regardless of other settings.

Save and exit, then restart the SSH daemon to reload your configuration file as follows:

sudo /etc/init.d/sshd reload

To test that it works, open a new Terminal tab with Command-T (you want to keep your old tab open still logged in to the server, in case you made a typo with your SSH configuration). Then make sure that you can no longer log in as root by issuing the following command:

ssh -p 7415 root@127.0.0.1

Replace 127.0.0.1 with your server’s IP as usual. You should now get an error that says “Permission denied (publickey,gssapi-keyex,gssapi-with-mic).”.

Now repeat this with the user that is allowed to log in with SSH:

ssh -p 23456 remote_user@127.0.0.1

Replace 127.0.0.1 with your server’s IP, and 23456 with the port you chose. If you successfully get in, your SSH is now locked down!

Setting up Your Firewall

Once you’ve taken care of server access, your next step is to set up a firewall to filter out undesirable network traffic such as bots and people trying to gain unauthorized access to your server. A tool called Fail2Ban lets you to setup rules to ban undesirable network traffic from even talking to your server – the traffic your mother warned you about. :]

Execute the following command:

sudo system-config-firewall-tui

You could edit the firewall rules directly by hand, but it’s quite complicated and the wrong move can open your server to attacks — or worse, prevent you from logging in! Using system-config-firewall-tui to make changes is slightly easier to use as it’s a text-based GUI. You use the tab and arrow keys to navigate and the space bar to make a selection – press once to select, press again to de-select.

The first screen has a fairly obvious option to enable the firewall, as shown below:

Linode_Enabled_Firewall

Press the spacebar to select this option; you’ll see a * appear beside the option. Use the arrow keys to reach the Customize button and hit the spacebar again to select it.

Trusted Services

Select the following protocols to allow through the firewall:

  • IPSec – allows the IP Security protocol to authenticate/authorize certain connections
  • SSH – allows you to remote into your server (like you are doing now)
  • Secure WWW (HTTPS) – allows HTTPS traffic
  • WWW (HTTP) – allows HTTP traffic

As your server needs grow, you may revisit this list and allow other protocols through; for example, SMTP and IMAP/POP3 for email hosting, or DNS to run your own name server. Select Forward and move onto the next page,

Other Ports

Arrow over and select Add to add a custom port. Now that you have SSH running on port 23456, you need to tell the firewall to allow connections on that port — otherwise, you won’t be able to log in. Set the Port to 23456 and the Protocol to tcp like so:

Linode_port_forward

Select OK to add the new custom port and then select Forward to the next page.

Trusted Interfaces

Because this is a fairly basic server setup for web hosting, you don’t need to expose any networks on the Trusted Interfaces screen. You’d typically allow eth+ if this server was going to act as a traffic filter or router for other servers on your network, but you don’t need to change anything for this tutorial. Select Forward to get to the next page.

Masquerading

The same is true for this screen – all options can be left blank. Masquerading lets multiple servers appear to be coming from one address, known as NAT, or Network Address Translation) Again, this is a simple server so you don’t need this. Forward on!

Port Forwarding

You won’t change anything on this page either but it’s important to know what this screen is for. You can add an entry on this page if you need to map one port to another.

Why would you do this? Well, say you have an application that only looks for an SSH connection on port 22, but you changed yours to 23456. With an entry on this page, you could say port 23456 actually maps to port 22. Any traffic that came from port 23456 would be sent to port 22 and your application would work as expected.

You don’t need to set this up right now, so select Forward to move on.

ICMP Filter

The ICMP Filter page actually has something you’ll change! Yippee!

This screen lists several types of protocols used by your server to communicate information about itself to the outside world. Enable the Destination Unreachable and Source Quench protocols; the first one tells other servers that your server is not available for communicating. The second one helps optimize bandwidth and is used by network routers to request that servers speed up or slow down their data rates.

Select Forward from this screen and then Close. You’re returned back to the main screen, so hit OK and accept the warning about overriding Firewall rules.

Exit your SSH session and log in again to make sure your access is still OK with these new firewall rules.

Whew – another piece finished!

Installing Fail2Ban

Fail2Ban automatically prevents people from connecting when they have too many failed login attempts. Malicious automated bots out there often try thousands of username and password combinations and tie up your server; Fail2Ban stops these attempts early on.

Note: Fail2Ban provide an additional layer of security on top of the previous SSH changes you’ve made to this point by blocking malicious attempts. Additionally, Fail2Ban can be configured to block malicious activity on other services like HTTP and FTP. Visit the Official Fail2Ban Documentation for advanced configuration options.

Enter the following commands at the shell prompt:

sudo rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
sudo yum install fail2ban

Fail2Ban isn’t available in the usual package repositories that CentOS ships with. The first line lets the system know about the Extra Packages for Enterprise Linux (or EPEL) repository, which includes many useful third-party libraries and utilities.

The second line then installs Fail2Ban itself. Accept the prompts to install the package and associated dependencies.

Next, set up the configuration file with the following commands:

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local

Fail2Ban comes with some default configuration settings in jail.conf, but you don’t want to modify it directly because upgrading Fail2Ban later may overwrite this configuration file. To keep things clean, make a copy called jail.local which Fail2Ban reads as local customizations.

Once jail.local opens in the editor, find the line starting with ignoreip. If you have a static IP, or at least one that doesn’t change very often on your end, you can add it to this list to stop Fail2Ban from blocking you if you have too many failed logon attempts. You can Google “what is my ip address” and it will give it to you in the search results. Google FTW! :]

The line will look similar to the following once you’re done editing:

ignoreip = 127.0.0.1/8 103.209.112.213

Next, find the line starting with bantime and change it as follows:

bantime = 3600

If a system fails to authenticate itself after a certain number of attempts, Fail2Ban locks them out for 600 seconds by default. 10 minutes is not a lot of time for a persistent attacker, so this new value of 3600 bumps that up that to an hour.

Save and close your file. Since this is a fresh install of Fail2Ban, start it manually with the following command:

sudo service fail2ban start

In the future, you can edit the configuration file and use the command above with “restart” in place of “start” to have the Fail2Ban service start automatically.

If you want some late night reading material, the jail.local file defines ban parameters for every protocol on the server (Apache, FTP, etc) and examples of how to set up different options for each one for the ultimate customization possibilities.

Installing Apache

LAMP servers – Linux, Apache, MySQL, and PHP – are the de facto configuration these days and power everything from simple blogs and websites like the one you are building in this tutorial all the way up to infrastructure that companies like Facebook and Twitter built their legacy on.

Enter the following command at the prompt:

sudo yum install httpd

This installs the Apache web server. CentOS names the package httpd after the name of the executable, while other Linux distributions might call it Apache. Don’t worry, the names all refer to the same thing. :]

Next, you’ll need to set up the configuration file. Execute the commands below:

cp /etc/httpd/conf/httpd.conf ~/httpd.conf.backup
sudo nano /etc/httpd/conf/httpd.conf

Just like you did for Fail2Ban, first copy the default configuration to a backup file in case you need it in the future. Once you have the backup, you then open httpd.conf in a text editor.

In httpd.conf file, find the section for the prefork module as shown below:

<IfModule prefork.c>
StartServers       2
MinSpareServers    6
MaxSpareServers   12
ServerLimit      128
MaxClients       128
MaxRequestsPerChild  3000
</IfModule>

Change the values in your file to match the list above. These values are optimized for Apache running on the base Linode server and allow for a low number of active services/threads but allow the server to ramp up when the traffic starts flowing in.

Finally, find the ServerName line in your file, and uncomment it by removing the # character at the start of the line and change the default value to localhost. Your line should look like the following:

ServerName localhost

Save the file and exit the editor by hitting Control-X. Then start Apache with the following command:

sudo service httpd start

Open up your favorite web browser and browse to the IP address of your server to see your new web site in all its glory!

<pre lang="html">sudo yum install httpd</pre>

That’s the L and the A — there’s only two more letters to go in LAMP.

Installing MySQL

Enter these commands at the prompt to install MySQL:

sudo yum install mysql-server
sudo service mysqld start
sudo /usr/bin/mysql_secure_installation

Getting MySQL up and running requires only these three lines. It doesn’t get much easier than that! :]

The first line above installs the package and any required dependencies. The second line starts up the MySQL service. And finally, the third line runs a configuration script to secure the installation of MySQL.

When running through the mysql_secure_installation steps, you’ll be prompted for a root password for MySQL — just hit enter as you don’t have one yet. You’ll be prompted to create one, so do so. Say yes to all of the installation prompts, such as remove anonymous users, drop test database, and all others.

You might be wondering whether to allow incoming MySQL connections through your firewall. This is generally a bad idea for security reasons. The only thing connecting to your database should be your applications on your server. Allowing random strangers from the Internet to touch your MySQL database directly is a bad idea.

Up to this point, you’ve been installing software and starting it up manually. If your server is rebooted though, you’d have to manually start all the services you installed such as Apache and MySQL.

To save you the headache, enter these commands at the shell prompt to set your services to automatically start:

sudo chkconfig fail2ban on
sudo chkconfig httpd on
sudo chkconfig mysqld on

The chkconfig program is short for “check configuration” and sets up the services that should start automatically.

Installing PHP

PHP is just as easy to install. It doesn’t have its own server, but it’s called from Apache so you don’t have to worry about starting up another service.

Install PHP with the following command:

sudo yum install php php-mysql php-pear

Notice that there are a couple packages specified in the yum call above:

  • php – base install of PHP.
  • php-mysql – PHP components specifically for interacting with MySQL.
  • php-pear – an extension repository that offers many helper components.

PHP requires some tuning in order to be more secure, developer friendly, and performant. Open up the default PHP configuration with the following command:

sudo nano /etc/php.ini

Edit the three lines shown below in your version of php.ini:

error_reporting = E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR
error_log = /var/log/php.log
max_input_time = 30

Each of these changes are found in different locations in php.ini, but instead of scrolling around the file looking for them, you can hit Control-W in the text editor to search and find the configuration keys such as “error_reporting” and “max_input_time”.

Here’s what each change above does:

  • error_reporting – sets what kind of errors to show. There are several categories of errors, notices, and warnings; you can combine them with the | character as shown.
  • error_log – sets the location of the log file. While your web site is running, you can check this file to check for errors.
  • max_input_time – sets the maximum time a script to run. Setting a value here helps prevent runaway scripts from taking up all the processor time and slowing down the server.

Save and close the file when you’re done. Again, PHP will be called from Apache so there’s no separate PHP service to start. However, you do need to restart the web server so that it detects the new PHP installation, so restart the web server with the following command:

sudo service httpd restart

To confirm that your LAMP stack is running correctly, you need a basic web page to replace the generic Apache test page.

Open up the default web page in a text editor:

sudo nano /var/www/html/index.php

Modify the contents of the file to look like the following:

<h1>Hello World!</h1>
 
<p>LAMP on Linode checking in! :]</p>
 
<?php echo "<p>And don't forget about PHP.</p>"; ?>
 
<p>- Love, RayWenderlich.com</p>

Be creative here and show off your HTML and PHP skills! Enter your server’s IP address in a browser and you’ll see this message instead of the Apache start page.

Hello, LAMP on Linode!

Setting Up Your Domain

No one these days says “check out 127.0.0.1″. Although 127.0.0.1 is where the ♥ is…ha! Okay, sorry, bad geek joke.

People want to use domain names like HowToSetupLinode.com instead. It’s also good for business, branding, and easy to remember.

Luckily, getting a domain name is quick and simple!

First, buy a domain that you want to use. In this case, we used GoDaddy and the domain howtosetuplinode.com.

Once you’ve registered the domain name, view the domain properties by selecting the Launch button on the right under the Action section, shown below:

Linode_GoDaddy

Select the DNS Zone File tab and click the Edit button, like so:

Linode_GoDaddy_DNS

Edit the A (Host) record and change the IP address to the address of your Linode server as shown below:

Linode_GoDaddy_DNS2

Edit the NS (Nameserver) section and add 4 entries for Linode’s name servers as ns1.linode.com, ns2.linode.com, ns3.linode.com, and ns4.linode.com.

Set the Points To address to an “@” sign – this tells the Nameserver to go look at what is defined for the “@” address set as the A (Host) record in the previoius step — this points to your Linode server.

Your configuration should resemble the screenshot below:

Linode_GoDaddy_DNS3

Save the changes via the big black button in the top center of the window and we’re done with GoDaddy.

Head to Linode.com and log in. On the DNS Manager tab, click the Add a domain zone option, like so:

Linode_DNS_Manager

Enter the domain name you want routed to your server and add a contact email in the event there are any issues with routing traffic, as such:

Linode_DNS_Setup

Finally, click the Add a Master Zone button, and that’s it! A new domain name can take up to 48 hours to propagate over the internet, if your domain doesn’t resolve right away, be patient; you can always use the IP address in the meantime.

Where to Go From Here?

Congratulations! You now have your very own LAMP server configured with some security best-practices, and you can host a basic website on your own. From here, the sky’s the limit!

If you want to create a more robust website but don’t have the necesasry HTML/JS/CSS chops, Twitter’s Bootstrap framework is extremely popular and comes ready for mobile, tablet, and desktop websites out of the box. Likewise, WordPress offers the ability to host your own blog on your server.

If you want to learn more about CentOS system administration, the CentOS 6 Linux Server Cookbook offers a no non-sense look at building and running a CentOS server. Alternatively, if you’d prefer a straight-from-the-source guide, Red Hat has created a System Administration Guide that discusses every detail of working with CentOS.

Hopefully you enjoyed the tutorial; if you have any questions or comments, please let us know in the forum discussion below!

How to Set Up a LAMP server on Linode is a post from: Ray Wenderlich

The post How to Set Up a LAMP server on Linode appeared first on Ray Wenderlich.


Video Tutorial: Table Views Search

Readers’ App Reviews – March 2014

$
0
0
zest

Readers’ Apps!

It is March, so you know what that means: more great apps by fellow readers ready for the world!

Once again I’ve been lucky enough to play with all your apps and pick a few to showcase. It’s a hard job, but someone’s got to do it! :]

Here are some of the highlights from this month:

  • A space shooter that brings back memories of Galaga
  • A combination of Tetris and Candy Crush
  • An app to help you learn foreign language vocabulary

So stop what you’re doing now: it’s app time!

Time Clash

timeclash
Battle evil across the ages in Time Clash!

Time Clash takes your hero through time to fight evil every-when. Fight hordes of enemies with special abilities and weapons. Grab powerups to help and upgrade your hero between levels.

But you’re not alone, summon an army of allies to fight beside you or get a pet for moral support.

Retro Blaster

RetroBlaster
Retro Blaster brings fond memories of our favorite games from arcades of the past.

With classic graphics and sound effects Retro Blaster brings a modern touch. And thanks to flingable bombs you even get a bit of touch screen delight.

Space Invaders, Galaga, Centipede, and more are all represented in this retro fusion remake. It’s a blast from the past!

Connectris Multiplayer

connectris
Bejeweled and Candy Crush are kinda fun, but then again so is Tetris. Lets combine them!

Connectris is a Tetris style game where the goal isn’t lines of blocks, but instead 3+ color matches. It takes the strategy dynamic to a whole new level.

During endless single player, combos build your energy which you can use to eliminate entire colors. But during GameCenter multiplayer your energy bar can be used to drop iron bricks on your opponent to give you the edge.

Gold Word

goldword
Gold Word is a different kind of word game.

Gold Word provides 7 letters and your goal is to find the highest point word, the Gold Word. You get points for lesser words too, and speed counts, you’ve only got 30 seconds.

With its fast paced head to head play, Gold Word becomes a fantastic multiplayer game. You both get the same letters and same time limit. Highest scoring word wins!

Don Julio

donjulio
Don Julio is on a mission. He needs the most exotic ingredients for his restaurant.

You can help Don Julio battle chickens and goats while he hunts for the ingredients at the end of the rainbow in the sidescrolling platformer. You’ll visit Spain, Peru, Italy, and more.

Bonus points for a sweet setting that allows you to drag and drop the controls whereever you’d like them.

Pickabulary

pickabulary
Pickabulary is a great tool for learning new vocabulary for foreign languages.

Pickabulary lets you enter your own word sets along with their translations, then offers chances to practice, learn, and test yourself. It will keep track of the words you have trouble with so you can revisit them more often.

I’ll defintely be putting Pickabulary to use in my German classes.

Rare Steak Timer

steakTimer
Cooking steak isn’t always east. Sometimes we forget about it, sometimes we just don’t have a feel for how long to leave it on.

Rare Steak Timer helps. Pick your cut, select a thickness, and then decide how you want it cooked. Rare Steak Timer will tell you how long it needs to sizzle, and fire a timer when it’s done. It will even remind you to flip it. Don’t forget to let it rest before you stuff your face. ;]

Melody DJ

melodyDJ
Melody DJ is a Guitar Hero style game in your pocket.

Melody DJ has you take the lead playing the melody of your favorite songs in realtime. If you mess up, you’ll know about it.

Its landscape design means you are tapping notes all over the place as they come from down screen. This was a very addicting game to have in your pocket. Who’s got two thumbs and Melody DJ? This guy. :]

Mouse or House

mouseHouse
Mouse or House is a cute game for the younger kids.

Kids get to wipe away the frost on the glass to see the card underneath, then they match it to the 3 cards on the right. It’s got 30 very cute illustrations kids will love to uncover.

Yardhoppr

yardhoppr
Yardhoppr is a great app when you just want to shop around local.

Yardhoppr uses aggregator 3taps to find all the yard sales, garage sales, estate sales, and auctions around you. You can see a map of the closest ones and favorite the ones you’d like to hit.

Yardhoppr offers turn by turn directions when you’re ready to go.

Sync and Swim

syncswim
Sync and Swim is a great pattern and memory game for kids.

Sync and Swim has patterns repetition, 3 card memory matching, and timed pattern repetitions. With cute begging to be touched, kids with love it.

Its a addictive so make sure you share with your kids. :P

Lost Lands – a Treasure Hunt Puzzle Game

lostlands
If you’re addicted to puzzles like I am, then this is another one for you.

Lost Lands is a path finding game. You’ve got to make it to the gem at the end. There are one way doors in your way though so you’ll have to pick your path carefully.

Collect sapphires, emeralds, and rubies in this retro art styled puzzle game. There are a 168 gems to collect so you’ll be listening to Indiana Jones on your iPod for awhile. ;]

Shubru

Shubru
Shubru isn’t satisfied with order. Shubru wants chaos!

You must defeat him with reflexes, both mental and physical. Reorder the clouds before the time runs out.

But don’t expect Shubru to give up that easily, he’ll keep swapping clouds all the way through. And he’s got a few more tricks up his sleeve as you battle through 50 levels of organizational fun.



Honorable Mentions

I had some apps I couldn’t review. Don’t feel bad, it wasn’t a popularity contest or even a rating contest. Forum members get priority, among other factors. I make time to try out every app that comes across my screen, one day I’ll find time to write about them all too!

Juggler

appay

Luminetic Land

TimeSaver app

Pixel Fixor

HushBox

KittyPow!

FlexiTimer

5 Mins Mystery

Titi & Miro Adventure

Jumpy Flying Squirrel

Balz!

Squishy Fish

ShiftCal

Guess Guess Movie

Fight With Ghosts

Crow’s Quest

Vivid Sudoku

Holoradix Motion Comics

FileStation

Wheel of Pain Push-Ups

ClosetApp

SnapLite Highlight Text in Photos, Scans and PDFs

WriteDrawGame

Seohtracker

The Falling Man



Where To Go From Here?

As expected, I really enjoyed your apps – it’s great fun to see what fellow readers make each month.

If you’ve never made an app, we’ve got you covered! Check out our free tutorials to become an iOS star. What are you waiting for – I want to see your app next month!

If you’ve already made the next great app, let me know about it! Submit here!

Readers’ App Reviews – March 2014 is a post from: Ray Wenderlich

The post Readers’ App Reviews – March 2014 appeared first on Ray Wenderlich.

Video Tutorial: Table Views Indexing

Introduction to RestKit Tutorial

$
0
0

Need coffee now? You're gonna write an app for that!

Update 02/24/2014: Updated RestKit tutorial for new version of the RestKit library.

There are a lot of web services that you can connect to to get interesting and useful data.

For example, Twitter has a web service you can use to list and send Tweets, and Foursquare has a web service you can connect to that allows you to retrieve a list of restaurants near your current location.

If you want to use these APIs, you can connect to them directly with NSURLRequest or a wrapper library like AFNetworking. However, there’s an easier way for many of these APIs – use RestKit!

RestKit is a popular and easy-to-use framework that saves you from having to write much of the boring code you usually have to when working with web service APIs, such as parsing JSON or mapping responses to objects.

In this RestKit tutorial, we’ll try it out with by making a simple app that uses the FourSquare API to list the coffee shops nearby – because we all love and need our coffee! :]

This tutorial is for any level of iOS developer, from beginner to advanced. So read on and get ready for a RESTful caffeine buzz! If you are not sure about networking in general on iOS yet, the I suggest checking out some of the other tutorials on this site

Getting Started

To start, we’re going to create a Master-View application in Xcode. If you’re already familiar with how to do this and how it works, feel free to glance through this quickly and move to the next section – but I’m going to include some more details for the beginners.

Start up Xcode and create a new project with the iOS\Application\Master-Detail Application template.

Enter CoffeeKit for the product name, set device family to iPhone (leave “Use Core Data” checkbox unchecked):

Project settings for CoffeeKit app

Click Next and choose a location to save your project.

The Master-Disciple, er, wait… Master-Detail template is a fully-functioning app, so build and run.

You should see a blank screen with Edit and Add (+) buttons. Click the (+) button to add some table entries to the Master screen. Tapping one of these entries will show a Detail screen:

You can see how this format is perfect for lists of data that contain different levels of information. Open MasterViewController.h. You will see something like this:

#import <UIKit/UIKit.h>
 
@interface MasterViewController : UITableViewController
 
@end

MasterViewController is a UITableViewController, which manages a UITableView and conforms to two protocols: UITableViewDelegate and UITableViewDataSource. UITableViewDataSource handles the data model needs for the UITableView, and UITableViewDelegate handles the appearance needs of the UITableView (such as managing selections; configuring section headers and footers; deleting and reordering of cells).

Look at some key methods in MasterViewController.m:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    return 1; 
}
 
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{
    return _objects.count; 
}
 
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath 
{ 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
 
    NSDate *object = [_objects objectAtIndex:indexPath.row];
    cell.textLabel.text = [object description];
    return cell; 
}

The first two methods, numberOfSectionsInTableView: and tableView:numberOfRowsInSection: are as their names imply. You use them to tell the table how many sections it has and how many rows are in each section.

You specify the data displayed in each cell using tableView:cellForRowAtIndexPath:.

For this tutorial, you’ll only be using the Master View Controller to display a list of nearby coffee shops. To keep things simple, the Detail View Controller will not be used. So remove the following:

  • prepareForSegue:sender: from MasterViewController.m
  • The #import for DetailViewController.h at the top of MasterViewController.m.
  • The files DetailViewController.h and DetailViewController.m. (Make sure you choose Move to trash – you really don’t need these any more!)

Next, delete “Detail View Controller – Detail” from Main.storyboard. Yes that’s right, the entire view controller! You can find it here:

RESTing Easy

OK now on to the fun stuff – RestKit!

The RestKit GitHub project describes RestKit as the following:

RestKit is a modern Objective-C framework for implementing RESTful web services clients on iOS and Mac OS X. It provides a powerful object mapping engine that seamlessly integrates with Core Data and a simple set of networking primitives for mapping HTTP requests and responses built on top of AFNetworking. It has an elegant, carefully designed set of APIs that make accessing and modeling RESTful resources feel almost magical.

…like unicorns.

RestKit has three main components:

  1. Network – RestKit now uses AFNetworking v1.3.3 for the network layer. RestKit maintainers are working on updating to AFNetworking 2.0.
  2. Object Mapping – Provides a simple API for turning remote JSON/XML responses into local objects.
  3. Core Data – Provides additional support on top of the object mapper for mapping remote resources to persisted local objects. (No Core Data for this tutorial)

In other words, that’s all a lot of code that you don’t have to write! ;]

The hardest thing about working with RestKit is the installation and setup. There are two setup options: CocoaPods (with automatic configuration, i.e. the easy way) or Git submodule (with manual configuration, the harder way). I recommend using CocoaPods.

  1. The first option is using CocoaPods: [for more on CocoaPods, see Introduction to CocoaPods.]

    Open up Terminal and enter the following commands:

    $ sudo gem install cocoapods
    $ pod setup
    $ cd /path/to/CoffeeKit
    $ touch Podfile
    $ [edit] Podfile (using your preferred editor; vim, nano, etc)
    platform :ios, '5.0'
    pod 'RestKit', '~> 0.20.0'

    Install RestKit into your project:

    $ pod install

    Close your CoffeeKit.xcodeproj and reopen CoffeeKit.xcworkspace.

  2. The second option is as a Git submodule:

    Open up Terminal and enter the following commands:

    $ cd /path/to/CoffeeKit
    $ git init 
    $ git submodule add git://github.com/RestKit/RestKit.git RestKit
    $ git submodule update --init --recursive

    Next, add RestKit to your project. In a Finder window, open the RestKit folder inside your CoffeeKit project folder. Drag RestKit.xcodeproj into the Project Navigator in Xcode, like this:

    Now that you’ve told your project RestKit is there, it’s time for the most detailed step: configuring Restkit so you can use it properly. You’ll both configure settings and add some frameworks to your build configuration.

    1. Click on the top item in the Project Navigator pane and select the CoffeeKit target.
    2. Click the Build Settings filter for Other Linker Flags in the search box. Click the value column to the right of Other Linker Flags, add -ObjC and hit return.

      other_linker_flag

    3. Now clear the search box text and input Header Search Paths. Double click the value column to the right of Header Search Paths, add "$(BUILT_PRODUCTS_DIR)/../../Headers" to the list (be sure to include the quotes) and hit return. Then click outside the drop down to return to the build settings.

    4. Now click on the Build Phases tab, click on the disclosure triangle for Target Dependencies, and tap the Add (+) button. Select RestKit and click Add.
    5. Now click on the Link Binary With Libraries disclosure triangle and tap the Add (+) button. Select libRestKit.a and click Add.
    6. You also need to add some required Apple frameworks. Click the Add (+) button again and select the following: (⌘-click for multi-select)

      • CFNetwork.framework
      • CoreData.framework
      • MobileCoreServices.framework
      • Security.framework
      • SystemConfiguration.framework

      Click Add one last time!

    7. Next you need to update the precompiled header file to avoid build warnings from AFNetworking. Open CoffeeKit-Prefix.pch (it’ll be under Supporting Files). Replace the contents with the following:
      #ifndef __IPHONE_5_0
      #warning "This project uses features only available in iOS SDK 5.0 and later."
      #endif
       
      #ifdef __OBJC__
          #import <UIKit/UIKit.h>
          #import <Foundation/Foundation.h>
          #import <SystemConfiguration/SystemConfiguration.h>
          #import <MobileCoreServices/MobileCoreServices.h>
      #endif

For the final step in the setup, verify your RestKit installation and configuration. Open AppDelegate.m, and add the following:

#import <RestKit/RestKit.h>

Build and run. If it builds without error, RestKit is set up correctly. Feel the force!

Connecting with Foursquare

Now that you have RestKit working, you can use it to connect to Foursquare’s web services to get venue data for your app.

You will be using Foursquare’s Search Venues API to search for coffee shops near your current location.

Don’t worry about reading that whole document right now, just know we’ll be using this basic query (feel free to click it to try it out!):

This will return JSON-formatted data of coffee-related venues located near Apple Headquarters (latitude: 37.33 and longitude: -122.03). Foursquare’s identifier for venues categorized as “Coffee Shop” is
“categoryId=4bf58dd8d48988d1e0931735”. And to clarify for our Dutch-speaking friends, at FourSquare, the “Coffee Shop” category is for venues that specialize in selling brewed beverages prepared from the roasted and ground seeds of several species of an evergreen shrub of the genus Coffea.

A typical JSON response to the basic query will look something like this:

{
    "meta": {
        "code": 200
    },
    "notifications": [
        {
            "item": {
                "unreadCount": 3
            },
            "type": "notificationTray"
        }
    ],
    "response": {
        "confident": true,
        "neighborhoods": [],
        "venues": [
            {
                "categories": [
                    {
                        "icon": {
                            "prefix": "https://ss1.4sqi.net/img/categories_v2/food/coffeeshop_",
                            "suffix": ".png"
                        },
                        "id": "4bf58dd8d48988d1e0931735",
                        "name": "Coffee Shop",
                        "pluralName": "Coffee Shops",
                        "primary": true,
                        "shortName": "Coffee Shop"
                    }
                ],
                "contact": {
                    "formattedPhone": "(408) 446-9000",
                    "phone": "4084469000",
                    "twitter": "philzcoffee"
                },
                "hereNow": {
                    "count": 0,
                    "groups": []
                },
                "id": "51630409498eedc7dd88e60b",
                "location": {
                    "address": "20686 Stevens Creek Blvd",
                    "cc": "US",
                    "city": "Cupertino",
                    "country": "United States",
                    "crossStreet": "De Anza Blvd",
                    "distance": 936,
                    "lat": 37.32246179607897,
                    "lng": -122.03470838696346,
                    "postalCode": "95014",
                    "state": "CA"
                },
                "name": "Philz Coffee",
                "referralId": "v-1390061483",
                "specials": {
                    "count": 0,
                    "items": []
                },
                "stats": {
                    "checkinsCount": 3790,
                    "tipCount": 40,
                    "usersCount": 1460
                },
                "verified": true
            },
            {
                "categories": [
                    {
                        "icon": {
                            "prefix": "https://ss1.4sqi.net/img/categories_v2/food/coffeeshop_",
                            "suffix": ".png"
                        },
                        "id": "4bf58dd8d48988d1e0931735",
                        "name": "Coffee Shop",
                        "pluralName": "Coffee Shops",
                        "primary": true,
                        "shortName": "Coffee Shop"
                    }
                ],
                "contact": {
                    "formattedPhone": "(650) 321-2161",
                    "phone": "6503212161",
                    "twitter": "philz_coffee"
                },
                "hereNow": {
                    "count": 0,
                    "groups": []
                },
                "id": "4dd1580eb3adb047f5024231",
                "location": {
                    "address": "101 Forest Ave",
                    "cc": "US",
                    "city": "Palo Alto",
                    "country": "United States",
                    "crossStreet": "at Alma St.",
                    "distance": 17063,
                    "lat": 37.442086282055726,
                    "lng": -122.16159119091502,
                    "postalCode": "94301",
                    "state": "CA"
                },
                "name": "Philz Coffee",
                "referralId": "v-1390061483",
                "specials": {
                    "count": 0,
                    "items": []
                },
                "stats": {
                    "checkinsCount": 14168,
                    "tipCount": 118,
                    "usersCount": 4044
                },
                "verified": true
            }
        ]
    }
}

Foursquare provides free access to their web services, as long as you register your app using the OAuth Consumer Registration page, so make sure you do that before going any further.

First, go to this page on Foursquare. You should see a form similar to this:

Enter a name, CoffeeKit and a random download URL and redirect URI. These can be dummy pages on your website. Your app will be a mobile connection, and won’t actually make use of these. Check out Foursquare’s User Authentication page for more information.

Click Save Changes.

You’ll then be given a Client ID and a Client Secret that you can use for Foursquare API calls.

You need to add these to your source code so that RestKit can authenticate itself when making any Foursquare API calls. Add the following to the top of MasterViewController.m, right below the #import lines:

#define kCLIENTID @"Your Foursquare Client ID"
#define kCLIENTSECRET @"Your Foursquare Client Secret"

Remember that you must replace the dummy values above with the actual client ID and secret you receive from Foursquare.

Time to Code, It Is Surely

You have all the pieces in place to build your app. All you need to do now is add the code!

You will use two of the main components of RestKit: Network and Object Mapping. For Network, you define the base URL for Foursquare’s API, (https://api.foursquare.com) and send/receive your messages. For Object Mapping, you create a data model that you will map to the returned JSON values.

The JSON output above lists two venues. So, use that output to define a Venue data model class.

  1. Select File/New/File… (or right-click in the Project Navigator then click New File…, or ⌘-N).

  2. Select iOS\Cocoa Touch\Objective-C class and click Next.

  3. Enter Venue for class name, NSObject for subclass of and click Next.

  4. Choose a location and click Create.

The only JSON venue data you are adding for now is the venue name. So, open Venue.h, and add a property for name:

@interface Venue : NSObject
 
@property (nonatomic, strong) NSString *name;
 
@end

You will add more in a bit, when needed.

Next, open MasterViewController.m. Then add the following imports at the top of the file:

#import <RestKit/RestKit.h>
#import "Venue.h"

And modify viewDidLoad to:

- (void)viewDidLoad
{
    [super viewDidLoad];
 
    [self configureRestKit];
    [self loadVenues];
}

Then add the following method (one of the two you added a call to in viewDidLoad above):

- (void)configureRestKit
{
    // initialize AFNetworking HTTPClient
    NSURL *baseURL = [NSURL URLWithString:@"https://api.foursquare.com"];
    AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:baseURL];
 
    // initialize RestKit
    RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:client];
 
    // setup object mappings
    RKObjectMapping *venueMapping = [RKObjectMapping mappingForClass:[Venue class]];
    [venueMapping addAttributeMappingsFromArray:@[@"name"]];
 
    // register mappings with the provider using a response descriptor
    RKResponseDescriptor *responseDescriptor = 
        [RKResponseDescriptor responseDescriptorWithMapping:venueMapping 
                                                     method:RKRequestMethodGET 
                                                pathPattern:@"/v2/venues/search" 
                                                    keyPath:@"response.venues" 
                                                statusCodes:[NSIndexSet indexSetWithIndex:200]];
 
    [objectManager addResponseDescriptor:responseDescriptor];
}

Here you define the base URL for Foursquare’s API. All requests will be appended to this URL. This is nice if you make requests to several endpoints at the same service. Using this base URL, you create a AFHTTPClient object, and pass that client to create an RKObjectManager. RKObjectManager is the primary interface for interacting with RESTful services.

The RKObjectMapping class defines the mapping between a JSON attribute and your data model’s attribute. addAttributeMappingsFromArray is a shortcut method to use when the JSON and your data model share the same keys, which is “name” in your case. You will add other mappings later in this tutorial.

Next, you create an RKResponseDescriptor, which describes an object mapping that is applicable to an HTTP response. pathPattern matches against URLs for which the mapping should be used. This is appended to the base URL. keyPath is a subset of the parsed JSON response data for which the mapping should be used. Looking at the JSON sample data above, you see that venues is inside of the response object. So, keyPath:@"response.venues" tells RestKit where to find the venue objects.

Now add the following method:

- (void)loadVenues
{
    NSString *latLon = @"37.33,-122.03"; // approximate latLon of The Mothership (a.k.a Apple headquarters)
    NSString *clientID = kCLIENTID;
    NSString *clientSecret = kCLIENTSECRET;
 
    NSDictionary *queryParams = @{@"ll" : latLon,
                                  @"client_id" : clientID,
                                  @"client_secret" : clientSecret,
                                  @"categoryId" : @"4bf58dd8d48988d1e0931735",
                                  @"v" : @"20140118"};
 
    [[RKObjectManager sharedManager] getObjectsAtPath:@"/v2/venues/search"
                      parameters:queryParams
                         success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
                                     _venues = mappingResult.array;
                                     [self.tableView reloadData];
                                 }
                         failure:^(RKObjectRequestOperation *operation, NSError *error) {
                                     NSLog(@"What do you mean by 'there is no coffee?': %@", error);
                                 }];
}

This creates and sends a request to, and receives a response from Foursquare.

The getObjectsAtPath:parameters:success:failure: method is being used to fetch the objects. This is just doing a normal HTTP request, using AFNetworking, to Foursquare’s API with path /v2/venues/search. When the response comes back, it uses the response descriptor mapping you set up earlier in configureRestKit to map the response to Venue objects.

You’ll notice that there is a problem building at the moment though. This is because the success block sets the value of the venues property. But this doesn’t exist. To fix this, open MasterViewController.m, then change the following code at the top:

@interface MasterViewController () {
    NSMutableArray *_objects;
}
@end
 
@implementation MasterViewController

to this:

@interface MasterViewController ()
 
@property (nonatomic, strong) NSArray *venues;
 
@end
 
@implementation MasterViewController

Also, in the same file, change:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
 
    NSDate *object = [_objects objectAtIndex:indexPath.row];
    cell.textLabel.text = [object description];
    return cell;
}

to:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
 
    Venue *venue = _venues[indexPath.row];
    cell.textLabel.text = venue.name;
 
    return cell;
}

Also, still in MasterViewController.m, change the return statement in tableView:numberOfRowsInSection: to:

return _venues.count;

Finally, remove the tableView:commitEditingStyle: and insertNewObject: methods from MasterViewController.m, since the data is no longer editable. (Plus, Xcode throws a few compilation errors if you don’t remove/fix those methods :])

Build and run. You should see something similar to this:

You’ll notice some of the places on this list aren’t actually coffee houses, such as Kaiser Permanente and Nokia. I blame Foursquare for that! :P

Stylin’ the Cells

We want to make the cells look a bit nicer. Open Main.storyboard and find the master view controller. Click on the single “prototype cell”. You should see something like this:

One of the options in the image above is the table view cell’s Style. The default is Basic. It provides a left-aligned text label in the cell. The other provided options are:

  • Right Detail
  • Left Detail   
  • Subtitle       

These other options make it possible to show a detail of your choice in the Master view. For example, if you were to use this app to find nearby coffee shops, it would be nice to see how far away each shop is from your present location. Nobody wants to go too far for a coffee fix!

Change the style to Right Detail.

In the JSON data above, the location field provides the distance:

"location": {
    "address": "20686 Stevens Creek Blvd",
    "cc": "US",
    "city": "Cupertino",
    "country": "United States",
    "crossStreet": "De Anza Blvd",
    "distance": 936,
    "lat": 37.32246179607897,
    "lng": -122.03470838696346,
    "postalCode": "95014",
    "state": "CA"
}

So that RestKit can retrieve this, create a Location data model and provide the mapping. Here are the steps:

  1. Create a new file called Location, a subclass of NSObject.
  2. In Location.h, add the following properties:
    @property (nonatomic, strong) NSString *address;
    @property (nonatomic, strong) NSString *city;
    @property (nonatomic, strong) NSString *country;
    @property (nonatomic, strong) NSString *crossStreet;
    @property (nonatomic, strong) NSString *postalCode;
    @property (nonatomic, strong) NSString *state;
    @property (nonatomic, strong) NSNumber *distance;
    @property (nonatomic, strong) NSNumber *lat;
    @property (nonatomic, strong) NSNumber *lng;
  3. Now in Venue.h, add the following at the top, under the imports:
    @class Location;

    And also add the following property:

    @property (nonatomic, strong) Location *location;
  4. Open MasterViewController.m, add the following import at the top:
    #import "Location.h"
  5. Now, still in the same file, add the Location mappings at the bottom of configureRestKit
    // define location object mapping
    RKObjectMapping *locationMapping = [RKObjectMapping mappingForClass:[Location class]];
    [locationMapping addAttributeMappingsFromArray:@[@"address", @"city", @"country", @"crossStreet", @"postalCode", @"state", @"distance", @"lat", @"lng"]];
     
    // define relationship mapping
    [venueMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"location" toKeyPath:@"location" withMapping:locationMapping]];
  6. This is similar to the Venue mapping you did earlier, except for addPropertyMapping:. It informs your venueMapping instance to use locationMapping for its location property.

  7. Change the contents of tableView:cellForRowAtIndexPath: to:
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
     
    Venue *venue = _venues[indexPath.row];
    cell.textLabel.text = venue.name;
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%.0fm", venue.location.distance.floatValue];
     
    return cell;

Build and run. Now you should see something like this:

The ‘m’ stands for meters, not miles. Also remember that we’re still using the latitude/longitude for Apple HQ – if you want you might want to replace it with your own lat/lng coordinates. For more info on how to do that, check out this tutorial.

Customizing TableViewCells

Let’s wrap things up by displaying the Foursquare checkins in our table view cell as well. To do this, we’ll need to make a custom table view cell.

Open Main.storyboard. Change the table view cell style to Custom. The default labels will disappear. In the Size Inspector, change the Row Height to Custom and from 44 to 64.

Set the Row Height property of the table view itself to 64 as well.

Add 3 UILabels: name, distance and checkins. Make it look like this:

Since the cell is now set to Custom style, you cannot use UITableViewCell‘s textLabel and detailTextLabel properties to add text to the labels. This means that in order to refer to the individual labels, you need to create a subclass of UITableViewCell with custom labels for venue name, distance, and check-ins.

Add a new file to the project, with the Objective-C class template. Name it VenueCell and make it a subclass of UITableViewCell.

Replace VenueCell.h contents with the following:

#import <UIKit/UIKit.h>
 
@interface VenueCell : UITableViewCell
 
@property (nonatomic, weak) IBOutlet UILabel *nameLabel;
@property (nonatomic, weak) IBOutlet UILabel *distanceLabel;
@property (nonatomic, weak) IBOutlet UILabel *checkinsLabel;
 
@end

Replace VenueCell.m contents with the following:

#import "VenueCell.h"
 
@implementation VenueCell
 
@end

As you can see, this class doesn’t do much: it just adds properties for nameLabel, distanceLabel and checkinsLabel.

Next, open Main.storyboard again. Then, select the prototype cell and set its class to VenueCell in the Identity Inspector. Also, in the Attributes Inspector, change Identifier to VenueCell.

These items don’t need to match, but it is good to match them for consistency and clarity.

Now connect the outlets to the labels in VenueCell. In the Connections Inspector, connect the outlets: nameLabel, distanceLabel and checkinsLabel to their respective UILabels.

Open MasterViewController.m. Add an import for VenueCell at the top:

#import "VenueCell.h"

Still in MasterViewController.m, replace tableView:cellForRowAtIndex: with the following:

VenueCell *cell = [tableView dequeueReusableCellWithIdentifier:@"VenueCell" forIndexPath:indexPath];
 
Venue *venue = _venues[indexPath.row];
cell.nameLabel.text = venue.name;
cell.distanceLabel.text = [NSString stringWithFormat:@"%.0fm", venue.location.distance.floatValue];
cell.checkinsLabel.text = [NSString stringWithFormat:@"%d checkins", venue.stats.checkins.intValue];
 
return cell;

This won’t work if you try to build and run, because Venue does not have a stats property… yet. Just as with location data, Foursquare provides venue stats in the JSON data:

"stats": {
    "checkinsCount": 3790,
    "tipCount": 40,
    "usersCount": 1460
},

And just as for the location data, you need to create a Stats data model and provide the mapping for RestKit.

  1. Create a new file called Stats, and make it a subclass of NSObject.
  2. In Stats.h, add the following properties:
    @property (nonatomic, strong) NSNumber *checkins;
    @property (nonatomic, strong) NSNumber *tips;
    @property (nonatomic, strong) NSNumber *users;
  3. In Venue.h, add the following at the top, underneath the other class forward-declaration you added earlier:
    @class Stats;
  4. Then add the following property:
    @property (strong, nonatomic) Stats *stats;
  5. In MasterViewController.m, add the following import at the top:
    #import "Stats.h"
  6. Then add the Stats mappings to the bottom of configureRestKit
    RKObjectMapping *statsMapping = [RKObjectMapping mappingForClass:[Stats class]];
    [statsMapping addAttributeMappingsFromDictionary:@{@"checkinsCount": @"checkins", @"tipsCount": @"tips", @"usersCount": @"users"}];
     
    [venueMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"stats" toKeyPath:@"stats" withMapping:statsMapping]];

For statsMapping, this time you’re changing things by using addAttributeMappingsFromDictionary: instead of addAttributeMappingsFromArray:. The Stats properties are defined checkins, tips, and users, while the JSON fields are checkinsCount, tipsCount and usersCount. This method therefore provides the mapping from the JSON key to the object’s property name.

Using addAttributeMappingsFromDictionary: comes in real handy when the JSON response fields are labeled with Objective-C keywords like id and description. This is because id is a keyword in Objective-C so you cannot use it as a property name. Similarly, description is already a method on all NSObjects. So you wouldn’t want to override that by creating a property with the same name!

Build and run, and you should see something like this:

Wow, who knew that Kaiser Permanente had an on-call Barista. ;]

Note: If you have any crashes at this point, double-check to make sure that you set the Identifier for the cell to “VenueCell” in Main.storyboard. That’s the most likely culprit.

Where to Go From Here?

Here is a example project with all of the code from the above tutorial.

Here is list of what you have done:

  • An introduction to UITableView using the Master-Detail Application template.
  • RestKit installation and configuration for your app.
  • Foursquare configuration for your app and an introduction to their Venues API.
  • Created data models for your app.
  • Setup RestKit mappings so that it can request, receive and parse the data into your data model.
  • Created a custom table view cell to display the Foursquare data.

Here is what you did not do:

  • Setup and use NSURLConnections or NSURLConnectionDelegates.
  • Parse JSON or XML data.
  • Map the JSON or XML responses to your own objects.

Because RestKit handled all of this for you! Not bad, eh?

From here, feel free set up Foursquare user authentication to gain full access to Foursquare’s API and extend this example with even more features, or find other web services that you can use RestKit to provide data for your app.

I hope you enjoyed this tutorial, and if you have any questions on it or RestKit in general, please join the forum discussion below!


This is a post by iOS Tutorial Team Member Scott McAlister, an iOS developer at Flat World Knowledge.

Introduction to RestKit Tutorial is a post from: Ray Wenderlich

The post Introduction to RestKit Tutorial appeared first on Ray Wenderlich.

Cookbook: Moving Table View Cells with a Long Press Gesture

$
0
0
Cookbook: Move table view cells with a long press gesture!

Cookbook: Move table view cells with a long press gesture!

In this cookbook-style tutorial you will learn how to move a table view row by using a long press gesture, like in Apple’s Weather App.

You can either add this code directly to your project, add it to a starter project I’ve made for you, or just download the completed example.

What do you need?

  • UILongGestureRecognizer
  • UITableView (it can be substituted with UICollectionView)
  • UITableViewController (it can be substituted with UIViewController or UICollectionViewController)
  • 5 minutes.

How to do it?

Start by adding a UILongGestureRecognizer to the table view. You can do this in viewDidLoad for your table view controller.

UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] 
  initWithTarget:self action:@selector(longPressGestureRecognized:)];
[self.tableView addGestureRecognizer:longPress];

Next add the action method for gesture recognizer. It should start by getting the location of the long press in the table view, and find the corresponding index path for the cell at that location. Remember the index path might be nil (for example, if the user taps and holds on a section header of the table view).

- (IBAction)longPressGestureRecognized:(id)sender {
 
  UILongPressGestureRecognizer *longPress = (UILongPressGestureRecognizer *)sender;
  UIGestureRecognizerState state = longPress.state;
 
  CGPoint location = [longPress locationInView:self.tableView];
  NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
 
  // More coming soon...
}

Next you’ll handle the UIGestureRecognizerStateBegan case. If there is a valid (non-nil) index path, get the corresponding UITableViewCell and take a snapshot view of the table view cell using a helper method. Then add the new snapshot view to the table view and center it on the corresponding cell.

For a better user experience and a more natural effect black out the original cell, fade in the snapshot view, make the snapshot view slightly bigger, and offset its Y coordinate to align with gesture’s location Y. This way it appears as if the cell is popped out of the table view, floating over it and snapped to user’s finger.

static UIView       *snapshot = nil;        ///< A snapshot of the row user is moving.
static NSIndexPath  *sourceIndexPath = nil; ///< Initial index path, where gesture begins.
 
switch (state) {
  case UIGestureRecognizerStateBegan: {
    if (indexPath) {
      sourceIndexPath = indexPath;
 
      UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
 
      // Take a snapshot of the selected row using helper method.
      snapshot = [self customSnapshotFromView:cell];
 
      // Add the snapshot as subview, centered at cell's center...
      __block CGPoint center = cell.center;
      snapshot.center = center;
      snapshot.alpha = 0.0;
      [self.tableView addSubview:snapshot];
      [UIView animateWithDuration:0.25 animations:^{
 
        // Offset for gesture location.
        center.y = location.y;
        snapshot.center = center;
        snapshot.transform = CGAffineTransformMakeScale(1.05, 1.05);
        snapshot.alpha = 0.98;
 
        // Black out.
        cell.backgroundColor = [UIColor blackColor];
      } completion:nil];
    }
    break;
  }
  // More coming soon...
}
// Add this at the end of your .m file. It returns a customized snapshot of a given view.
- (UIView *)customSnapshotFromView:(UIView *)inputView {
 
  UIView *snapshot = [inputView snapshotViewAfterScreenUpdates:YES];
  snapshot.layer.masksToBounds = NO;
  snapshot.layer.cornerRadius = 0.0;
  snapshot.layer.shadowOffset = CGSizeMake(-5.0, 0.0);
  snapshot.layer.shadowRadius = 5.0;
  snapshot.layer.shadowOpacity = 0.4;
 
  return snapshot;
}

As gesture moves (the UIGestureRecognizerStateChanged case), move the snapshot view by offsetting its Y coordinate only. If the gesture moves enough that its location corresponds to a different index path, tell the table view to move the rows. At the same time, you should update your data source too:

case UIGestureRecognizerStateChanged: {
  CGPoint center = snapshot.center;
  center.y = location.y;
  snapshot.center = center;
 
  // Is destination valid and is it different from source?
  if (indexPath && ![indexPath isEqual:sourceIndexPath]) {
 
    // ... update data source.
    [self.objects exchangeObjectAtIndex:indexPath.row withObjectAtIndex:sourceIndexPath.row];
 
    // ... move the rows.
    [self.tableView moveRowAtIndexPath:sourceIndexPath toIndexPath:indexPath];
 
    // ... and update source so it is in sync with UI changes.
    sourceIndexPath = indexPath;
  }
  break;
}
// More coming soon...

Finally, when the gesture either ends or cancels, both the table view and data source are up to date. All you have to do is removing the snapshot view from table view and reverting the blackout.

For a better user experience, fade out the snapshot view and make it smaller to match the size of the cell. It appears as if the cell drops back into its place.

default: {
  // Clean up.
  UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:sourceIndexPath];
  [UIView animateWithDuration:0.25 animations:^{
 
    snapshot.center = cell.center;
    snapshot.transform = CGAffineTransformIdentity;
    snapshot.alpha = 0.0;
 
    // Undo the black-out effect we did.
    cell.backgroundColor = [UIColor whiteColor];
 
  } completion:^(BOOL finished) {
 
    [snapshot removeFromSuperview];
    snapshot = nil;
 
  }];
  sourceIndexPath = nil;
  break;
}

That’s it; build and run your project, and you can now use a long press gesture to reorder your table view cells!

You can checkout the completed project here at GitHub.

How to use this with UICollectionView?

Assuming you have already a sample project that uses UICollectionView, you can easily adopt the above code for that project. All you have to do is replacing self.tableView with self.collectionView and updating calls to get and move UICollectionViewCell.

To do an exercise, checkout the starter project of UICollectionView from GitHub and add tap-and-hold gesture to it for re-ordering cells. You can checkout the UICollectionView answer here from GitHub.

Where to go from here?

We hope you enjoyed this cookbook article! If you would like to see more cookbook-style articles like this in the future, please let us know.

Also, if you’d prefer to learn about this in video format, we have a video tutorial for that.

Also, I’d love to hear your comments or questions in the forums below!

Cookbook: Moving Table View Cells with a Long Press Gesture is a post from: Ray Wenderlich

The post Cookbook: Moving Table View Cells with a Long Press Gesture appeared first on Ray Wenderlich.

Video Tutorial: Beginner OpenGL ES and GLKit Part 0: Introduction

Video Tutorial: Beginner OpenGL ES and GLKit Part 1: Hello, OpenGL!


How to Make a Game Like Mega Jump With Sprite Kit: Part 1/2

$
0
0
Create a game like Mega Jump using Sprite Kit

Make A Game Like Mega Jump Using Sprite Kit

In this two-part tutorial series, you will use Sprite Kit to create a game in the style of Mega Jump. If you’ve somehow missed trying Mega Jump from the App Store, it’s a quite popular vertical jumping game with really nice graphics and addictive gameplay. As you build your game, you’ll learn how to use a number of Sprite Kit’s capabilities, including the physics engine, collision detection, accelerometer control and scene transitions.

If you are new to Sprite Kit, it would be best to work your way through Ray’s Sprite Kit Tutorial for Beginners before starting this tutorial series.

But if you’re comfortable with the basics of Sprite Kit, then—jump right in!

Getting Started

You are going to create a game similar to Mega Jump. Yours will obviously be a truly amazing game and so it needs a truly amazing title. As everyone knows, “uber” is better than “mega,” so let’s call your game “Uber Jump.” ;]

At its heart, a game like Mega Jump is a physics game. The game hurls the player character up the screen and from that point the player must fight against gravity to get as high as they can. Collecting coins boosts the player upward while platforms provide temporary respite along the way.

Uber Jump will take the same model, initially thrusting your player character upward and continuously applying gravity to pull them down. Collecting stars along the way will propel the player further on their journey upward, taking care of the up and down (y-axis) portion of the player’s movement (miss too many stars and you fall down though!). The accelerometer will handle the player’s left and right movement (x-axis).

The result will be a complex, hybrid physics manipulation, as you both apply forces to the player node and also directly change its velocity. It’ll also be lots of fun!

To begin, you need a brand new Sprite Kit Xcode project. Fire up Xcode, select File\New\Project, choose the iOS\Application\SpriteKit Game template and click Next.

01-NewProject

Enter UberJump for the Product Name, iPhone for Devices and then click Next.

02-NewProjectName

Choose somewhere to save the project and click Create. Then build and run the fledgling project, and you will see the following in the Simulator:

03-NewProjectRun

Before getting down to business, let’s do some preliminary setup. There’s an ugly black-text status bar at the top of the screen. You don’t want that in your game—it will just get in the way of the action.

Open ViewController.m and add the following method to the implementation:

- (BOOL) prefersStatusBarHidden
{
  return YES;
}

This is iOS 7’s callback method for a view controller to determine whether or not to show the status bar. You are telling the view controller to hide the status bar.

Build and run again, and—voilà, no more status bar.

uj_screen_nostatusbar

You have one last thing to set up. Since your game is going to use the accelerometer, you need to make sure that tilting the device doesn’t flip the game into landscape mode.

With your project selected in the Project Navigator in Xcode, select the UberJump target, go to the General settings tab and look in the Deployment Info section. Ensure that the only available device orientation is Portrait.

04-NewProjectPortrait

Now you are ready to start adding your game’s components. First up: the pretty pictures.

Importing the Art

Before you get down to adding Sprite Kit nodes to your game, you need some art.

Download the graphics resources for this project, unzip the archive and drag the contents into your Xcode project. Make sure that “Copy items into destination group’s folder (if needed)” is checked and that your UberJump target is selected.

uj_asset_files

I’ve split the artwork into background tiles and game assets.

Background tiles are large tiles that scroll up and down the screen as the player moves:

uj_bg_thumb

The game assets are all of the sprites, such as the player character, platforms and stars:

Player@2x

The game assets are stored in a texture atlas for efficiency. You can learn more about texture atlases in Sprite Kit in this tutorial.

Note: I pieced together the graphics for Uber Jump using the amazing artwork provided by lostgarden.com. This website provides high-quality graphics for devs to use in prototyping their games and is well worth a visit. You can check their exact licensing policy.

Building the Scene

In your project, you can see that the Sprite Kit template has already created the MyScene class for you. This is the Sprite Kit scene that is currently showing the “Hello, World!” message when you run the game. Most of Uber Jump’s action will take place here, so open MyScene.m and replace the contents with the following:

#import "MyScene.h"
 
@implementation MyScene
 
- (id) initWithSize:(CGSize)size
{
  if (self = [super initWithSize:size]) {
    self.backgroundColor = [SKColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];
 
  }
  return self;
}
 
@end

Build and run. MyScene now displays a simple white screen. This is the blank canvas onto which you’ll add your game nodes.

Mega Jump uses parallaxed layers to produce a neat visual representation of speed. (Eg. things in front move faster than things in the background.) In Uber Jump, you’re going to produce the same effect by creating the following layers in your scene:

  • Background: a slow-moving layer that shows the distant landscape.
  • Midground: faster-moving scenery made up of tree branches.
  • Foreground: the fastest layer, containing the player character, stars and platforms that make up the core of the gameplay.
  • HUD: the top layer that does not move and displays the score labels.

First, add the background node. Open MyScene.m and add the following method:

- (SKNode *) createBackgroundNode
{
  // 1
  // Create the node
  SKNode *backgroundNode = [SKNode node];
 
  // 2
  // Go through images until the entire background is built
  for (int nodeCount = 0; nodeCount < 20; nodeCount++) {
    // 3
    NSString *backgroundImageName = [NSString stringWithFormat:@"Background%02d", nodeCount+1];
    SKSpriteNode *node = [SKSpriteNode spriteNodeWithImageNamed:backgroundImageName];
    // 4
    node.anchorPoint = CGPointMake(0.5f, 0.0f);
    node.position = CGPointMake(160.0f, nodeCount*64.0f);
    // 5
    [backgroundNode addChild:node];
  }
 
  // 6
  // Return the completed background node
  return backgroundNode;
}

Let’s take a closer look at what you’re doing here:

  1. First, you create a new SKNode. SKNodes have no visual content, but do have a position in the scene. This means you can move the node around and its child nodes will move with it.
  2. You have 20 background images to stack to complete the background.
  3. Each child node is made up of an SKSpriteNode with the sequential background image loaded from your resources.
  4. Changing each node’s anchor point to its bottom center makes it easy to stack in 64-point-tall sections.
  5. You add each child node to the background node.
  6. Finally, you return the background node.

Now you can add the background node to your scene. Still in MyScene.m, add the following class extension above the @implementation section:

@interface MyScene ()
{
  // Layered Nodes
  SKNode *_backgroundNode;
  SKNode *_midgroundNode;
  SKNode *_foregroundNode;
  SKNode *_hudNode;
}
@end

You are adding private instance variables for each of the nodes you need for the game. You only need the background node for the moment, but it doesn’t hurt to add the other node declarations now.

To add the background to the scene, insert the following into initWithSize: in MyScene.m, just after the line that sets the background color:

// Create the game nodes
// Background
_backgroundNode = [self createBackgroundNode];
[self addChild:_backgroundNode];

Build and run to see your background node displayed in the scene, as shown below:

05-BackgroundNode

Note: Although you added 20 nodes to the background node, you’ll see that the node count in the scene is only nine nodes if you’re running on a 4″ display or eight nodes if you’re running on a 3.5″ display. Sprite Kit is clever enough to include only the nodes that are actually visible at any given moment in the game.

Adding the Player Node

It’s time for your Uber Jumper to enter the scene. In MyScene.m, add the following method:

- (SKNode *) createPlayer
{
  SKNode *playerNode = [SKNode node];
  [playerNode setPosition:CGPointMake(160.0f, 80.0f)];
 
  SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:@"Player"];
  [playerNode addChild:sprite];
 
  return playerNode;
}

As with the background node you added earlier, you create a new SKNode and add the SKSpriteNode to it as a child. You position the player node so that it is not at the bottom of the scene.

To add the player node to the scene, you first need to create a foreground node. As discussed above, the foreground node will contain the player, the stars and the platforms. That means when you move the foreground node, all the game elements it contains will move together.

Add the following to initWithSize:, just after the line that adds _backgroundNode to the scene:

// Foreground
_foregroundNode = [SKNode node];
[self addChild:_foregroundNode];

Now that you have your foreground node for the gameplay elements, you can add the player node to it.

At the top of MyScene.m, add the following variable to the class extension along with the other variables you added to hold the layer nodes:

// Player
SKNode *_player;

Now add the player node to the scene by inserting the following into initWithSize:, just after the line that adds _foreground to the scene:

// Add the player
_player = [self createPlayer];
[_foregroundNode addChild:_player];

Build and run to see your Uber Jumper ready to start their adventure:

06-ForegroundNode

Adding Gravity and a Physics Body

The Uber Jumper looks a little too comfortable sitting there, so you’re going bring some physics into play and see what happens.

First, your game can’t have physics without gravitation. In MyScene.m, add the following line to initWithSize:, after the line that sets the background color:

// Add some gravity
self.physicsWorld.gravity = CGVectorMake(0.0f, -2.0f);

You add a suitable amount of gravity to the physics world, based on the gameplay you want to achieve. Gravity has no influence along the x-axis, but produces a downward force along the y-axis.

Build and run to see how this gravity affects the player node.

06-ForegroundNode

Hmm… Nothing happened. Why isn’t the gravity affecting the player node? See if you can figure it out yourself before clicking below to see the answer.

Solution Inside: Solution SelectShow>

In createPlayer, add the following just before the return statement at the end:

// 1
playerNode.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:sprite.size.width/2];
// 2
playerNode.physicsBody.dynamic = YES;
// 3
playerNode.physicsBody.allowsRotation = NO;
// 4
playerNode.physicsBody.restitution = 1.0f;
playerNode.physicsBody.friction = 0.0f;
playerNode.physicsBody.angularDamping = 0.0f;
playerNode.physicsBody.linearDamping = 0.0f;

The above code defines the player node’s physics body. Take a look at it in detail:

  1. Each physics body needs a shape that the physics engine can use to test for collisions. The most efficient body shape to use in collision detection is a circle (easier to detect if overlaps another circle you see), and fortunately a circle fits your player node very well. The radius of the circle is half the width of the sprite.
  2. Physics bodies can be static or dynamic. Dynamic bodies are influenced by the physics engine and are thus affected by forces and impulses. Static bodies are not, but you can still use them in collision detection. That is, a static body will never move, but things can bump into it. Since you want your player node to be affected by gravity, you set it’s dynamic property to YES.
  3. You want your player node to remain upright at all times and so you disable rotation of the node.
  4. Since you’re handling collisions yourself in this game, you adjust the settings on the player node’s physics body so that it has no friction or damping. However, you set its restitution to 1, which means the physics body will not lose any of its momentum during collisions.

Build and run to see your player sprite fall off the bottom of the screen as gravity draws it relentlessly toward the Earth’s core.

05-BackgroundNode

Perhaps that sounded a little melodramatic, but how is an Uber Jumper supposed to get anywhere in this world?

Tap To Start

Now that gravity is working, you’re going to give the player sprite a fighting chance and make its physics body static until the user actually decides to start playing.

Still inside MyScene.m, find the line in createPlayer that sets the dynamic property on playerNode‘s physics body. Change it to NO, as shown here:

playerNode.physicsBody.dynamic = NO;

You are going to write code to allow the player to start the game by tapping the screen. The player needs to know this, though, so first you need to put some instructions on the screen.

Since the instructions will go in your HUD node, create that layer first. In initWithSize:, just after where you add the foreground node to the scene, insert the following code:

// HUD
_hudNode = [SKNode node];
[self addChild:_hudNode];

The starter project includes an image that tells the player to tap to start the game, so add the following variable to the class extension at the top of MyScene.m:

// Tap To Start node
SKSpriteNode *_tapToStartNode;

To show the node, add the following code to initWithSize:, just after the line that adds the player node:

// Tap to Start
_tapToStartNode = [SKSpriteNode spriteNodeWithImageNamed:@"TapToStart"];
_tapToStartNode.position = CGPointMake(160, 180.0f);
[_hudNode addChild:_tapToStartNode];

Build and run, and you will see the instruction to “Tap to Start” above the player sprite:

07-TapToStart

To respond to touch events and start the game, add the following method to MyScene.m:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
  // 1
  // If we're already playing, ignore touches
  if (_player.physicsBody.dynamic) return;
 
  // 2
  // Remove the Tap to Start node
  [_tapToStartNode removeFromParent];
 
  // 3
  // Start the player by putting them into the physics simulation
  _player.physicsBody.dynamic = YES;
  // 4
  [_player.physicsBody applyImpulse:CGVectorMake(0.0f, 20.0f)];
}

Take a look at the method in detail:

  1. You check to see if the player node is already dynamic. If so, you ignore the touch event and return.
  2. You remove the Tap to Start node.
  3. You change the player node’s physics body to dynamic so that the physics engine can influence it.
  4. You give the player node an initial upward impulse to get them started.

Build and run. When you tap the screen, the game removes the Tap to Start node and thrusts the player sprite upward, albeit briefly, before gravity takes over.

Game Objects: Reach for the Stars!

To give your player something to do—as well as some upward momentum—it’s “high” time for you to add stars to your game. Stars have a key role in Uber Jump: They are what the player needs to grab to move higher into the level.

Initially, you will add one star to the game and implement it fully. Then in Part Two of this tutorial, you’ll complete the level.

In Uber Jump, as in Mega Jump, when the player sprite goes a certain distance higher than a star, platform or any other game object, the game will remove that object from the scene. Since star and platform nodes share this functionality, it makes sense to create a subclass of SKNode for all game objects.

Create a new Objective-C class called GameObjectNode and make it a subclass of SKNode.

08-NewClassGameObjectNode

GameObjectNode will provide the following functionality:

  • It will remove the game object from the scene if the player node has passed it by more than a set distance.
  • It will handle collisions between the player node and the object. This method will return a BOOL that informs the scene whether the collision with the game object has resulted in a need to update the HUD—for example, if the player has scored points.

Add the following method declarations to GameObjectNode.h:

// Called when a player physics body collides with the game object's physics body
- (BOOL) collisionWithPlayer:(SKNode *)player;
 
// Called every frame to see if the game object should be removed from the scene
- (void) checkNodeRemoval:(CGFloat)playerY;

You’ll call collisionWithPlayer: whenever the player node collides with this object, and you’ll call checkNodeRemoval: every frame to give the node a chance to remove itself.

Add the following definitions for these methods to GameObjectNode.m:

- (BOOL) collisionWithPlayer:(SKNode *)player
{
  return NO;
}
 
- (void) checkNodeRemoval:(CGFloat)playerY
{
  if (playerY > self.position.y + 300.0f) {
    [self removeFromParent];
  }
}

In the GameObjectNode class, collisionWithPlayer: is simply a stub. You will define the full method in each of your game object subclasses.

checkNodeRemoval: checks to see if the player node has traveled more than 300 points beyond this node. If so, then the method removes the node from its parent node and thus, removes it from the scene.

The Star Class

Now that you have a base class for the interactive game nodes, you can create a class for your stars. Create a new Objective-C class called StarNode and make it a subclass of GameObjectNode.

09-NewClassStarNode

In StarNode.m, add the following implementation of collisionWithPlayer: for the star:

- (BOOL) collisionWithPlayer:(SKNode *)player
{
  // Boost the player up
  player.physicsBody.velocity = CGVectorMake(player.physicsBody.velocity.dx, 400.0f);
 
  // Remove this star
  [self removeFromParent];
 
  // The HUD needs updating to show the new stars and score
  return YES;
}

Collision with a star boosts the player node up the y-axis. You may be thinking, “Why am I not using a force or impulse in the physics engine to do this?”

If you were to apply the star boost as a force or impulse, it wouldn’t always have the same effect. For example, if the player node were moving down the screen when it collided with the star, then the force would have a much weaker effect on the player than if the player were already moving up the screen.

The following diagram shows a very simplified visualization of this:

10-ForcesAndBounce

A solution to this problem is to change the player node’s velocity directly. The player node’s velocity is obviously made up of an x-axis speed and a y-axis speed.

The x-axis speed needs to stay the same, since it is only affected by the accelerometer, which you’ll implement later. In the method above, you set the y-axis velocity to 400 on collision—a fixed amount so that the collision has the same effect no matter what the player node is doing when it collides with the star.

Now add your new star class to the scene. Open MyScene.m and import your StarNode class header:

#import "StarNode.h"

Now add the following method to MyScene:

- (StarNode *) createStarAtPosition:(CGPoint)position
{
  // 1
  StarNode *node = [StarNode node];
  [node setPosition:position];
  [node setName:@"NODE_STAR"];
 
  // 2
  SKSpriteNode *sprite;
  sprite = [SKSpriteNode spriteNodeWithImageNamed:@"Star"];
  [node addChild:sprite];
 
  // 3
  node.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:sprite.size.width/2];
 
  // 4
  node.physicsBody.dynamic = NO;
 
  return node;
}

The code above should all look familiar by now:

  1. You instantiate your StarNode and set its position.
  2. You then assign the star’s graphic using an SKSpriteNode.
  3. You’ve given the node a circular physics body – you use it for collision detection with other objects in the game.
  4. Finally, you make the physics body static, because you don’t want gravity or any other physics simulation to influence the stars.

Now add the following code to initWithSize:, just before where you create the player node. You want the stars to be behind the player in the foreground node and so you need to add them before you add the player node.

// Add a star
StarNode *star = [self createStarAtPosition:CGPointMake(160, 220)];
[_foregroundNode addChild:star];

Build and run the game. Tap to start and watch the player sprite collide with the star.

11-FirstStar

The Uber Jumper bonks its head on the star. That wasn’t the plan! Why do you think that happened? Take a guess.

Solution Inside: Solution SelectShow>

Collision Handling and Bit Masks

To handle collisions between the player and star nodes, you need to capture the collision event and call the GameObjectNode method collisionWithPlayer:.

This is a good time to take a look at collision bit masks in Sprite Kit.

When setting up collision information for your physics bodies, there are three bit mask properties you can use to define the way the physics body interacts with other physics bodies in your game:

  • categoryBitMask defines the collision categories to which a physics body belongs. [TODO: Can a physics body belong to more than one category? If not, make “categories” singular.]
  • collisionBitMask identifies the collision categories with which this physics body should collide. Here, “collide” means to bump into each other as physical objects would. For example, in a third-person shooter you may want your player sprite to collide with enemy sprites, but pass through other player sprites.
  • contactTestBitMask tells Sprite Kit that you would like to be informed when this physics body makes contact with a physics body belonging to one of the categories you specify. For example, in your game you want Sprite Kit to tell you when the player sprite touches a star or a platform. [TODO: I think we need to distinguish between “makes contact with” and “collides with” – that the categories in this bit mask don’t have to be collision categories.] Using the correct combination of settings for the contactTestBitMask and the collisionBitMask, you can tell Sprite Kit to let objects pass through each other but still notify you when that happens so you can trigger events.

First, define your categories. Open MyScene.m and add the following typedef above the @interface section:

typedef NS_OPTIONS(uint32_t, CollisionCategory) {
  CollisionCategoryPlayer   = 0x1 << 0,
  CollisionCategoryStar     = 0x1 << 1,
  CollisionCategoryPlatform = 0x1 << 2,
};

To set up the player node’s collision behavior, add the following code to the bottom of createPlayer, just before the return statement:

// 1
playerNode.physicsBody.usesPreciseCollisionDetection = YES;
// 2
playerNode.physicsBody.categoryBitMask = CollisionCategoryPlayer;
// 3
playerNode.physicsBody.collisionBitMask = 0;
// 4
playerNode.physicsBody.contactTestBitMask = CollisionCategoryStar | CollisionCategoryPlatform;

Let’s take a closer look at this code block:

  1. Since this is a fast-moving game, you ask Sprite Kit to use precise collision detection for the player node’s physics body. After all, the gameplay for Uber Jump is all about the player node’s collisions, so you’d like it to be as accurate as possible! (it costs few more cpu cycles, but the fun is considerably more!)
  2. This defines the physics body’s category bit mask. It belongs to the CollisionCategoryPlayer category.
  3. By setting collisionBitMask to zero, you’re telling Sprite Kit that you don’t want its physics engine to simulate any collisions for the player node. That’s because you’re going to handle those collisions yourself!
  4. Here you tell Sprite Kit that you want to be informed when the player node touches any stars or platforms.

Now set up the star node. Add the following code to the bottom of createStarAtPosition:, just before the return statement:

node.physicsBody.categoryBitMask = CollisionCategoryStar;
node.physicsBody.collisionBitMask = 0;

This is similar to your setup for the player node. You assign the star’s category and clear its collisionBitMask so it won’t collide with anything. In this case, though, you don’t set its contactTestBitMask, which means Sprite Kit won’t notify you when something touches the star. You already instructed Sprite Kit to send notifications when the player node touches the star, which is the only contact with the star that you care about, so there’s no need to send notifications from the star’s side.

Sprite Kit sends notifications for the node contacts you’ve registered by calling didBeginContact: on its SKContactDelegate. Set the scene itself as the delegate for the physics world by adding the SKContactDelegate protocol to the MyScene class extension in MyScene.m. It should now look like this:

@interface MyScene () <SKPhysicsContactDelegate>

Now register the scene to receive contact notifications by adding the following line to initWithSize:, just after the line that sets the gravity:

// Set contact delegate
self.physicsWorld.contactDelegate = self;

Finally, add the following method to MyScene.m to handle collision events:

- (void) didBeginContact:(SKPhysicsContact *)contact
{
  // 1
  BOOL updateHUD = NO;
 
  // 2
  SKNode *other = (contact.bodyA.node != _player) ? contact.bodyA.node : contact.bodyB.node;
 
  // 3
  updateHUD = [(GameObjectNode *)other collisionWithPlayer:_player];
 
  // Update the HUD if necessary
  if (updateHUD) {
    // 4 TODO: Update HUD in Part 2
  }
}

Let’s take a closer look at this code:

  1. You initialize the updateHUD flag, which you’ll use at the end of the method to determine whether or not to update the HUD for collisions that result in points.
  2. SKPhysicsContact does not guarantee which physics body will be in bodyA and bodyB. You know that all collisions in this game will be between the player node and a GameObjectNode, so this line figures out which one is not the player node.
  3. Once you’ve identified which object is not the player, you call the GameObjectNode’s collisionWithPlayer: method.
  4. This is where you will update the HUD, if required. You’ll implement the HUD in Part Two, so there’s nothing but a comment here for now.

Build and run the game. Tap to start. Upon collision, the star provides the player sprite with a sizable boost and then removes itself from the scene. Good work!

12-FirstStarCollision

That was a lot of heavy lifting there! Take a well-deserved break before moving on. In the next section, you’re going to add a new star type—the uber star—as well as a cool sound effect.

Note: If you want to know more about detecting contacts and collisions in Sprite Kit feel free to check out “iOS Games by Tutorials“, which contains 3 solid chapters on Sprite Kit physics.

Multiple Star Types

Uber Jump will have two different kinds of stars: those worth a single point and special stars worth five points. Each star-type will have its own graphic. To identify the star type, you’ll have an enumeration in the StarNode class.

At the top of StarNode.h, add the following enumeration:

typedef NS_ENUM(int, StarType) {
  STAR_NORMAL,
  STAR_SPECIAL,
};

To store the star type, add the following property to the StarNode interface in StarNode.h:

@property (nonatomic, assign) StarType starType;

You now need to specify a star type when creating a star, so in MyScene.m, add starType as a parameter to the createStarAtPosition: method signature so that it looks like this:

- (StarNode *) createStarAtPosition:(CGPoint)position ofType:(StarType)type

Inside createStarAtPosition:ofType:, replace the three lines of code that create and add the SKSpriteNode with the following:

[node setStarType:type];
SKSpriteNode *sprite;
if (type == STAR_SPECIAL) {
  sprite = [SKSpriteNode spriteNodeWithImageNamed:@"StarSpecial"];
} else {
  sprite = [SKSpriteNode spriteNodeWithImageNamed:@"Star"];
}
[node addChild:sprite];

First, you set the star type. Then, when you create the sprite, you check to see which star type it is so you can get the correct graphic.

All that remains is to specify a star type when you create the star. In initWithSize: in MyScene.m, find the line where you call createStarAtPosition: and replace it with this:

StarNode *star = [self createStarAtPosition:CGPointMake(160, 220) ofType:STAR_SPECIAL];

You specify that you would like this star to be a STAR_SPECIAL type.

Build and run. Your star is now pink! Later, you’ll add a scoring system and the differences in star types will become more apparent.

13-FirstStarSpecial

Ping! Adding a Sound Effect

It would be nice if, when the player collides with the star, they got an audible cue. Download the star sound effect here and drag it into your Xcode project. Make sure that “Copy items into destination group’s folder (if needed)” is checked and that your UberJump target is selected.

To add sound effects to your StarNode class, you need to import the AVFoundation library, so at the top of StarNode.m, add the following line:

@import AVFoundation;

In Sprite Kit, you use SKActions to play sounds. At the top of StarNode.m, add the following class extension:

@interface StarNode ()
{
  SKAction *_starSound;
}
@end

Now all that remains is to instantiate the sound action and run it when the player node collides with the star.

Add the following init method to StarNode.m:

- (id) init
{
  if (self = [super init]) {
    // Sound for when a star is collected
    _starSound = [SKAction playSoundFileNamed:@"StarPing.wav" waitForCompletion:NO];
  }
 
  return self;
}

This instantiates the SKAction with a sound file. You set up the action here so it will be ready to play when you need it. If you were to create it when you wanted to play it, the user would notice a delay in the game as the app loaded the sound resource.

Add the following line to collisionWithPlayer: in StarNode.m, just before the line that removes the node from its parent:

// Play sound
[self.parent runAction:_starSound];

This runs the sound SKAction using the star node’s parent node. You use the parent node rather than the star node itself because the very next line removes the star node from its parent. Running the action on the star itself wouldn’t work because the node would be gone before the action had a chance to run.

Build and run. As the player sprite collides with the star, you’ll hear a delightful, twinkly ping. :]

Game Objects: Platforms

In the final section of the first part of this tutorial, you’re going to add a platform to the scene. You’ll represent platforms with a new subclass of GameObjectNode so that you get all the associated goodness from that class. As with the stars, you’ll have two types of platforms: one that is indestructible and one that disappears as soon as the player sprite has jumped off of it.

Start by creating a new Objective-C class called PlatformNode and make it a subclass of GameObjectNode.

14-NewClassPlatformNode

In PlatformNode.h, add the following enumeration above the @interface section to define the two platform types:

typedef NS_ENUM(int, PlatformType) {
  PLATFORM_NORMAL,
  PLATFORM_BREAK,
};

Still in PlatformNode.h, add a property for the platform type to the interface:

@property (nonatomic, assign) PlatformType platformType;

In PlatformNode.m, add the following implementation of collisionWithPlayer::

- (BOOL) collisionWithPlayer:(SKNode *)player
{
  // 1
  // Only bounce the player if he's falling
  if (player.physicsBody.velocity.dy < 0) {
    // 2
    player.physicsBody.velocity = CGVectorMake(player.physicsBody.velocity.dx, 250.0f);
 
    // 3
    // Remove if it is a Break type platform
    if (_platformType == PLATFORM_BREAK) {
      [self removeFromParent];
    }
  }
 
  // 4
  // No stars for platforms
  return NO;
}

Let’s take a closer look at this code:

  1. As is common in this type of game, the player node should only bounce if it hits a platform while falling, which is indicated by a negative dy value in its velocity. This check also ensures the player node doesn’t collide with platforms while moving up the screen.
  2. You give the player node a vertical boost to make it bounce off the platform. You accomplish this the same way you did for the star, but with a less powerful boost. You want stars to be important, right?
  3. If this is a PLATFORM_BREAK-type platform, then you remove the platform from the scene.
  4. Finally, the Uber Jumper doesn’t get points from bouncing on or off platforms so there is no need to refresh the HUD.

To add a platform to your scene, open MyScene.m and import the PlatformNode header at the top, like so:

#import "PlatformNode.h"

Now add the following method:

- (PlatformNode *) createPlatformAtPosition:(CGPoint)position ofType:(PlatformType)type
{
  // 1
  PlatformNode *node = [PlatformNode node];
  [node setPosition:position];
  [node setName:@"NODE_PLATFORM"];
  [node setPlatformType:type];
 
  // 2
  SKSpriteNode *sprite;
  if (type == PLATFORM_BREAK) {
    sprite = [SKSpriteNode spriteNodeWithImageNamed:@"PlatformBreak"];
  } else {
    sprite = [SKSpriteNode spriteNodeWithImageNamed:@"Platform"];
  }
  [node addChild:sprite];
 
  // 3
  node.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:sprite.size];
  node.physicsBody.dynamic = NO;
  node.physicsBody.categoryBitMask = CollisionCategoryPlatform;
  node.physicsBody.collisionBitMask = 0;
 
  return node;
}

This method is very similar to createStarAtPosition:ofType:, but note these main points:

  1. You instantiate the PlatformNode and set its position, name and type.
  2. You choose the correct graphic for the SKSpriteNode based on the platform type.
  3. You set up the platform’s physics, including its collision category.

Now to add the platform, insert the following code in initWithSize:, just before the line that creates the star:

// Add a platform
PlatformNode *platform = [self createPlatformAtPosition:CGPointMake(160, 320) ofType:PLATFORM_NORMAL];
[_foregroundNode addChild:platform];

Build and run the game. Tap to start and watch as the player sprite gets a boost from the star and then bounces on the platform!

15-FirstPlatform

Where to Go From Here?

Well done! As you’ve seen, creating a game like Mega Jump is not that hard at all. You’ve got all the basics of Uber Jump in place and are on your way to building a great game.

Here is the project with everything you’ve done so far in this tutorial series.

In Part Two of the series, you’ll implement the accelerometer for movement on the x-axis. You’ll also load an entire level from a property list and add a scoring system. That’s a lot to look forward to, right? ;]

Please post a comment below if you have any questions, thoughts or suggestions for future tutorials!

How to Make a Game Like Mega Jump With Sprite Kit: Part 1/2 is a post from: Ray Wenderlich

The post How to Make a Game Like Mega Jump With Sprite Kit: Part 1/2 appeared first on Ray Wenderlich.

Video Tutorial: Beginner OpenGL ES and GLKit Part 2: Vertex Buffers and Attributes

How to Make a Game Like Mega Jump With Sprite Kit: Part 2/2

$
0
0
Create a game like Mega Jump using Sprite Kit

Make a game like Mega Jump using Sprite Kit!

Welcome to the second part of the tutorial series that walks you through using Sprite Kit to create a game like Mega Jump.

In the first part of the tutorial, you created a new Sprite Kit game called “Uber Jump.” You added graphics, a player sprite and some gameplay elements.

In this second part, you’ll use that firm foundation to build an entire level for Uber Jump, including a scoring system. You’ll also add accelerometer support so that your Uber Jumper can move from side to side as well as up and down. When you’re done, you’ll have a completely playable game that you could expand in many different ways.

As with Part One, be sure you are familiar with the basics of Sprite Kit before continuing.

Your level awaits—so let’s jump to it!

Getting Started

If you don’t have it already, grab a copy of the complete project from Part One.

Your level will contain many stars and platforms. Rather than arrange them manually, download this level configuration file. Unzip it and drag Level01.plist into your Xcode project. Make sure that Copy items into destination group’s folder (if needed) is checked and that your UberJump target is selected.

Open Level01.plist and examine its contents. At the root, it has three elements:

  • EndY specifies the height the player must reach to finish the level.
  • Stars defines the positions of all the stars in the level.
  • Platforms defines the positions of all the platforms in the level.

The Stars and Platforms elements each contain two sub-elements:

  • Patterns contains a number of reusable patterns of stars or platforms.
  • Positions specifies where to place the patterns of stars or platforms throughout the level.

jm_level_plist

To better understand the file format, take a look at Stars/Positions/Item 0. This contains three elements telling the game to place stars in a cross pattern positioned at (160, 240).

jm_level_plist1

Now look at Patterns/Cross and you’ll see this pattern is made up of five items, including (x, y) coordinates relative to the position given in Stars/Positions and the type of star, where NORMAL=0 or SPECIAL=1.

jm_level_plist2

This is simply a convenient way of reusing patterns of stars and platforms without having to code the position of every individual object.

rrr

Loading the Level Data

To add support for loading the level from Level01.plist, open MyScene.m and add the following instance variable to the class extension in MyScene.m:

// Height at which level ends
int _endLevelY;

_endLevelY will store the height, or y-value, that the player must reach to finish the level.

Insert the following code into initWithSize:, just before the lines that instantiate and add platform:

// Load the level
NSString *levelPlist = [[NSBundle mainBundle] pathForResource: @"Level01" ofType: @"plist"];
NSDictionary *levelData = [NSDictionary dictionaryWithContentsOfFile:levelPlist];
 
// Height at which the player ends the level
_endLevelY = [levelData[@"EndY"] intValue];

This loads the data from the property list into a dictionary named levelData and stores the property list’s EndY value in _endLevelY.

Now for the stars and platforms. Begin with the platforms. In initWithSize:, replace the following lines:

// Add a platform
PlatformNode *platform = [self createPlatformAtPosition:CGPointMake(160, 320) ofType:PLATFORM_NORMAL];
[_foregroundNode addChild:platform];

With this code:

// Add the platforms
NSDictionary *platforms = levelData[@"Platforms"];
NSDictionary *platformPatterns = platforms[@"Patterns"];
NSArray *platformPositions = platforms[@"Positions"];
for (NSDictionary *platformPosition in platformPositions) {
  CGFloat patternX = [platformPosition[@"x"] floatValue];
  CGFloat patternY = [platformPosition[@"y"] floatValue];
  NSString *pattern = platformPosition[@"pattern"];
 
  // Look up the pattern
  NSArray *platformPattern = platformPatterns[pattern];
  for (NSDictionary *platformPoint in platformPattern) {
    CGFloat x = [platformPoint[@"x"] floatValue];
    CGFloat y = [platformPoint[@"y"] floatValue];
    PlatformType type = [platformPoint[@"type"] intValue];
 
    PlatformNode *platformNode = [self createPlatformAtPosition:CGPointMake(x + patternX, y + patternY)
                                                         ofType:type];
    [_foregroundNode addChild:platformNode];
  }
}

There’s a lot going on here, but it’s simple stuff. You load the Platforms dictionary from levelData and then loop through its Positions array. For each item in the array, you load the relevant pattern and instantiate PlatformNodes of the correct type at the specified (x, y) positions. You add all the platform nodes to the foreground node, where all the game objects belong.

Build and run. You’ll see a set of three platforms aligned in the scene, which is the “Triple” pattern described in Level01.plist.

16-Level01Platforms

Now do the same for the stars. Inside MyScene.m, replace the following line in initWithSize::

// Add a star
StarNode *star = [self createStarAtPosition:CGPointMake(160, 220) ofType:STAR_SPECIAL];
[_foregroundNode addChild:star];

With this code:

// Add the stars
NSDictionary *stars = levelData[@"Stars"];
NSDictionary *starPatterns = stars[@"Patterns"];
NSArray *starPositions = stars[@"Positions"];
for (NSDictionary *starPosition in starPositions) {
  CGFloat patternX = [starPosition[@"x"] floatValue];
  CGFloat patternY = [starPosition[@"y"] floatValue];
  NSString *pattern = starPosition[@"pattern"];
 
  // Look up the pattern
  NSArray *starPattern = starPatterns[pattern];
  for (NSDictionary *starPoint in starPattern) {
    CGFloat x = [starPoint[@"x"] floatValue];
    CGFloat y = [starPoint[@"y"] floatValue];
    StarType type = [starPoint[@"type"] intValue];
 
    StarNode *starNode = [self createStarAtPosition:CGPointMake(x + patternX, y + patternY) ofType:type];
    [_foregroundNode addChild:starNode];
  }
}

This is exactly what you did to create the platforms, but this time you create stars for the items in the Stars dictionary.

Build and run. This is starting to look like a real game!

17-Level01Stars

The Midground Layer

Graphically, there’s just one more thing to add to give the game a greater illusion of depth, and that’s the midground layer. This is the node that’s going to contain decorative graphics to bring the game to life.

Add the following method to MyScene.m:

- (SKNode *)createMidgroundNode
{
  // Create the node
  SKNode *midgroundNode = [SKNode node];
 
  // 1
  // Add some branches to the midground
  for (int i=0; i<10; i++) {
    NSString *spriteName;
    // 2
    int r = arc4random() % 2;
    if (r > 0) {
      spriteName = @"BranchRight";
    } else {
      spriteName = @"BranchLeft";
    }
    // 3
    SKSpriteNode *branchNode = [SKSpriteNode spriteNodeWithImageNamed:spriteName];
    branchNode.position = CGPointMake(160.0f, 500.0f * i);
    [midgroundNode addChild:branchNode];
  }
 
  // Return the completed background node
  return midgroundNode;	
}

Take a closer look at this code:

  1. You add ten branches to midgroundNode, spaced evenly throughout the level.
  2. There are two different branch images, one showing branches coming in from the left of the screen and the other from the right. Here you grab one randomly.
  3. You space the branches at 500-point intervals on the y-axis of the midground node.

Now add the midground node to your scene by inserting the following code into initWithSize:, immediately after the line that adds the background node:

// Midground
_midgroundNode = [self createMidgroundNode];
[self addChild:_midgroundNode];

Build and run. Look! It’s a branch (of sorts) and maybe some pink butterflies!

18-MidgroundNode

Note: The pink butterflies will only appear if the randomly-chosen branch is the one coming from the right side of the screen. The other branch image does not include the butterflies.

Tap to start the game and you will see the player sprite shoot up the screen. However, even as the Uber Jumper ascends, the game world remains still.

19-MidgroundNodeRun

The background, midground and foreground layers should all move with the player node to keep the player sprite in the center of the screen. You’re going to sort that out next.

Parallaxalization

No, that’s not a word! ;]

To give your game the parallax effect, you’re going to move the background, midground and foreground nodes at different rates as the player moves up and down the scene. Sprite Kit calls update: on your scene every frame, so that’s the place to implement this logic to produce smooth animation.

Open MyScene.m and add the following method:

- (void) update:(CFTimeInterval)currentTime {
  // Calculate player y offset
  if (_player.position.y > 200.0f) {
    _backgroundNode.position = CGPointMake(0.0f, -((_player.position.y - 200.0f)/10));
    _midgroundNode.position = CGPointMake(0.0f, -((_player.position.y - 200.0f)/4));
    _foregroundNode.position = CGPointMake(0.0f, -(_player.position.y - 200.0f));
  }
}

You check to make sure the player node has moved up the screen at least 200 points, because otherwise you don’t want to move the background. If so, you move the three nodes down at different speeds to produce a parallax effect:

  • You move the foreground node at the same rate as the player node, effectively keeping the player from moving any higher on the screen.
  • You move the midground node at 25% of the player node’s speed so that it appears to be farther away from the viewer.
  • You move the background node at 10% of the player node’s speed so that it appears even farther away.

Build and run, and tap to start the game. You’ll see the layers all move with the player, and the different speeds of the background and midground nodes will produce a very pleasing parallax effect.

20-Parallax

Great work! But don’t rest on your laurels yet. To get any higher in this world, you need to get your tilt on.

Moving With the Accelerometer

It’s now time to consider the accelerometer. You’ve got movement along the vertical axis working well, but what about movement along the horizontal axis? Just like in Mega Jump, the player will steer their Uber Jumper using the accelerometer.

Note: To test accelerometer, you need to run your game on a device. The iPhone Simulator does not simulate accelerometer inputs.

The accelerometer inputs are part of the Core Motion library, so at the top of MyScene.m, add the following import:

@import CoreMotion;

Then add the following lines to the MyScene class extension:

// Motion manager for accelerometer
CMMotionManager *_motionManager;
 
// Acceleration value from accelerometer
CGFloat _xAcceleration;

You’re going to use _motionManager to access the device’s accelerometer data, and you’ll store the most recently calculated acceleration value in _xAcceleration, which you’ll use later when you set the player node’s velocity along the x-axis.

To instantiate your CMMotionManager, add the following code to initWithSize:, just after the line that adds _tapToStartNode to the HUD:

// CoreMotion
_motionManager = [[CMMotionManager alloc] init];
// 1
_motionManager.accelerometerUpdateInterval = 0.2;
// 2
[_motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue]
  withHandler:^(CMAccelerometerData  *accelerometerData, NSError *error) {
    // 3
    CMAcceleration acceleration = accelerometerData.acceleration;
    // 4
    _xAcceleration = (acceleration.x * 0.75) + (_xAcceleration * 0.25);
  }];

There’s a lot going on here, so take a deeper dive:

  1. accelerometerUpdateInterval defines the number of seconds between updates from the accelerometer. A value of 0.2 produces a smooth update rate for accelerometer changes.
  2. You enable the accelerometer and provide a block of code to execute upon every accelerometer update.
  3. Inside the block, you get the acceleration details from the latest accelerometer data passed into the block.
  4. Here you calculate the player node’s x-axis acceleration. You could use the x-value directly from the accelerometer data, but you’ll get much smoother movement using a value derived from three quarters of the accelerometer’s x-axis acceleration (say that three times fast!) and one quarter of the current x-axis acceleration.

Now that you have an x-axis acceleration value, you need to use that value to set the player node’s velocity along the x-axis.

As you are directly manipulating the velocity of the player node, it’s important to let Sprite Kit handle the physics first. Sprite Kit provides a method for that very purpose called didSimulatePhysics. You should call it as soon as Sprite Kit has dealt with the game’s physics for each frame.

Add the following method to MyScene.m:

- (void) didSimulatePhysics
{
  // 1
  // Set velocity based on x-axis acceleration
  _player.physicsBody.velocity = CGVectorMake(_xAcceleration * 400.0f, _player.physicsBody.velocity.dy);
 
  // 2
  // Check x bounds
  if (_player.position.x < -20.0f) {
    _player.position = CGPointMake(340.0f, _player.position.y);
  } else if (_player.position.x > 340.0f) {
    _player.position = CGPointMake(-20.0f, _player.position.y);
  }
  return;
}

A couple of things are happening here:

  1. You change the x-axis portion of the player node’s velocity using the _xAcceleration value. You multiply it by 400.0 because the accelerometer scale does not match the physics world’s scale and so increasing it produces a more satisfying result. You leave the velocity’s y-axis value alone because the accelerometer has no effect on it.
  2. In Mega Jump, when the player leaves the screen from the left or right, they come back onscreen from the other side. You replicate that behavior here by checking the bounds of the screen and leaving a 20-point border at the edges.

Build and run on your device, and use the accelerometer to steer the player sprite as high as you can!

21-AccelerometerRun

The Scoring System

Your complete Uber Jump will have three pieces of information pertinent to the player:

  • The Current Score. Each game, the score will start at zero. The higher the player gets, the more points you’ll award toward the score. You’ll also add points for each star the player collects.
  • The High Score. Every run through the game will result in a final score. Uber Jump will save the highest of these in the app’s user defaults so that the player always knows the score to beat.
  • The Stars. While the current score will reset at the beginning of each game, the player’s stars will accumulate from game to game. In a future version of Uber Jump, you may decide to make stars the in-game currency with which users can buy upgrades and boosts. You won’t be doing that as part of this tutorial, but you’ll have the currency in case you’d like to do it on your own.

You’re going to store the current score, the high score and the number of the collected stars in a singleton class called GameState. This class will also be responsible for saving the high score and number of stars to the device so that the values persist between game launches.

Create a new Objective-C class called GameState and make it a subclass of NSObject.

22-NewClassGameState

Add the following properties and method to GameState.h:

@property (nonatomic, assign) int score;
@property (nonatomic, assign) int highScore;
@property (nonatomic, assign) int stars;
 
+ (instancetype)sharedInstance;

These three properties will provide access to the current score, the high score and the star count. The static method sharedInstance will provide access to the singleton instance of GameState.

Now add the following to GameState.m:

+ (instancetype)sharedInstance
{
  static dispatch_once_t pred = 0;
  static GameState *_sharedInstance = nil;
 
  dispatch_once( &pred, ^{
    _sharedInstance = [[super alloc] init];
  });
  return _sharedInstance;
}

This is the standard way to create a singleton object in Objective-C. It ensures that the GameState referenced by _sharedInstance is only initialized once no matter how many times you call this method. Now you can use the same object from anywhere in your code to access the current game state.

You need to provide an initialization method for GameState that sets the current score to zero and loads any existing high score and star count from the user defaults.

Add the following init method to GameState.m:

- (id) init
{
  if (self = [super init]) {
    // Init
    _score = 0;
    _highScore = 0;
    _stars = 0;
 
    // Load game state
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    id highScore = [defaults objectForKey:@"highScore"];
    if (highScore) {
      _highScore = [highScore intValue];
    }
    id stars = [defaults objectForKey:@"stars"];
    if (stars) {
      _stars = [stars intValue];
    }
  }
  return self;
}

NSUserDefaults is a simple way to persist small bits of data on the device. It’s intended for user preferences, but in this example it works well to store the high score and star count. In a real app, do not use NSUserDefaults as someone could easily tamper with the data stored there.

Note:There is a complete tutorial called “How to store your game’s data” coming out the week after this one. It will introduce you to using the Keychain, iCloud and more for storing your high scores and other game data.

To store these values, you need a method in GameState. Add the following method declaration to GameState.h:

- (void) saveState;

Now add the implementation to GameState.m:

- (void) saveState
{
  // Update highScore if the current score is greater
  _highScore = MAX(_score, _highScore);
 
  // Store in user defaults
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  [defaults setObject:[NSNumber numberWithInt:_highScore] forKey:@"highScore"];
  [defaults setObject:[NSNumber numberWithInt:_stars] forKey:@"stars"];
  [[NSUserDefaults standardUserDefaults] synchronize];
}

You now have a GameState class that synchronizes with storage on the device. Since the app will use GameState throughout, you can add the GameState.h import to the project’s precompile header file.

Locate and open UberJump-Prefix.pch in the Project Navigator. Add the following import after the imports for the UIKit and Foundation header files:

#import "GameState.h"

This gives each of your classes access to GameState without having to import its header file directly.

What good is a score if nobody knows what it is? You’ve got to show me the money!

Building the HUD

Before you start awarding points, you’re going to build a simple HUD so that the player can see their score and star count.

Your HUD will show the total number of collected stars on the top-left of the scene and the current score on the top-right of the scene. For this, you need to create two SKLabelNodes.

Add the following variable declarations to the class extension in MyScene.m:

// Labels for score and stars
SKLabelNode *_lblScore;
SKLabelNode *_lblStars;

To build the HUD, add the following code to initWithSize: in MyScene.m, just before the line that initializes _motionManager:

// Build the HUD
 
// Stars
// 1
SKSpriteNode *star = [SKSpriteNode spriteNodeWithImageNamed:@"Star"];
star.position = CGPointMake(25, self.size.height-30);
[_hudNode addChild:star];
// 2
_lblStars = [SKLabelNode labelNodeWithFontNamed:@"ChalkboardSE-Bold"];
_lblStars.fontSize = 30;
_lblStars.fontColor = [SKColor whiteColor];
_lblStars.position = CGPointMake(50, self.size.height-40);
_lblStars.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeLeft;
// 3
[_lblStars setText:[NSString stringWithFormat:@"X %d", [GameState sharedInstance].stars]];
[_hudNode addChild:_lblStars];
 
// Score
// 4
_lblScore = [SKLabelNode labelNodeWithFontNamed:@"ChalkboardSE-Bold"];
_lblScore.fontSize = 30;
_lblScore.fontColor = [SKColor whiteColor];
_lblScore.position = CGPointMake(self.size.width-20, self.size.height-40);
_lblScore.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeRight;
// 5
[_lblScore setText:@"0"];
[_hudNode addChild:_lblScore];

Take a closer look at this section of code:

  1. First you add a star graphic in the top-left corner of the scene to tell the player that the following number is the collected star count.
  2. Next to the star, you place a left-aligned SKLabelNode.
  3. You initialize the label with the number of stars from GameState.
  4. You add a right-aligned SKLabelNode in the top-right corner of the scene.
  5. You initialize that label to zero, as there is no score currently.

Build and run. You’ll see the two labels at the top of the screen.

23-HUD

The last layer of your game is complete! Now let’s have some points already!

Awarding Points

It’s finally time to award points for the player’s hard work. There are two ways to score points in Uber Jump: climbing up the scene and collecting stars.

To award points for collecting stars, simply add the following code to the bottom of collisionWithPlayer: in StarNode.m, just before the return statement:

// Award score
[GameState sharedInstance].score += (_starType == STAR_NORMAL ? 20 : 100);

That’s it! You add 20 points to the score for a normal star and 100 points for the special type.

To show this updated score, go back to didBeginContact: in MyScene.m. Recall from Part One of this tutorial that this method sets a flag named updateHUD to YES when it determines that the values displayed in the HUD need to change.

Add the following two lines of code to didBeginContact: inside the if(updateHUD) {} condition curly braces. There should be a comment there that reads TODO: Update HUD in Part 2:

[_lblStars setText:[NSString stringWithFormat:@"X %d", [GameState sharedInstance].stars]];
[_lblScore setText:[NSString stringWithFormat:@"%d", [GameState sharedInstance].score]];

Build and run, and tap to start the game. As you collect stars, watch your score increase.

24-HUDPointsFromStars

To work out when to award points for traveling up the screen, you need to store the highest point along the y-axis that the player has reached during this play-through. You’ll use this data to increase the score only when the player reaches a new high point, rather than award points constantly as the player bobs up and down the screen.

Add the following instance variable to the class extension in MyScene.m:

// Max y reached by player
int _maxPlayerY;

The player node initially starts at a y-coordinate of 80.0, so you need to initialize _maxPlayerY to 80 if you don’t want to give the player 80 points just for starting the game. ;]

Add the following line to initWithSize: in MyScene.m, just after the line that sets the background color:

// Reset
_maxPlayerY = 80;

To increase the score when the player travels up the screen, go to MyScene.m. At the top of update:, add the following lines:

// New max height ?
// 1
if ((int)_player.position.y > _maxPlayerY) {
  // 2
  [GameState sharedInstance].score += (int)_player.position.y - _maxPlayerY;
  // 3
  _maxPlayerY = (int)_player.position.y;
  // 4
  [_lblScore setText:[NSString stringWithFormat:@"%d", [GameState sharedInstance].score]];
}

This deserves closer inspection:

  1. First, you check whether the player node has travelled higher than it has yet travelled in this play-through.
  2. If so, you add to the score the difference between the player node’s current y-coordinate and the max y-value.
  3. You set the new max y-value.
  4. Finally, you update the score label with the new score.

Build and run, and tap to start. As you play, your score will go up as you move higher through the level.

25-HUDPointsFromY

Now consider the star count. You need to increment it every time the player node collides with a star, so open StarNode.m and add the following code to collisionWithPlayer:, just after the line that awards the points:

// Award stars
[GameState sharedInstance].stars += (_starType == STAR_NORMAL ? 1 : 5);

That’s all that needs doing! Build and run, and tap to start. Watch the star count increase as you collect them.

26-HUDStars

As you play, you may notice that when you fall, all the game objects you passed are still in the game. “Hey!” you are surely thinking “I spent a considerable amount of time with Mega Jump, and I am sure that’s not how it was in that game!” Yes, but that’s easy to fix.

Recall that you added a method named checkForNodeRemoval: to GameObjectNode that checks whether or not to remove a node. It’s now time to call that method every frame.

Add the following code to update: in MyScene.m, just before the line that checks if the player node’s position is greater than 200:

// Remove game objects that have passed by
[_foregroundNode enumerateChildNodesWithName:@"NODE_PLATFORM" usingBlock:^(SKNode *node, BOOL *stop) {
  [((PlatformNode *)node) checkNodeRemoval:_player.position.y];
}];
[_foregroundNode enumerateChildNodesWithName:@"NODE_STAR" usingBlock:^(SKNode *node, BOOL *stop) {
  [((StarNode *)node) checkNodeRemoval:_player.position.y];
}];

Here you enumerate through the platforms in the foreground node and call checkNodeRemoval: for each one. You then do the same for each of the stars.

Build and run, and tap to start. Now when you fall, it’s nothing but empty sky!

27-RemoveOldGameNodes

Game Over!

At the end of the game, when the player falls off the bottom of the scene or climbs to the top of the level, you want to show the final score and the current high score. You’ll do it by transitioning to an end game scene.

Create a new Objective-C class called EndGameScene and make it a subclass of SKScene.

28-NewClassEndGameScene

EndGameScene will be a simple screen that shows the player’s score, their star count and the current high score. You add all the nodes in initWithSize:, so open EndGameScene.m and add the following method:

- (id) initWithSize:(CGSize)size
{
  if (self = [super initWithSize:size]) {
    // Stars
    SKSpriteNode *star = [SKSpriteNode spriteNodeWithImageNamed:@"Star"];
    star.position = CGPointMake(25, self.size.height-30);
    [self addChild:star];
    SKLabelNode *lblStars = [SKLabelNode labelNodeWithFontNamed:@"ChalkboardSE-Bold"];
    lblStars.fontSize = 30;
    lblStars.fontColor = [SKColor whiteColor];
    lblStars.position = CGPointMake(50, self.size.height-40);
    lblStars.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeLeft;
    [lblStars setText:[NSString stringWithFormat:@"X %d", [GameState sharedInstance].stars]];
    [self addChild:lblStars];
 
    // Score
    SKLabelNode *lblScore = [SKLabelNode labelNodeWithFontNamed:@"ChalkboardSE-Bold"];
    lblScore.fontSize = 60;
    lblScore.fontColor = [SKColor whiteColor];
    lblScore.position = CGPointMake(160, 300);
    lblScore.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter;
    [lblScore setText:[NSString stringWithFormat:@"%d", [GameState sharedInstance].score]];
    [self addChild:lblScore];
 
    // High Score
    SKLabelNode *lblHighScore = [SKLabelNode labelNodeWithFontNamed:@"ChalkboardSE-Bold"];
    lblHighScore.fontSize = 30;
    lblHighScore.fontColor = [SKColor cyanColor];
    lblHighScore.position = CGPointMake(160, 150);
    lblHighScore.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter;
    [lblHighScore setText:[NSString stringWithFormat:@"High Score: %d", [GameState sharedInstance].highScore]];
    [self addChild:lblHighScore];
 
    // Try again
    SKLabelNode *lblTryAgain = [SKLabelNode labelNodeWithFontNamed:@"ChalkboardSE-Bold"];
    lblTryAgain.fontSize = 30;
    lblTryAgain.fontColor = [SKColor whiteColor];
    lblTryAgain.position = CGPointMake(160, 50);
    lblTryAgain.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter;
    [lblTryAgain setText:@"Tap To Try Again"];
    [self addChild:lblTryAgain];
  }
  return self;
}

That’s a lot of code, but by now, after all you’ve done in this tutorial, you’ve got pwnage.

In brief, you create three labels: one each to show the star count, the final score and the high score. You populate these labels with values from the GameState singleton. You also add a label explaining to the player that they can tap the screen to play again.

To track whether or not the game is over, add the following BOOL to the class extension in MyScene.m:

// Game over dude !
BOOL _gameOver;

At the end of the game, the GameState singleton needs to save the current state and transition to the new scene. In MyScene.m, add the following import at the top:

#import "EndGameScene.h"

Now, add the following method to MyScene.m:

- (void) endGame
{
  // 1
  _gameOver = YES;
 
  // 2
  // Save stars and high score
  [[GameState sharedInstance] saveState];
 
  // 3
  SKScene *endGameScene = [[EndGameScene alloc] initWithSize:self.size];
  SKTransition *reveal = [SKTransition fadeWithDuration:0.5];
  [self.view presentScene:endGameScene transition:reveal];
}

Look at this method in detail:

  1. First you set _gameOver to YES.
  2. Then you instruct the GameState singleton to save the game state to the app’s user defaults.
  3. Finally, you instantiate an EndGameScene and transition to it by fading over a period of 0.5 seconds.

The game needs to call endGame when the player node either falls off the bottom of the screen or reaches the maximum height for the level. You’ll test for both of these triggers in update: in the main scene.

Open MyScene.m and add the following code to the end of update::

// 1
// Check if we've finished the level
if (_player.position.y > _endLevelY) {
  [self endGame];
}
 
// 2
// Check if we've fallen too far
if (_player.position.y < (_maxPlayerY - 400)) {
  [self endGame];
}

Take a look at these checks:

  1. Remember, you loaded _endLevelY from the level’s property list—it’s the y-value at which the player has finished the level.
  2. If the player node falls by more than 400 points below the max height they’ve reached, then it’s game over.

Before you can run the game to see your end game scene, you need to make sure the game doesn’t try to call endGame more than once, which might happen if update: runs again for another frame.

Add the following line to the start of update: in MyScene.m:

if (_gameOver) return;

Now, when the game calls update:, the method checks to see if the game is already over before progressing.

Build and run. Tap to start and then play the game, allowing the Uber Jumper to fall at some point. The game will transition to the end game scene.

UberJump-EndGameScene

Restarting

To restart the game from the end game scene, you need to modify EndGameScene so it transitions back to the main game scene upon a touch event.

Open EndGameScene.m and add the following import at the top:

#import "MyScene.h"

Now add the following method to handle touch events:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
  // Transition back to the Game
  SKScene *myScene = [[MyScene alloc] initWithSize:self.size];
  SKTransition *reveal = [SKTransition fadeWithDuration:0.5];
  [self.view presentScene:myScene transition:reveal];
}

This code simply transitions to a new MyScene in much the same way you transition to this scene when the app first starts.

Build and run, and tap to start. Play the game and fall to reveal the end game scene. Tap the screen and watch the game restart.

uj_bg_noresetscore

Whoops, you forgot to reset the score! Remedy that now by stopping the app and going to MyScene.m. In initWithSize:, where you reset _maxPlayerY, add the following code:

[GameState sharedInstance].score = 0;
_gameOver = NO;

This resets the score in the GameState singleton and also resets the _gameOver flag.

Build and run again. Tap to start and play the game. When you get to the end game scene, whether from top or bottom, tap to try again. This time, the score resets to zero.

uj_bg_resetscore

Now go and beat that high score! ;]

Where to Go From Here?

Congratulations, you’ve made a game like Mega Jump!

Here is a sample project with all of the code from this tutorial series.

In the 2 parts of this series you’ve covered the whole process of creating a physics based game. You learned much about how to setup collisions and how to build your game logic around detecting contacts in the game.

But you can do much more for your Uber Jump game! Open up the plist level data and think of new levels. What new shapes could you implement? You can just copy the plist source code and create any number of levels by adjusting what’s inside the level file.

Play some Mega Jump and get inspiration! Can you implement some better game feat compared to the original game?

And last but not least if you want to learn more about Sprite Kit, check out the iOS Games by Tutorials book, where you’ll learn how to make five complete games—from zombie action to car racing to shootouts in space!

In the meantime, if you have any questions or comments, please join the forum discussion below.

How to Make a Game Like Mega Jump With Sprite Kit: Part 2/2 is a post from: Ray Wenderlich

The post How to Make a Game Like Mega Jump With Sprite Kit: Part 2/2 appeared first on Ray Wenderlich.

Video Tutorial: Beginner OpenGL ES and GLKit Part 3: Shaders and the Graphics Pipeline

Special Announcement: Oculus WWDC!

$
0
0
We're happy to announce our brand new app: Oculus WWDC!

We’re happy to announce our brand new app: Oculus WWDC!

Are any of you nervous about failing to get a WWDC ticket in the < 5 seconds before the conference sells out?

Well, never fear, the Tutorial Team has got you covered! In the past six months, we have been working hard on a brand new app that will allow everyone to attend WWDC - virtually.

The new app is called Oculus WWDC, and allows you to watch WWDC presentations in realtime on your Oculus Rift, and socialize with other attendees virtually.

Keep reading to find out more about the app - and stay tuned for a special announcement at the end!

Oculus WWDC Features

The core feature of the app is to watch WWDC presentations live in full 3D. Our goal is to give you the full WWDC experience. The app includes:

  • Full 3D simulation: See the presenters in full 3D, including a lovingly crafted model of Hair Craft One.
  • Head tilt support: Turn your head upon the announcement of each new feature to see the crowd go wild.
  • Controller movement: Tour Moscone with your Xbox 360 controller – even includes rumble support as you ride the escalators!
  • Multiplayer support: Showcialize with other virtual attendees using integrated voice chat.

The best part is we have made the app completely free of charge, to thank you for reading this site. In fact, it will actually save you money, because you won’t have to buy a plane ticket or book a hotel room!

That said, we have included two optional in-app purchases for the die-hard Apple fanboys and fangirls out there:

1) Full Experience Pack: First, for just $4.99 you can purchase some optional components to simulate the full WWDC experience. This includes a virtual box lunch each day, and a “Moscone line-waiting” simulation. Between these, you will feel like you are really there.

Virtual box lunch

Virtual box lunch

Virtual box lunch - exterior view

Virtual box lunch – exterior view

Virtual line simulator

Virtual line simulator

2) Virtual Handshake. Second, for for just 99c, you can give Tim Cook a virtual handshake. There’s nothing more satisfying than thanking the man himself – in virtual person.

Virtual handshake with Tim Cook

Virtual handshake with Tim Cook

Special Announcement

Update 4/1/14: We just got a phone call from Mark Zuckerberg, who is really excited about this app. He says it fits in perfectly with Facebook’s goals of “making the world more open and connected”. So today, we are happy to announce that Facebook is acquiring raywenderlich.com for a bucket of cash!

Don’t worry, Facebook has promised to give us full independence and very little changes day-to-day at this site. Except for a few small, tiny little things.

First, we will be renaming the site. As you may have noticed in the header, henceforth we will be known as rayzuckerberg.com. Please update your bookmarks accordingly.

Hey don't judge - everybody has a price!

Hey don’t judge – everybody has a price!

Second, Mark has requested that we make a small update to Oculus WWDC in order to present a more authentic Facebook experience. Here is our mockup of what the app will look like after these minor changes.

Oculus WWDC after Facebook acquisition

Oculus WWDC after Facebook acquisition

I encourage you all to download Oculus WWDC for free so you have it ready to go in advance. If you want, you even make use of the line simulator now to reserve the best virtual seat.

Download now!

I’m proud to be a member of this community – thank you all for helping us take virtual conferences and tutorials forward and trusting us to deliver. We won’t let you down – that would be just foolish!

Special Announcement: Oculus WWDC! is a post from: Ray Wenderlich

The post Special Announcement: Oculus WWDC! appeared first on Ray Wenderlich.

Viewing all 4374 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>