iOS Games Tutorial for Facebook

Overview

Facebook gives people a social gaming experience on every mobile platform. Games can integrate with Facebook on iOS, Android and the web. This tutorial shows you how to implement the Facebook SDK 3.5 for iOS to add Facebook features to your game.

We’ll build on a sample game, Friend Smash, which was built in Xcode and includes native Objective-C and C++. The sample mixes Objective-C and C++, because it’s common for game developers to build their products in a cross-platform language with device-specific features in native languages. As we’re focusing on the Facebook SDK for iOS, we’ll primarily use Objective-C in this tutorial.

The game initially has no social functionality, so we’ll build out a full Facebook integration and use Facebook’s technology to give users a better experience.

To complete the tutorial, you’ll need to be familiar with Objective-C, Xcode and C++. Before you start, download and install the Facebook SDK for iOS, create your Facebook App and start a new Xcode project as described in Getting Started with the iOS SDK.

This tutorial walks through the following sections:

  1. Authenticate
  2. Personalize
  3. Invites and Requests
  4. Bragging and Feed
  5. Publish an Open Graph Story
  6. Game State Persistence

Setup

Friend Smash is open-source and available in Facebook’s Samples on GitHub. Please download and extract the sample to follow along.

Play the game

Once you build Friend Smash, run the app inside the simulator and give it a play. You’ll see a simple game where celebrity photos launch on the screen. The goal of the game is to tap the right celebrity while their picture is still visible. You can also pickup coins, which can be used to buy bomb items. By clicking the ‘drop the bomb’ button in the bottom left of the screen, you clear all celebrities on the screen. If you miss 3 celebrity pictures or tap the wrong celebrity, the game ends and you’re directed back to the title screen.

Though this is a little fun, the game would be more entertaining with social features. Ideally, you should be able to smash friend’s pictures and interact with them on Facebook. We’ll update the game to include these features in the next few steps.

Authenticate

The first stage of this process is getting the player authenticated through Facebook, so we can display their name, profile picture and friend list. We’ll update the codebase to support Facebook Login.

For the purposes of this tutorial, to keep the code clear and succinct, we’ll only create a login mechanism through Facebook. We do recommend that you provide other login forms or maintain a login-free mode for any game you create.

Import the Facebook SDK

First, be sure to follow the instructions on how to import the Facebook SDK for iOS into the Friend Smash Xcode project. Follow the guidelines under the ‘Adding SDK & framework dependencies’ header in Step 5 on the Getting Started with the iOS SDK page.

Then, open the AppDelegate.h file. Below the #import <UIKit/UIKit.h> line, remove the line:

#define NO_FACEBOOK_INTEGRATION

Replace it with this:

#import <FacebookSDK/FacebookSDK.h>

Create a session

Next, open the FacebookController.cpp file. At the top of the file, you should see three empty methods titled void FacebookController::CreateNewSession()void FacebookController::OpenSession(void (*callback)(bool)) and void FacebookController::Login(void (*callback)(bool)).

The CreateNewSession method will be called to create a new Facebook session when the game first loads. OpenSession will then be called to attempt to open the session, so that if the user has logged in previously, they will continue to be connected to Facebook. Finally, the Login method will be called when the user clicks a ‘Log in with Facebook’ button on the title screen of Friend Smash. This method will potentially open a Facebook UI to authenticate the user.

First, replace the CreateNewSession method, so that it looks like below:

voidFacebookController::CreateNewSession(){FBSession* session =[[FBSession alloc] init];[FBSession setActiveSession: session];}

This code creates a new FBSession object, which is the core object in the Facebook SDK for iOS for handling and managing a Facebook session. We then make this new session the active session.

Next, we need to make a few changes to the AppDelegate.mm file. Switch to this file and locate the

-(BOOL)application :( UIApplication*)application
            openURL :( NSURL *)url
            sourceApplication :( NSString*)sourceApplication
            annotation :( id)annotation 

method. Replace the method with the code below:

-(BOOL)application :( UIApplication*)application openURL :( NSURL *)url
  sourceApplication :( NSString*)sourceApplication annotation :( id)annotation {[FBAppCall handleOpenURL:url sourceApplication:sourceApplication fallbackHandler:^(FBAppCall*call){if(call.appLinkData && call.appLinkData.targetURL){[[NSNotificationCenter defaultCenter] postNotificationName:APP_HANDLED_URL object:call.appLinkData.targetURL];}}];return YES;}

This allows the Facebook SDK to respond to cross-app calls from the Facebook app, such as incoming URLs from requests, feed posts and Open Graph stories. We’ll cover these topics in depth later in this tutorial.

Next, locate the - (void)applicationDidBecomeActive:(UIApplication *)applicationmethod at the bottom of the file. Inside the method, add the following code:

[FBAppCall handleDidBecomeActive];

This ensures the Facebook SDK handles the situation where the app becomes suspended by the iOS (because of an app-switch into the Facebook app or otherwise) and is then reactivated.

Finally, locate the - (void)applicationWillTerminate:(UIApplication *)applicationmethod. Add in the following code to that method:

[[FBSession activeSession] close];

This ensures the Facebook Session is properly terminated when the app is closed.

Handle a login

Navigate back to FacebookController.cpp and locate the void FacebookController::OpenSession(void (*callback)(bool)) method. This will be called when the app first loads and will attempt to open an existing Facebook session, created via a previous login to Facebook. Add the code below, so the function looks as follows:

voidFacebookController::OpenSession(void(*callback)(bool)){NSArray*permissions =[[NSArray alloc] initWithObjects:@"email",nil];// Attempt to open the session. If the session is not open, show the user the Facebook login UX[FBSession openActiveSessionWithReadPermissions:permissions allowLoginUI:false completionHandler:^(FBSession*session,FBSessionState status,NSError*error){// Did something go wrong during login? I.e. did the user cancel?if(status ==FBSessionStateClosedLoginFailed|| status ==FBSessionStateClosed|| status ==FBSessionStateCreatedOpening){
            ms_bIsLoggedIn =false;
            callback(false);}else{
            ms_bIsLoggedIn =true;
            callback(true);}}];}

This code performs the following steps:

  • Create an array of permissions, which we’ll ask the user to grant. These permissions allow Friend Smash to perform certain actions on behalf of the user. Here, we’re asking for a basic read permission, and email, which is for the user’s email address. In the Facebook SDK for iOS 3.1+, you need to ask the user for ‘read’ and ‘publish’ permissions separately. If you need publish permissions, you need to make the request at an appropriate time (ex: when the user takes a positive action to publish to the graph). Publish permissions are discussed later in this guide, but for more information, see the permissions you can request..
  • Try to open the session with read permissions. This uses the Objective-C blocks metaphor, which is fully supported in the Facebook SDK for iOS 3.1. Learn more about blocks.
  • Critically, here we set the allowLoginUI to be false. This means that if the user has not previously logged in, this code will not send them into the login flow, instead it will simply complete into the block with a FBSessionStateClosed status.
  • Depending on the outcome of the session opening attempt, the game will be set into an appropriate logged-in or logged-out state. The callback function, which updates the UI accordingly will then be triggered.

Next, we need to handle the situation of the user actively choosing to login with Facebook by clicking a button on the UI. The user will expect this action to trigger the Facebook Login flow and move them from a logged-out to a logged-in state.

Locate the void FacebookController::Login(void (*callback)(bool)) method, and add the following code:

voidFacebookController::Login(void(*callback)(bool)){NSArray*permissions =[[NSArray alloc] initWithObjects:@"email",nil];// Attempt to open the session. If the session is not open, show the user the Facebook login UX[FBSession openActiveSessionWithReadPermissions:permissions allowLoginUI:true completionHandler:^(FBSession*session,FBSessionState status,NSError*error){// Did something go wrong during login? I.e. did the user cancel?if(status ==FBSessionStateClosedLoginFailed|| status ==FBSessionStateClosed|| status ==FBSessionStateCreatedOpening){// If so, just send them round the loop again[[FBSession activeSession] closeAndClearTokenInformation];[FBSession setActiveSession:nil];CreateNewSession();
            ms_bIsLoggedIn =false;
            callback(false);}else{
            ms_bIsLoggedIn =true;
            callback(true);}}];}

This code performs largely the same steps as the previous OpenSession method. We create an array of permissions, and then attempt to open a new Facebook session. In this case however, we pass aallowLoginUI value of true, which allows the Facebook SDK for iOS to trigger the Facebook login flow in the case that the user is logged-out.

If the user fails to login correctly, due to either cancelling the flow or to error, then the session is closed and a new session is created. In a full application, you may choose to handle this situation differently by alerting the user directly in the user interface.

Now the game has enabled Facebook login, it will run in a ‘social mode’, replacing the smashing target with that of a friend, rather than a celebrity. If you run the game, you will see the ‘Play’ button replaced with a button labelled ‘Login with Facebook’. Tapping this button will trigger the login code we have just written.

Run the game and tap on the login button. If you haven’t logged in before, depending on your device settings, you’ll either see the native login modal dialog box, be redirected to the Facebook App for iOS or be redirected to Facebook in Safari to complete the login flow. Assuming you created your Bundle ID and other Xcode environment settings correctly, you should be successfully signed in with Facebook and switched back to Friend Smash.

Web based Facebook login and iOS native login (iOS6 and above)

Personalize

Now we’ve successfully logged in a player, we can query Facebook to establish their name, profile picture and friend list. We haven’t done anything with this information yet though, so the game hasn’t changed. Let’s take the next step and personalize the app for the player.

Change the title screen

Once a player successfully logs in, the game executes code to customize the front menu of Friend Smash for the user. This includes displaying their first name and profile picture. In order to accomplish this, we need to request some basic information about the user from Facebook. The methodFacebookController::FetchUserDetails(void (*callback)(bool)) is executed to perform this task.

Open FacebookController.cpp and look for the empty method, void FacebookController::FetchUserDetails(void (*callback)(bool)) - add the following code to the method:

voidFacebookController::FetchUserDetails(void(*callback)(bool)){// Start the facebook request[[FBRequest requestForMe]
     startWithCompletionHandler:^(FBRequestConnection*connection,NSDictionary<FBGraphUser>*result,NSError*error){// Did everything come back okay with no errors?if(!error && result){// If so we can extract out the player's Facebook ID and first name
             ms_nsstrFirstName =[[NSString alloc] initWithString:result.first_name];
             ms_uPlayerFBID =[result.id longLongValue];

             callback(true);}else{
             callback(false);}}];}

This code performs the following steps:

  • Use the FBRequest class to make an HTTP GET request to the Open Graph for details about the logged in user. This is available at the graph endpoint http://graph.facebook.com/me
  • Start the request with a completion handler using the Objective-C blocks metaphor. Once the call is finished, the block is executed.
  • If there were no errors and the result is valid, extract the player’s unique Facebook ID from the returned result.
  • Extract the player’s first name.
  • Call the appropriate callback function to update the UI with the user’s details.
  • The ms_uPlayerFBID variable is then used to fetch the user’s profile picture, via thehttps://graph.facebook.com/USER_ID/picture?width=256&height=256 graph endpoint. The exact mechanism by which the profile picture is created as an OpenGL texture and added to the scene is beyond the scope of this tutorial, but you can inspect theSystem::TextureResource::CreateFromFBID(u64 uID, u32 uWidth, u32 uHeight)function inside TextureResource.cpp for more details.

Compile the code and launch Friend Smash. Perform a Facebook login if you haven’t already done so. The code just written should be executed and you should see the menu screen customize to show your first name and profile picture.

Change the gameplay

Tap the play button. The game should select a random person to smash from your friend list.

This change came from the following code, which is inside the GameController::StartGame(...method, inside the GameController.cpp file. (Note: This code truncated for clarity.)


if(bSocial){...[FBRequestConnection startForMyFriendsWithCompletionHandler:^(FBRequestConnection*connection, id result,NSError*error){NSArray* fetchedFriendData;if(!error && result){
            fetchedFriendData =[[NSArray alloc] initWithArray:[result objectForKey:@"data"]];NSDictionary*friendData =[fetchedFriendData objectAtIndex: arc4random()% fetchedFriendData.count];NSString*friendId =[friendData objectForKey:@"id"];
            m_friendName =[[[friendData objectForKey:@"name"] componentsSeparatedByString:@" "] objectAtIndex:0];

            m_labelFriendName.text =[NSString stringWithFormat:@"Smash %@!", m_friendName];if(m_pFriendTexture){delete m_pFriendTexture;}

            m_uFriendFBID =[friendId longLongValue];

            m_pFriendTexture =newSystem::TextureResource();
            m_pFriendTexture->CreateFromFBID(m_uFriendFBID,128,128);}}];

These steps occur when this code executes at the start of the game in social mode:

  • Create a FBRequest class to make an HTTP GET request to the Open Graph for details about the user’s friends. This is available at the graph endpointhttp://graph.facebook.com/me/friends
  • If this call returns successfully with a valid result, create an array to represent the friend list from Facebook.
  • Select a random person from the user’s friend list.
  • Create a dictionary to enumerate the friend’s properties.
  • Extract the friend’s Facebook ID and name.
  • Set the m_labelFriendName label with the instructional text: ‘Smash <Friend’s Name>!’
  • Create an OpenGL texture resource with the friend’s profile picture based on their Facebook ID.

Invites and Requests

We now have a socially-enabled game, which is more fun to play and feels more personalized. Next, let’s implement invites and challenges with requests to enable organic discovery of our app on Facebook.

Invites from friends are one of the primary ways that games can generate organic traffic and acquire new players. Now that you have implemented authentication and personalization, you can take the next step and add invites to Friend Smash.

Basic requests

Requests are one of Facebook’s primary social channels, used for direct communication between users. Let’s implement requests to let people challenge their friends in Friend Smash.

At the end of the game, you’ll see a ‘Challenge’ button on the title screen. Tapping this button executes the void FacebookController::SendRequest(const int nScore) method, which is further down in the FacebookController.cpp file.

The method is currently empty. Add this code to let users send requests:

voidFacebookController::SendRequest(constint nScore){NSMutableDictionary*params=[NSMutableDictionary dictionaryWithObjectsAndKeys:nil];[FBWebDialogs presentRequestsDialogModallyWithSession:nil
            message:[NSString stringWithFormat:@"I just smashed %d friends! Can you beat it?", nScore]
            title:@"Smashing!"
            parameters:params
            handler:^(FBWebDialogResult result, NSURL *resultURL,NSError*error){if(error){// Case A: Error launching the dialog or sending request.NSLog(@"Error sending request.");}else{if(result ==FBWebDialogResultDialogNotCompleted){// Case B: User clicked the "x" iconNSLog(@"User canceled request.");}else{NSLog(@"Request Sent.");}}}
            friendCache:nil];}

This code spawns the Facebook web dialog for Requests, passing along a pithy and interesting message, to be sent to a user’s friend, and a set of parameters, which is initially set to nil, but we’ll use later. The response from the Request Dialog is then handled and logged for debugging purposes.

Request dialog with no added parameters.

Customize the dialog

The previous code is very simple, but is somewhat limited in what it can achieve. You can pass other parameters in the ‘params’ dictionary to customize the request dialog’s behavior. We’ll run through a few specific examples, but you can see a complete list of request parameters in the docs.

Direct the request

NSMutableDictionary*params=[NSMutableDictionary dictionaryWithObjectsAndKeys:// 2. Optionally provide a 'to' param to direct the request at@"286400088",@"to",// Alinil];

If you provide a parameter with the key ‘to’ and the value as a specific user’s Facebook ID, the request dialog will be fixed to prompt the player to send a request to that user only. They won’t be able to add more friends or remove the ‘to’ suggested friend.

This use-case is appropriate when you’re implementing a turn-based game and you need to alert the other player that it’s their turn. In this scenario, you want the request to go to the specified user.

A directed request at an individual user.

Suggest friend

NSArray*suggestedFriends =@[@"286400088",@"685145706",@"596824621",@"555279551"];// 3. Suggest friends the user may want to request, could be game context specific?     NSMutableDictionary*params=[NSMutableDictionary dictionary];NSString*suggestedFriendsStr =[suggestedFriends componentsJoinedByString:@","];NSString*suggestedFriendsArrayStr =[NSString stringWithFormat:@"[%@]", suggestedFriendsStr];params[@"suggestions"]= suggestedFriendsArrayStr;

This example passes in an extra parameter with the key ‘suggestions’. The value is an array of Facebook User IDs that were defined further up the method. This creates a list of ‘suggested friends’, who appear first, in order of your specification within the array, in the list of friends in the dialog.

This is useful if you want the player to be able to pick friends to send a request to, but you have suggestions based on the context of the game. Perhaps the suggested users are players recently interacted with inside the game, or friends you know the player interacted with frequently. This is a best-practice, as it removes the requirement for the player to scroll through lots of friends looking for specific people.

A suggested group of friends.

Give more context

    SBJSON *jsonWriter =[SBJSON new];NSDictionary*challenge =[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%d", nScore],@"challenge_score",nil];NSString*challengeStr =[jsonWriter stringWithObject:challenge];NSMutableDictionary*params=[NSMutableDictionary dictionaryWithObjectsAndKeys:// 4. Provide context through the data param
    challengeStr,@"data",

Finally, you can give more data with the request using the 'data' parameter. Here, we created a 'challenge' dictionary that contains the player's last score. This becomes the target score of the challenge.

Then, then we serialize this dictionary into a string using a JSON serializer, and pass it into our dialog parameter dictionary with the key 'data'. When a user receives a request with data attached, the app polls Facebook to provide the additional data. We'll look at this more later in this tutorial, when we handle an incoming request.

Note: It is not necessary to explicitly give details about where a request originated. Facebook handles this for you and makes it available when handling the incoming request.

Frictionless requests

We touched on a scenario where users exchange requests back and forth. If this scenario is typical in your game, it can be a bad user experience to force them through the request dialog every time they want to send a request. The solution for this is frictionless requests.

Frictionless requests let users send requests to friends from an app without having to click on a pop-up confirmation dialog. When sending a request to a friend, a user can authorize the app to send subsequent requests to the same friend without another dialog. This streamlines the process of sharing with friends.

To turn on frictionless requests with the SDK, we need to add a FBFrictionlessRecipientCacheinstance to our call to FBWebDialogs presentRequestsDialogModallyWithSession:. TheFBFrictionlessRecipientCache object is used to cache details of our friend list and keep track of who we've previously sent requests to. First, let's add an instance of theFBFrictionlessRecipientCache to our FacebookController class.

Go to FacebookController.h, and add the following item as a private static member of the class:

...private:staticFBFrictionlessRecipientCache* ms_friendCache;

Now navigate to FacebookController.cpp, at the top of the file, above the first class method, our previously created CreateNewSession() method, add the following line to instantiate the recipient cache:

FBFrictionlessRecipientCache*FacebookController::ms_friendCache = NULL;

Then scroll back down to the SendRequest(const int nScore) method. Below where you define the NSMutableDictionary* params object, add the following code:

if(ms_friendCache == NULL){
    ms_friendCache =[[FBFrictionlessRecipientCache alloc] init];}[ms_friendCache prefetchAndCacheForSession:nil];

This will create the FBFrictionlessRecipientCache object, if it hasn’t already been initialised, and will prefetch and cache a list of frictionless friend recipients for the current session.

Finally, in the call to presentRequestsDialogModallyWithSession, which spawns the request dialog, add the friend cache to the final method parameter.

You should end up with code which looks like the following:

voidFacebookController::SendRequest(constint nScore){// Normally this won't be hardcoded but will be context specific, i.e. players you are in a match with, or players who recently played the game etcNSArray*suggestedFriends =[[NSArray alloc] initWithObjects:@"223400030",@"286400088",@"767670639",@"516910788",nil];SBJsonWriter*jsonWriter =[SBJsonWriternew];NSDictionary*challenge =[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%d", nScore],@"challenge_score",nil];NSString*challengeStr =[jsonWriter stringWithObject:challenge];// Create a dictionary of key/value pairs which are the parameters of the dialog// 1. No additional parameters provided - enables generic Multi-friend selectorNSMutableDictionary*params=[NSMutableDictionary dictionaryWithObjectsAndKeys:// 2. Optionally provide a 'to' param to direct the request at a specific user//@"286400088", @"to", // Ali// 3. Suggest friends the user may want to request, could be game context specific?//[suggestedFriends componentsJoinedByString:@","], @"suggestions",
                                     challengeStr,@"data",nil];if(ms_friendCache == NULL){
        ms_friendCache =[[FBFrictionlessRecipientCache alloc] init];}[ms_friendCache prefetchAndCacheForSession:nil];[FBWebDialogs presentRequestsDialogModallyWithSession:nil
                                                message:[NSString stringWithFormat:@"I just smashed %d friends! Can you beat it?", nScore]
                                                title:@"Smashing!"
                                                parameters:params
                                                handler:^(FBWebDialogResult result, NSURL *resultURL,NSError*error){if(error){// Case A: Error launching the dialog or sending request.NSLog(@"Error sending request.");}else{if(result ==FBWebDialogResultDialogNotCompleted){// Case B: User clicked the "x" iconNSLog(@"User canceled request.");}else{NSLog(@"Request Sent.");}}}
                                              friendCache:ms_friendCache];}

You’ll now see the extra checkbox in the request dialog. The behavior for managing frictionless requests is entirely handled by the Facebook SDK. Once a request is sent to a user through the UI once, subsequent sends will happen without spawning the request dialog.

Frictionless requests.

Deep linking

We’ve looked at the various methods you can use to send requests. Now let’s look at receiving them.

When a user taps on a request in the Facebook iOS app and is redirected to your game, it’s possible to process the incoming native app link to provide a contextual experience. Previously, we sent a request with an additional data parameter containing the score of the challenging player. Now, let’s add code to Friend Smash to process that incoming request, obtain the data that was sent and do something with the score.

When a user taps on the request notification in the Facebook app, the request is sent to your app by means of iOS’s internal app URL handling mechanism. This is in part, why you needed to set up a URL scheme for your app in Step 1. The request’s details are bundled by the Facebook app into a URL and then passed to your app to process.

The first step in handling an incoming request is turning on the ability for your app to detect an incoming URL from within your app delegate. This has already been taken care of within Friend Smash, but it’s worth noting what’s going on.

Open the AppDelegate.mm file and observe theapplication:openURL:sourceApplication:annotation: method. This code is called whenever the application is asked to open a URL.

First, the Facebook SDK processes the incoming URL. This is necessary the handle the case where Friend Smash is relaunched after a user logs in from the Facebook app; the SDK needs to store and process the newly authenticated user’s credentials. When the SDK detects that the incoming URL originated from the Facebook app, as a result of a user tapping on content from the app, it executes the given handler, which in turn alerts the main app logic via NSNotificationCenter. The next step is parsing the URL’s contents.

Go back to the FacebookController.cpp file and locate the void FacebookController::ProcessIncomingURL(NSURL* targetURL, void (*callback)(NSString *, NSString *)) method. This code is executed when the app receives an incoming URL. Copy and paste in the following code:

NSRange range =[targetURL.query rangeOfString:@"notif" options:NSCaseInsensitiveSearch];// If the url's query contains 'notif', we know it's coming from a notification - let's process itif(targetURL.query && range.location !=NSNotFound){// Yes the incoming URL was a notificationProcessIncomingRequest(targetURL, callback);}

An incoming URL from a request typically looks like this:

http://m.facebook.com/apps/friendsmashsample?fb_source=notification&request_ids=abc&ref=notif&app_request_type=Duser_to_user

Notice that the reference parameter is set to notif. This is specific and unique to requests, so in our code sample above, we look for this token within our incoming url string. If we find it, we then pass over to a method that will do the parsing, ProcessIncomingRequest(targetURL, callback);.

Now find the currently empty ProcessIncomingRequest(targetURL, callback);, and add the following code:

voidFacebookController::ProcessIncomingRequest(NSURL* targetURL,void(*callback)(NSString*,NSString*)){// Extract the notification idNSArray*pairs =[targetURL.query componentsSeparatedByString:@"&"];NSMutableDictionary*queryParams =[[NSMutableDictionary alloc] init];for(NSString*pair in pairs){NSArray*kv =[pair componentsSeparatedByString:@"="];NSString*val =[[kv objectAtIndex:1]
                         stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];[queryParams setObject:val forKey:[kv objectAtIndex:0]];}NSString*requestIDsString =[queryParams objectForKey:@"request_ids"];NSArray*requestIDs =[requestIDsString componentsSeparatedByString:@","];FBRequest*req =[[FBRequest alloc] initWithSession:[FBSession activeSession] graphPath:[requestIDs objectAtIndex:0]];[req startWithCompletionHandler:^(FBRequestConnection*connection, id result,NSError*error){if(!error){if([result objectForKey:@"from"]){NSString*from=[[result objectForKey:@"from"] objectForKey:@"name"];NSString*id =[[result objectForKey:@"from"] objectForKey:@"id"];

                 callback(from, id);}}}];}

This method looks rather complex, but is painless. First, the incoming “target_url” url is parsed to create a dictionary of key/values representing its query parameters.

We then pull out the Request ID by looking for the request_ids portion of the target URL. Once we have the Request ID, we create a FBRequest object with a request to the graph pathhttp://graph.facebook.com/<REQUEST_ID>, which returns the extra data for this request. When the request returns, as with several of our previous examples, we’re passed into our completion block.

The returned result looks something like this:

{
        application ={
            id =480369938658210;
            name ="Friend Smash!";namespace= friendsmashsample;};"created_time"="2012-09-10T12:26:17+0000";
        data ="{\"challenge_score\":\"2\"}";from={
            id =286400088;
            name ="Ali Parr";};
        id =416687855061262;
        message ="I just smashed 2 friends! Can you beat it?";}

As you can see, the result contains the data parameter we bundled with the request. Note that you also receive details about who created the request. We can parse this out and use it contextually. In this tutorial, we’ll start a challenge with the sending player.

Bragging and News Feed

You’ve successfully implemented requests, which will allow us to grow Friend Smash organically by allowing players to invite their friends to play the game. Next, you’ll implement bragging stories into Friend Smash. This will allow players to post a message to their Timeline and to their friends’ News Feed about Friend Smash. In this story, you’ll also include their current score as a 1-to-many challenge.

Implement Feed Dialog

Let’s use news feed to implement bragging in Friend Smash.

At the end of the game, you’ll see a button labeled ‘Brag!’ on the title screen. Tapping this button executes the method void FacebookController::SendBrag(const int nScore), which is further down in the FacebookController.cpp file. The method is currently empty. Add this code to let a user post stories to news feed:

voidFacebookController::SendBrag(constint nScore){// This function will invoke the Feed Dialog to post to a user's Timeline and News Feed// It will attemnt to use the Facebook Native Share dialog// If that's not supported we'll fall back to the web based dialog.NSString*linkURL =[NSString stringWithFormat:@"https://www.friendsmash.com/challenge_brag_%llu", ms_uPlayerFBID];NSString*pictureURL =@"http://www.friendsmash.com/images/logo_large.jpg";// Prepare the native share dialog parametersFBShareDialogParams*shareParams =[[FBShareDialogParams alloc] init];
    shareParams.link =[NSURL URLWithString:linkURL];
    shareParams.name =@"Checkout my Friend Smash greatness!";
    shareParams.caption=@"Come smash me back!";
    shareParams.picture=[NSURL URLWithString:pictureURL];
    shareParams.description =[NSString stringWithFormat:@"I just smashed %d friends! Can you beat my score?", nScore];if([FBDialogs canPresentShareDialogWithParams:shareParams]){[FBDialogs presentShareDialogWithParams:shareParams
                                    clientState:nil
                                        handler:^(FBAppCall*call,NSDictionary*results,NSError*error){if(error){NSLog(@"Error publishing story.");}elseif(results[@"completionGesture"]&&[results[@"completionGesture"] isEqualToString:@"cancel"]){NSLog(@"User canceled story publishing.");}else{NSLog(@"Story published.");}}];}else{// Prepare the web dialog parametersNSDictionary*params=@{@"name": shareParams.name,@"caption": shareParams.caption,@"description": shareParams.description,@"picture": pictureURL,@"link": linkURL
                                 };// Invoke the dialog[FBWebDialogs presentFeedDialogModallyWithSession:nil
                                               parameters:params
                                                  handler:^(FBWebDialogResult result, NSURL *resultURL,NSError*error){if(error){NSLog(@"Error publishing story.");}else{if(result ==FBWebDialogResultDialogNotCompleted){NSLog(@"User canceled story publishing.");}else{NSLog(@"Story published.");}}}];}}

This code creates a native feed dialog when possible or falls back to the web dialog.

First, we create a FBShareDialogParams instance and set its properties. We use this object to test if the native share dialog is supported on the user device. If it does, we show it using thepresentShareDialogWithParams:shareParams: function.

Otherwise, we fallback to the web version of the dialog. If you followed the requests section of this guide, the code for posting to news feed with a web dialog via the FBWebDialogs presentFeedDialogModallyWithSession: method should look similar to the code for requests. To show it, create a dictionary of parameters with a name, caption, description and picture that represents your game. Then, submit the dictionary to the FBWebDialogs method.

Deep linking

Sending

Just like requests, when a user taps a Friend Smash story in the native Facebook app, they’ll be directed to Friend Smash. In this case, it can be useful to provide some context so the user sees the same content they interacted with on Facebook.

In the example above, the game challenges friends to beat the score you achieved. It would be more interesting to your friends if the story in news feed takes them to a new game where they can smash you, the challenger, rather than another friend.

You can set this up easily with deep links. Similar to how we embedded data into requests with the data parameter, you can embed a link parameter into news feed posts. Then, you’ll parse that link when the app launches from news feed to give a more targeted game experience.

For example, in the above code we set the following URL in the link parameter:

[NSString stringWithFormat:@"https://www.friendsmash.com/challenge_brag_%d", m_uPlayerFBID]

The suffix challenge_brag_%d contains the Facebook ID of the player posting the story; this suffix will be embedded in the news feed story. Now, let’s look at how to process an incoming user from a story.

Receiving

In the section for deep-linking with requests, we processed an incoming request with some handling code in the app delegate. We also added some code in the FacebookController.cpp file to parse the data. Now, we’ll expand this parsing code to process an incoming user from a news feed story.

Go to the void FacebookController::ProcessIncomingURL(NSURL* targetURL, void (*callback)(NSString *, NSString *)) method in FacebookController.cpp. Previously, we searched the incoming URL for a "notif" token, which signified that we were processing an incoming request. Add this code to the bottom of the method to also handle an incoming story url:

    range =[targetURL.path rangeOfString:@"challenge_brag" options:NSCaseInsensitiveSearch];// If the url's path contains 'challenge_brag', we know it comes from a feed postif(targetURL.path && range.location !=NSNotFound){// Yes the incoming URL was a notificationProcessIncomingFeed(targetURL, callback);}

This code searchs the incoming url for the challenge_brag token in the news feed story. If it’s present, the incoming url comes from a news feed story, so you can let the void FacebookController::ProcessIncomingFeed(NSURL* targetURL, void (*callback)(NSString *, NSString *)) method to parse the URL.

Here’s the code to parse the incoming feed url:

voidFacebookController::ProcessIncomingFeed(NSURL* targetURL,void(*callback)(NSString*,NSString*)){// Here we process an incoming link that has launched the app via a feed post// Here is extract out the FBID component at the end of the brag, so 'challenge_brag_123456' becomes just 123456NSString* val =[[targetURL.path componentsSeparatedByString:@"challenge_brag_"] lastObject];FBRequest*req =[[FBRequest alloc] initWithSession:[FBSession activeSession] graphPath:val];// With the FBID extracted, we have enough information to go ahead and request the user's profile picture// But we also need their name, so here we make a request to http://graph.facebook.com/USER_ID to get their public profile[req startWithCompletionHandler:^(FBRequestConnection*connection, id result,NSError*error){// If the result came back okay with no errors...if(result &&!error){NSString*from=[result objectForKey:@"first_name"];

             callback(from, val);}}];}

The challenge_brag token is at the end of the URL. Use componentsSeparatedByString combined with lastObject to extract the numeric component following the token, so ‘challenge_brag_123456′ becomes 123456.

With the FBID extracted, you have enough information to request the user’s profile picture. You’ll also need their name, so make a request to http://graph.facebook.com/USER_ID to get their public profile. Use the completion handler/block mechanism to return the result. If you get a valid result and without errors, extract the challengers’s first name and start a game with them as the target.

Publish Open Graph Stories

Next, let’s look at how you can construct and publish an Open Graph story from Friend Smash.

With Open Graph, you can publish structured content about a player’s activity to their timeline. This gives your game better visibility and distribution on Facebook.

Publish scores

The Graph API for Scores is a straightforward mechanism that allows you to publish scores from a game to Facebook.

The process is simple. Each time a player achieves a score in the game, the game issues an HTTP POST request to /USER_ID/scores with a user access_token. Assuming the user has granted thepublish_actions permission, their score will post to the graph

From there, Facebook can automatically generate several interesting stories, including high score stories when the player reaches a new high score, and passing stories when the player overtakes a friend in the game.

Further down the FacebookController.cpp file, you should see a method named void FacebookController::SendScore(const int nScore). This method executes at the end of each game. Copy and paste in the following code to enable the sending of scores:

voidFacebookController::SendScore(constint nScore){// Make sure we have write permissionsRequestWritePermissions();NSMutableDictionary*params=[NSMutableDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%d", nScore],@"score",nil];NSLog(@"Fetching current score");// Get the score, and only send the updated score if it's highter[FBRequestConnection startWithGraphPath:[NSString stringWithFormat:@"%llu/scores", ms_uPlayerFBID] parameters:paramsHTTPMethod:@"GET" completionHandler:^(FBRequestConnection*connection, id result,NSError*error){if(result &&!error){int nCurrentScore =[[[[result objectForKey:@"data"] objectAtIndex:0] objectForKey:@"score"] intValue];NSLog(@"Current score is %d", nCurrentScore);if(nScore > nCurrentScore){NSLog(@"Posting new score of %d", nScore);[FBRequestConnection startWithGraphPath:[NSString stringWithFormat:@"%llu/scores", ms_uPlayerFBID] parameters:paramsHTTPMethod:@"POST" completionHandler:^(FBRequestConnection*connection, id result,NSError*error){NSLog(@"Score posted");}];}else{NSLog(@"Existing score is higher - not posting new score");}}}];}

The first thing to note here is we’re calling the method RequestWritePermissions() at the top of this block of code. Facebook requires you to request read and publish permissions from the user separately. Until this point, we haven’t needed publish permissions from the user, but as we’re about to post a score to the graph, we need to have permission to do so.

Find the void FacebookController::RequestWritePermissions() method, which should be empty. Copy and paste the following code to request write permissions for this user:

voidFacebookController::RequestWritePermissions(){// We need to request write permissions from Facebookstaticbool bHaveRequestedPublishPermissions =false;if(!bHaveRequestedPublishPermissions){NSArray*permissions =[[NSArray alloc] initWithObjects:@"publish_actions",nil];[[FBSession activeSession] requestNewPublishPermissions:permissions defaultAudience:FBSessionDefaultAudienceFriends completionHandler:^(FBSession*session,NSError*error){NSLog(@"Reauthorized with publish permissions.");}];



        bHaveRequestedPublishPermissions =true;}}

Here, we’re asking for the publish_actions permission. This is required for basic publishing to Open Graph. See a full list of available permissions.

Scroll back to the SendScore(const int nScore) method and take a look at the code.

We create a dictionary with the score that you want to post to Facebook, and then issue a request with the graph path http://graph.facebook.com/USER_ID/scores and pass in the score. Since you want to post a score, you’ll need to provide an extra parameter indicating the HTTP method the SDK should use to interact with Facebook is HTTP POST. To read a score, the endpointhttp://graph.facebook.com/APP_ID/scores with HTTP GET would do the trick.

You don’t need to do anything with the returned result; it just returns ‘true’. Leave the completion block empty.

Now Facebook will generate high score and passing stories automatically for Friend Smash. They look great on a user’s timeline and give your game more distribution. For more info, refer to the documentation on scores in the Graph API.

Publish achievements

The Graph API for Achievements works in parallel to the Graph API for Scores and enables achievement stories for players in a game.

As with scores, the publishing process is straightforward and allows Facebook to automatically generate stories with a badge that a user can show off to friends. Achievements can only be earned once per-player, so it’s worth making them occur at noteworthy moments in the game. As with the Graph API for Scores, the stories are generated automatically. When coupled with high-quality game art, these stories can really add extra visibility to your game on Facebook.

There are a couple of additional steps required to make achievements work. Let’s walk through those now.

Define an achievement

Achievements exist as Open Graph objects on the web. They follow the same Open Graph markup style as a normal OG object. For full documentation, see the Graph API for Achievements page. Let’s start by creating a first achievement, which players win after smashing 50 or more friends.

Create a new html document with this content:

<html><head><metaproperty="og:type"content="game.achievement"/><metaproperty="og:title"content="50 Score!"/><metaproperty="og:description"content="Smash 50 friends in 1 round"/><metaproperty="og:url"content="http://www.friendsmash.com/opengraph/achievement_50.html"/><metaproperty="og:image"content="http://www.friendsmash.com/opengraph/images/achievement_50.png"/><metaproperty="game:points"content="50"/><metaproperty="fb:appid"content="480369938658210"/><title>Friend Smash! - Achievement: 50 Score!</title></head><body><p>Friend Smash! - Achievement: 50 Score!</p><imgsrc="http://www.friendsmash.com/opengraph/images/achievement_50.png"/></body></html>

This contains the definition for our achievement object. Change the og:url parameter to match the location of this html file on the web. Take note of the game:points meta property tag. This tag is specific to achievements and defines the relative worth of that achievement in the game. You’re given 1000 points to distribute across all the achievements in your game, so make sure to set the weight for each achievement appropriately based on difficulty or rarity.

Once your changes are complete, save the file and upload it to the web.

You can use the Facebook Open Graph Debug Tool to ensure Facebook can read your achievement correctly. Input your achievement URL into the tool and click debug. The object should lint without errors, and your result should look like this:

Register the achievement

Once the achievement object exists on the web, register it with Facebook so it can be earned in the game by sending a HTTP POST request to the graph, as follows:

POST https://graph.facebook.com/APP_ID/achievements?achievement=http://www.friendsmash.com/opengraph/achievement_50.html&access_token=APP_ACCESS_TOKEN

Note that registering an achievement requires an App Access Token and the 1000 point limit is enforced here.

Earn the achievement

Once the achievement object is created and registered, a player can achieve it in the game. Further down in the FacebookController.cpp file, you should see a method named void FacebookController::SendAchievement(eGameAchievements achievement). This method is called in Friend Smash when an achievement should be earned (ex: when the player first scores over 50 points). Copy and paste the following code to enable the achievements to be published to Facebook:

voidFacebookController::SendAchievement(eGameAchievements achievement){// Make sure we have write permissionsRequestWritePermissions();NSArray*achievementURLs =[NSArray arrayWithObjects:@"http://www.friendsmash.com/opengraph/achievement_50.html",@"http://www.friendsmash.com/opengraph/achievement_100.html",@"http://www.friendsmash.com/opengraph/achievement_150.html",@"http://www.friendsmash.com/opengraph/achievement_200.html",@"http://www.friendsmash.com/opengraph/achievement_x3.html",nil];NSMutableDictionary*params=[NSMutableDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%@",[achievementURLs objectAtIndex:achievement]],@"achievement",nil];[FBRequestConnection startWithGraphPath:[NSString stringWithFormat:@"%llu/achievements", ms_uPlayerFBID] parameters:paramsHTTPMethod:@"POST" completionHandler:^(FBRequestConnection*connection, id result,NSError*error){}];}

This code follows the same FBRequest pattern as you’ve seen previously in this tutorial. You’re essentially performing an HTTP POST to graph.facebook.com/USER_ID/ with the user’s access token for permission, and the achievement parameter with the URL of our achievement object.

Now, once a player achieves a score of 50 or more, the achievement will publish to Facebook and a story will automatically generate.

Create custom stories

You can further build out the Open Graph implementation for Friend Smash by implementing custom objects and actions that map to specific events in the game. You can map several actions inside Friend Smash, but perhaps the most obvious one to start with is to post to the graph that a usersmashed (action) a friend (object).

Actions and objects are first defined in the Open Graph settings section of the App Dashboard. Like in the beginning of this tutorial, when you created an app on Facebook, navigate tohttps://developers.facebook.com/apps and edit the settings for the Friend Smash app you made.

In the left nav, click the ‘Open Graph’ tab. This brings you to a page with an overview of your Open Graph actions and objects. As you haven’t configured anything yet, this should be empty.

Let’s start by creating a friend object by clicking the ‘Create New Object Type’ button in the ‘Object Types’ subsection of the page. The dialog that pops up prompts you to enter the name of an object that exists in your game. You could enter ‘friend’ here, but Facebook already has a common object to represent a friend in the social graph: ‘profile’. If you click in the ‘Object Type Name’ box, you’ll see a drop-down of common objects. Select profile and click the ‘Submit’ button.

Now that you’ve defined the object, couple an action with it. Click the ‘Create New Action Type’ button. Enter that ‘People can ‘smash’ an object and click ‘Submit’.

You should see a page showing the setting attached to the ‘smash’ action. Indicate that players can smash a profile, so under the ‘Connected Object Types’ box, enter ‘profile’ to connect this action to the profile object. Click ‘Save Changes’ to create the action.

That’s all you need to get started. For more info, review the documentation on defining Open Graph actions.

Now, let’s walk through publishing the story from Friend Smash. Find the void FacebookController::SendOG(const u64 uFriendID) method within theFacebookController.cpp file and add the following code:

voidFacebookController::SendOG(const u64 uFriendID){FBRequest* newAction =[[FBRequest alloc]initForPostWithSession:[FBSession activeSession] graphPath:[NSString stringWithFormat:@"me/friendsmashsample:smash?profile=%llu", uFriendID] graphObject:nil];FBRequestConnection* conn =[[FBRequestConnection alloc] init];[conn addRequest:newAction completionHandler:^(FBRequestConnection*connection, id result,NSError*error){if(error){NSLog(@"Sending OG Story Failed: %@", result[@"id"]);return;}NSLog(@"OG action ID: %@", result[@"id"]);}];[conn start];}

Here, we’re constructing another HTTP POST request to the graph, with the endpoint defined by the app’s unique namespace. The action, friendsmashsample:smash?, is followed by the profile the user just smashed profile=%d", m_nFriendFBID.

Make sure this code executes correctly. Play and finish a new game. Then, check your activity log for something like this:

Game State Persistence

Next, let’s look at enabling cross-platform game state persistence to the game using Parse.

Up until now, the coins collected and bombs used within Friend Smash have been limited to an individual game session and device. An initial number of coins and bombs are allocated to the player at the start of the game, but any changes to those quantities were lost between play sessions and between devices.

It would be preferable to save this data to a remote storage location, so that it later could be retrieved for the user. This would provide the player with a greater sense of continued progress within the game. Furthermore, if we were to build out versions of Friend Smash for platforms other than iOS, we could have them all persist data to the same backend, allowing the player to continue with the same experience regardless of the device they are using at a given time.

Saving data to a remote server is traditionally a non-trivial task, requiring a significant investment of development time. Factors such as authentication, network connectivity, database schemas, and server reliability are just some of the many technical considerations necessary when building out a backend server component to couple your game client.

Thankfully, there are a number of ‘cloud storage’ products that have appeared recently which aim to remove the burden of these technical concerns from the developer. One such service, which this tutorial will focus on, is Parse. Parse aims to remove the complexity of building a server component, allowing the developer to focus on building a great user experience, without worrying about the supporting infrastructure.

In this section of the tutorial, we will use Parse to save user details, including the number of coins and bombs available. We will then fetch that data back from Parse, and present it seamlessly within the existing user interface.

Parse offers a number of services for developers, including Parse AnalyticsCloud Code,Parse Hosting and Parse Push. This tutorial focuses specifically on Parse Data.

Parse App Setup

As a first step, you’ll need to create an account on Parse so that we can create an application to store our data. Head to the Parse website. If you haven’t created a Parse account previously, follow the onscreen instructions to set up an account, and your first app.

If you have an existing Parse account, head to the Parse App Dashboard and click the ‘+ Create New App’ button.

On the ‘Create a New App’ screen, give the app an appropriate name, for example ‘Friend Smash’. You will be presented with several IDs and Keys. Be sure to note down the Application ID andClient Key, you’ll need these in step 2.

Next, we need to bind this Parse application with our previously created Facebook application for Friend Smash. We do this so that we can use each player’s Facebook login credentials as a unique identifier for a Parse user. On the app dashboard, you should now see your newly listed app. Click the cog icon in the upper right of its overview card to edit its settings.

On the next page, titled ‘Edit Your App’, click on the ‘User authentication’ menu item on the left hand side. Look for the ‘Facebook’ settings group on the right. Make sure the ‘Allow Facebook authentication’ option is set to ‘On’, then, enter the Facebook App ID you created for Friend Smash inbeginning of this guide. You can find your App ID at the top of your App overview page on the App Dashboard.

Once you’ve entered these settings, your Parse application setup is complete.

Next, we need to download the Parse iOS SDK and add it to our Xcode Friend Smash project.

For more information on integrating Parse into an existing iOS project, please see theExisting iOS App Quickstart Guide, available on the Parse website.

Adding Parse to Xcode

Head to the Parse SDK Downloads page and save to disk the Parse iOS SDK. Extract the archive and you should be left with a single file, Parse.framework.

Now open the Friend Smash project inside Xcode. Please use the friendsmash_social project available from the FB Samples Github Page as the basis for this tutorial. You can find this project inside the ios-friend-smash repository.

A complete implementation of the Friend Smash Parse Project is also available inside theios-friend-smash repository.
Look for the friendsmash_parse project.
Use this project as reference material as you proceed through the tutorial to ensure your implementation matches the tutorial perfectly.

Drag and drop the Parse.framework file into the ‘Frameworks’ section of your project tree inside Xcode.

You will be prompted to choose import options to add the framework. Make sure the ‘Copy items into destination group’s folder (if needed)’ is checked. Also make sure the framework is added to the active target, as illustrated below.

Great, now that the Parse SDK is included inside our project we can begin to make code changes to add Parse to the game.

Inside Xcode, navigate to AppDelegate.h. At the top of the file, just below where we previously included the Facebook SDK via

#import <FacebookSDK/FacebookSDK.h>

Add the following line:

#import <Parse/Parse.h>

to import the Parse SDK. Compile the project to ensure you have successfully added the Parse framework. If everything is in order, the project should build without error, if not, recheck the steps in this guide and ensure the Parse.framework file is listed under the ‘Frameworks’ section of your project tree.

Next, head to AppDelegate.mm, and find the following method:

-(BOOL)application :( UIApplication*)application didFinishLaunchingWithOptions :( NSDictionary*)launchOptions

Inside that method, add the following code:

[Parse setApplicationId:@"N1lOGVWXpikgvPFJxkfkd4kRTvaPNuOWe83zRoRx"
                  clientKey:@"uXn3ZPeUMZsCF1bJTUwkATTWX2jRYDxWzqyDznxp"];[PFAnalytics trackAppOpenedWithLaunchOptions:launchOptions];

Replace the Application Id and Client Key with the two values you noted down in step 1 of this guide. This code registers and verifies this iOS app instance with your Parse application.

The [PFAnalytics trackAppOpenedWithLaunchOptions:launchOptions] call is used so that you can track installs of your application using Parse Analytics. This is not covered by this guide, check out the website to learn more.

Next, further down inside the same AppDelegate.mm file, add the following method:

-(BOOL)application :( UIApplication*)application handleOpenURL :( NSURL *)url {return[PFFacebookUtils handleOpenURL:url];}

Finally, locate the openURL method, and add the following line:

-(BOOL)application :( UIApplication*)application openURL :( NSURL *)url
    sourceApplication :( NSString*)sourceApplication annotation :( id)annotation {[PFFacebookUtils handleOpenURL:url];

Build and run the game to ensure no errors were accidentally created so far. We now have the Parse SDK up and running inside Xcode.

Replace Facebook Login with Parse Login

Next, we will replace the Facebook login we implemented previously with a Parse based login. The Parse based login will wrap the Facebook login, linking a new Parse user with the existing Facebook credentials. This outcome of binding the accounts together is that you can still uniquely identify and customize the experience for the user via their Facebook ID, and can store data on behalf of that user, via Parse.

Open the file named ParseController.cpp inside the friendsmash_social project and find the following empty method:

voidParseController::Login(void(*callback)(bool))

Copy and paste in the code below, so that the method looks like the following:

voidParseController::Login(void(*callback)(bool)){[PFFacebookUtils initializeFacebook];NSArray*permissions =[[NSArray alloc] initWithObjects:@"email",nil];[PFFacebookUtils logInWithPermissions:permissions block:^(PFUser*user,NSError*error){if(!user){NSLog(@"Uh oh. The user cancelled the Facebook login.");
            callback(false);}else{NSLog(@"User logged in.");
            callback(true);}}];}

Now head to the MenuController.cpp file. At the top of the file, just below the line:

#include"FacebookController.h"

add

#include"ParseController.h"

to give this class access to our newly implemented Parse controller class. Further downMenuController.cpp, search for the call to FacebookController::Login, found inside the following method:

voidMenuController::OnTapUp(int nIndex,Math::vec2 vPosition)

Simply replace the call to FacebookController::Login(didLogIn) withParseController::Login(didLogIn).

Finally, navigate to the:

voidMenuController::OnEnter()

method. Toward the bottom of the function you will see the following code:

if(!FacebookController::IsLoggedIn()){
    m_bReturningFromGame =false;FacebookController::CreateNewSession();FacebookController::OpenSession(didLogIn);

Replace the two FacebookController calls with:

ParseController::Login(didLogIn);

That is all that is required to implement Facebook login with Parse. If you build and run the game, you should find the login implementation works in exactly the same way as the previous implementation. That is because Parse is performing the same steps to login the user to Facebook as we were previously doing. The only addition is that now the user is also bound to a unique Parse user, too.

Note – Because your Facebook login session may be already cached inside Friend Smash, it can be helpful to first remove the app from your device or simulator, to force a new login process to take place the next time the app is run.

Using the Parse Data Browser

The Parse website has a useful debugging tool that allows you to view, add and edit the objects you have saved in Parse. Let’s add a default bomb value for a user, so that we have something to retrieve from Parse.

Head back to your Parse App Dashboard. On your App’s overview card, click the Data Browser link:

The left hand panel shows you classes that have been created inside Parse. These classes couple the objects created via the client-side SDK. Notice how Parse has automatically created a User class, to contain our user information. If you click on the User class, you’ll be presented with a table containing the instances of that object stored inside Parse – in this case, the users who have logged in to Friend Smash.

Notice how the Facebook auth data, including Facebook ID has been automatically added to this class and stored with a given user. The Parse SDK makes these otherwise tedious and error-prone tasks completely effortless.

The Data Browser was introduced so that we could give the user some bombs, let’s do that now. Click the ‘Col +’ button, to add a new property type, or ‘column’ for this object.

In the dialog that pops up, enter ‘bombs’ as the column name, and set the type to ‘number’.

Click ‘Create Column’. The dialog should close and the ‘bomb’ column should be added to the far right of the ‘user’ table. You may need to scroll to the right to see the new column.

Double click on the cell for the active user row and the ‘bombs’ column, enter a test value, for example ’5′, in the screenshot above.

Getting values from Parse

Now that we have a unique user logged in to both Parse and Facebook, and have manually given them an initial bomb value for testing via the Data Browser, we are ready to programmatically retrieve the items available to this player from Parse. As we are now retrieving these values directly from Parse, we no longer need to allocate the player initial ‘seed’ values of either bombs or coins.

Open MenuController.cpp and search for the initialisation of ms_uBombs and ms_uCoins toward the top of the file. Specifically, look for:

u32 MenuController::ms_uBombs =5;
u32 MenuController::ms_uCoins =20;

Replace both values with ’0′. We want our user’s bomb and coin count to come from Parse, not hard-coded seed values. We now need to write the code to fetch this value from Parse. Open theParseController.cpp file and search for the method:

voidParseController::GetProperty(NSString*property,void(*callback)(u32))

This method takes in a property value, which is the named property field attached to this Parse user. In the previous step, we created a property named bombs, to store the number of bombs and coins available to this user. In the next step, we will programmatically create a property called coins, for saving the number of coin the user has earned.

Parse is a schema-less storage system, meaning there is no need to predefine a set of properties to attach to a user. This gives Parse a great deal of flexibility and power, and allows the data which you store within Parse to freely expand as your game grows in complexity.

Replace the ParseController::GetProperty method with the code below:

voidParseController::GetProperty(NSString*property,void(*callback)(NSString*, u32)){PFUser*currentUser =[PFUser currentUser];
    u32 uValue =[[currentUser objectForKey:property] intValue];
    callback(property, uValue);}

This code requests the given property from our currently logged in user. After Parse returns the data, the provided callback function is invoked to update the UI as appropriate.

Now the code to query Parse and fetch for a given property of the user is implemented, we need to trigger it at an appropriate time to update our bomb and coin count.

In MenuController.cpp look for the method named DidChangeFBLoginState. This method is called on the successful completion of a user login. Inside the method you will see the following code:

if(bLoggedIn){
    m_pLoginButtonSprite->SetDraw(false);#ifndef NO_FACEBOOK_INTEGRATION
    FacebookController::FetchUserDetails(didFetchUserDetails);#endif

Right below the #endif line, add the following code:

if(!m_bReturningFromGame){ParseController::GetProperty(@"bombs", didFetchPropertyFromParse);ParseController::GetProperty(@"coins", didFetchPropertyFromParse);}

This will trigger the fetch of these properties from Parse, and will call thedidFetchPropertyFromParse callback method upon completion. Next let’s add to thedidFetchPropertyFromParse method to update our UI.

Scroll down MenuController.cpp until you find the empty method:

voidMenuController::DidFetchPropertyFromParse(NSString*property, u32 uValue)

Add the following code:

voidMenuController::DidFetchPropertyFromParse(NSString*property, u32 uValue){if([property isEqualToString:@"bombs"]){
        ms_uBombs = uValue;
        m_labelBombs.text =[NSString stringWithFormat:@"%d", ms_uBombs];}elseif([property isEqualToString:@"coins"]){
        ms_uCoins = uValue;
        m_labelCoins.text =[NSString stringWithFormat:@"%d", ms_uCoins];}}

The code above should be fairly self-explanatory. Depending on the property we are updating, bombs or coins, we update the player’s inventory to the value retrieved from Parse, and update the associated UI elements to reflect the change.

Compile and run the game. The game should query Parse for the requested bombs and lives values, and present them on the menu screen. Try break-pointing the flow to watch the query happen and then return.

Game loaded, Parse fetch not yet complete.

You should see the new bomb value be fetched correctly and displayed in the Friend Smash UI. However the coin value remains at 0. This is because, while we are successfully retrieving the bomb value from Parse, we never saved a coin value. Therefore, Parse doesn’t have any value to return to us for coins, and so the default value of 0 remains. We will learn how to save data to Parse in step 6 of this guide.

Parse fetch complete.

Now the data we added to Parse is being successfully retrieved and presented inside the Friend Smash UI. So far, we only made this work for bombs. We could repeat these steps for coins, by adding them via the Data Browser in the same way. However, it’s inflexible to use the Data Browser every time we wish to make a change to our stored objects. It would be much more convenient to make the change programmatically. This is covered below.

Saving values to Parse

After the user has completed a game, the values of their coins and bombs will likely have changed. The user’s coin count is likely to have incremented, as you can collect coins in-game, whereas the user’s bomb count has likely decremented, as they’ve used bombs during the game. The end of the game is a sensible place for us to save these changes to Parse, ensuring the data stored in Parse is always in sync with the values we are using locally on the client.

Navigate to MenuController.cpp and search for the following method:

voidMenuController::ShowEndGame(NSString* friendName, u32 uScore, u32 uCoinsWon, u32 uBombsRemaining)

This is called by the GameController at the end of the game with parameters defining, amongst other things, the number of coins the player won in this round, and the number of bombs they have remaining. At the bottom of the function find the following code:

#ifndef NO_FACEBOOK_INTEGRATION

    m_pChallengeButtonSprite->SetDraw(true);
    m_pBragButtonSprite->SetDraw(true);FacebookController::SendScore(uScore);#endif

Directly underneath the #endif statement, add the following lines:

ParseController::SetProperty(@"bombs", ms_uBombs, didSavePropertyToParse);ParseController::SetProperty(@"coins", ms_uCoins, didSavePropertyToParse);

Next, we need to implement the ParseController::SetProperty method. Head toParseController.cpp and find the definition:

voidParseController::SetProperty(NSString*property, u32 uValue)

Replace it with the following code:

voidParseController::SetProperty(NSString*property, u32 uValue,void(*callback)(NSString*,bool)){NSNumber*val =[NSNumber numberWithInt:uValue];[[PFUser currentUser] setObject:val forKey:property];[[PFUser currentUser] saveInBackgroundWithBlock:^(BOOL succeeded,NSError*error){
        callback(property, succeeded);}];}

Here we set the appropriate key/value pair for the property we are saving, either coins or bombs, then invoke saveInBackgroundWithBlock. Note that we choose saveInBackgroundWithBlock here rather than just a straightforward save, which tells Parse to asynchronously handle transmitting this data to the server. Once the block completes, the callback function provided will be triggered, which simply outputs the result of the save to the log. In a full application, you might choose to implement behaviour to better handle a failed save state.

Run the game, play a couple of rounds and win some coins.

Now, head back to the Parse Data Browser. Refresh the Users table and look at the columns on the far right.

Notice that Parse has automatically created a new column to store our coins. We didn’t need to manually create this column, define a type or name it. It was created automatically when the coinsvalue was added to the user in our code. In addition, the value stored should match the current coin count of the user on the client.

Finishing Up

Congratulations, you have successfully configured and implemented your first Parse application. Having replaced Facebook Login with the simple and efficient Parse Login wrapper, we have learnt how to save and retrieve values from Parse Data. This serves as a demonstration of how little code is required to implement a fully asynchronous, cross platform, robust and efficient data-storage layer into your game.

We have only scratched the surface of what Parse can do. Other major features of Parse include:

  • Background Jobs – For the scheduling of backend tasks, so that you can perform maintenance tasks automatically at a given cadence.
  • Parse Analytics – An easy way to track any data-point in your app in real-time.
  • Parse Push – For simple push notification delivery to mobile.
  • Cloud Code – Run custom code in the cloud, no more need for traditional servers.

For more information on these services and more, checkout the Parse website.

In addition to iOS, Parse supports all major platforms including Android, Windows Phone, OSX, Windows, Javascript and Unity. See the Parse Quickstart Guides to get started on these platforms.

Check the Facebook Samples GitHub account for more updates to Friend Smash.

Next steps

Congratulations! You’ve added a range of Facebook features to a simple game, making it more interesting and engaging. As a next step, consider adding more achievements or Open Graph objects to Friend Smash to build its presence on Facebook, or try introducing new gameplay elements, storing the player’s progress in Parse.

Be sure to visit the Facebook Samples GitHub account for more updates to Friend Smash.

For info about games for the web, check out the Canvas Games Tutorial. For Android, try the Android Games Tutorial. Finally, be sure to browse the Games Developer Center for detailed guides to all Facebook’s gaming technologies.