Presented at SCREENS 2013 in Toronto.
Details at fitc.ca/screens
How to Create an Amazing Multi-Player/Multi-Device Experience for iOS Devices
With the increasing sophistication of smartphone devices, people are looking for socially connected and interactive mobile gaming experiences. People want to use their own mobile phone or device to challenge and play games with people around them, and not have to crowd around one device to enjoy the experience.
What does it take to get 15,000 people to download your multi-phone/multi-player app in 15 days? In this session we will share our secrets, crack open the code, and talk about what makes a great multi-player/multi-phone experience. When you leave the session, you’ll have the tools you need to create a great multi-player/multi-device experience.
The Ultimate Guide to Choosing WordPress Pros and Cons
15,000 downloads in 15 days with David Neumann and Thomas Ang
1. Thomas Ang, Mad Hatter Technologies
David Neumann, TVO
FITC Screens 2013 | Friday October 4, 2013
15,000 DOWNLOADS IN 15 DAYS
2. 1. Solid understanding of multi-device development for iOS
2. 4 concepts for creating an engaging experience
WHAT YOU WILL WALK AWAY WITH
3. 1. TVO’s IdeaShaker Innovation Lab
2. Intro the Ping Pong App
3. 4 engagement concepts
4. Mad Hatter Technology
5. Under the hood of the Ping Pong App
6. Q/A
THE AGENDA
4. TVO’s IdeaShaker Lab
TVO’s IdeaShaker team explores
emerging digital trends that have
“disruptive” potential and
approaches all projects through
the lens of how technology can
impact and enhance TVO’s
educational resources for
children, current affairs content
and other TVO content.
“
“
6. Ping Pong App
One of the few multi-device apps in the store
Featured by Apple in January 2013
Over 15,000 downloads in 15 days
Non-branded version developed for international
markets
Built to support the North American premiere of
the documentary Ping Pong: Never Too Old For
Gold
Overview
11. IdeaShaker + Mad Hatter
• Prototyped in both Android and iOS - > proof of concept
• Due to hard deadline had to bring in an awesome team to help execute the project
Working together
12. WHO IS ?
Mad Hatter Technology specializes
in marketing & communications
technology.
Team of specialists in a variety of
things:
-Digital design
-Web dev
-Mobile dev
-Social media
Strategy is our means.
Creativity is our craft.
Technology is our passion.
“
“
13. WHAT IS UP TO?
• TVO
• Ivanhoe Cambridge
• Balsillie School of International Affairs
• Centre for International Governance Innovation
• Alternatives Journal
• The Regional of Waterloo
• University of Waterloo
• University of Ontario
• Waterloo Regional Police Services
• Thunder Bay Police Services
15. Game Dev BasicsSimplified game loop for single player
#define LOOP_INTERVAL 0.033f
[NSTimer scheduledTimerWithTimeInterval:LOOP_INTERVAL target:self selector:@selector(gameLoop)
userInfo:nil repeats:YES];
- (void)gameLoop{
switch(gameState){
case kStateGameServe:
//if recent motion data tells us swing gesture was made
//go to Waiting state
break;
case kStateGameWaiting:
//Calculate and display AI player's response
//go to Return state
break;
16. Game Dev BasicsSimplified game loop for single player
case kStateGameReturn:
//if we've taken too long to return the shot
//rally is over: give AI player a point, go into appropriate Serve or Return state
//else if recent motion data tells us swing gesture was made
//if it was a bad swing
//rally is over: give AI player a point, go into appropriate Serve or Return state
//else go to Waiting state
break;
default:
break;
}
}
17. Pairing
//This was built foriOS 6
//Things have changed in iOS 7
GKPeerPickerController* picker;
picker = [[GKPeerPickerController alloc] init];
picker.delegate = self;
[picker show];
18. Pairing
- (void)peerPickerController:(GKPeerPickerController *)picker didConnectPeer:(NSString *)peerID toSession:
(GKSession *)session
//store info from session that we’ll need, like opponent’s ID
// Make sure we have a reference to the game session and it is set up to receive data
// Done with the Peer Picker so dismiss it.
// startGame
-(void)peerPickerControllerDidCancel:(GKPeerPickerController *)picker
//do any cleanup required and send us back to menu
// No need to implement -peerPickerController:didSelectConnectionType: delegate method since this app does not
//support multiple connection types.
- (GKSession *)peerPickerController:(GKPeerPickerController *)picker sessionForConnectionType:
(GKPeerPickerConnectionType)type
//init and return a GKSession that holds a game session ID and my display name sessionMode is
//GKSessionModePeer
GKPeerPickerControllerDelegate
20. 2 Player Logic
Game loop for two player
- (void)gameLoop{
switch (networkState) {
case kStateNetworkMatching:
break;
case kStateNetworkPlaying:
switch(gameState){
case kStateGameSyncServe:
case kStateGameSyncReturn:
//if phones have been pointing at each other for long enough
//save current phone direction
//if we’re in SyncServe go to Serve state
//if we’re in SyncReturn go to Waiting state
// send SYNC_SUCCESS to other phone with direction
//else send GESTURE_SYNC with direction
break;
21. 2 Player Logic
case kStateGameServe:
//if recent motion data tells us swing gesture was made
//if phone ended up pointing away from other player
//rally is over: give out points, go into appropriate Serve or Return state send HIT_FAIL message
//else go to Waiting state, display random arrow, send HIT_SUCCESS with orientation of arrow
break;
case kStateGameWaiting:
//make sure the arrow is still pointing the right way even if phone orientation changes
break;
case kStateGameReturn:
//if we've taken too long to return the shot
//rally is over: give out points, go into appropriate Serve or Return state send HIT_FAIL message
//else if recent motion data tells us swing gesture was made
//if phone ended up pointing away from other player or had wrong orientation
//rally is over: give out points, go into appropriate Serve or Return state send HIT_FAIL message
//else go to Waiting state, display random arrow, send HIT_SUCCESS with orientation of arrow
break;
22. 2 Player Logic
// once every 8 updates check if we have a recent heartbeat from the other player, and
send a //heartbeat packet with current state
//if the last heartbeat is too old go to NetworkReconnect state
break;
case kStateNetworkReconnect:
// we have lost a heartbeat for too long, so pause game and notify user while we wait for
next //heartbeat or session disconnect.
break;
}
23. Sending Data
typedef enum {
NETWORK_ACK, // no packet
NETWORK_PLAYER_INFO,
NETWORK_PASS_SERVE, //let the other device know that its player serves first
NETWORK_GESTURE_SYNC, //packets we send when syncing device directions
NETWORK_SYNC_SUCCESS,
NETWORK_HIT_SUCCESS, // the result of a swing
NETWORK_HIT_FAIL,
NETWORK_WIN,
NETWORK_HEARTBEAT
} PacketCode;
24. Sending Data
- (void)sendNetworkPacket:(GKSession *)session packetID:(PacketCode)packetID withData:(void *)data ofLength:
(int)length reliable:(BOOL)reliable
static unsigned char networkPacket[kMaxPacketSize];
const unsigned int packetHeaderSize = 2 * sizeof(int); // we have two "ints" for our header
if(length < (kMaxPacketSize - packetHeaderSize)) { // make sure packet isn’t bigger than buffer
int *pIntData = (int *)&networkPacket[0];
pIntData[0] = gamePacketNumber++; // header info
pIntData[1] = packetID;
memcpy( &networkPacket[packetHeaderSize], data, length ); // copy data in after the header
NSData *packet = [NSData dataWithBytes: networkPacket length:
(length+packetHeaderSize)];
if(reliable== YES) {
[session sendData:packet toPeers:[NSArray arrayWithObject:gamePeerId]
withDataMode:GKSendDataReliable error:nil];
} else {
[session sendData:packet toPeers:[NSArray arrayWithObject:gamePeerId]
withDataMode:GKSendDataUnreliable error:nil];}
25. Receiving Data
- (void)receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context
//unpack our data into local variables, make sure they arrive in order, etc.
switch( packetID ) {
case NETWORK_PLAYER_INFO:
//save whatever opponent info you need
//coin toss to see who serves first (device with smaller ID does this)
//If we're not serving first send PASS_SERVE message
break;
case NETWORK_PASS_SERVE:
//set our state to SyncServe (the default is SyncReturn)
break;
case NETWORK_GESTURE_SYNC:
//if devices are not pointing in opposite directions restart timer
//else if devices are not pointing horizontally restart timer
//else let players know to continue holding that position
break;
26. Receiving Data
case NETWORK_SYNC_SUCCESS:
//save the successful sync direction and go to Serve or Waiting state
break;
case NETWORK_HIT_SUCCESS:
//store orientation we have to match and go to Return state
break;
case NETWORK_HIT_FAIL:
//increment our score
//if we won send NETWORK_WIN else figure out who serves next and go to appropriate state
break;
case NETWORK_WIN:
//update stats, etc.
break;
case NETWORK_HEARTBEAT:
// update our record of most recent heartbeat
// if we were trying to reconnect, set the state back to multiplayer as the peer is back
break;
27. Syncing Directions
CMDeviceMotion has a CMAttitude, which has a CMQuaternion
There’s more information than we want here. We just want a direction
vector representing the normal of plane of device screen.
Apply each phone’s rotation (encoded by quaternion) to an arbitrary
vector and compare the resulting vectors.
Let v = [0, 0, 0, 1], and q is our quaternion
v´ = q v q-1
if the two resulting v´ vectors are roughly opposite, we’re good
28. Detecting Swing Motion
Check that userAcceleration exceeds threshold
Check gravity to see that phone is mostly on its side
Check that rotation in all three axes is small
29. Dealing With Rejection
We found that your app exhibited one or more bugs, when
reviewed on the iPhone 5 and the iPad (3rd Gen) running iOS
6.0.1, on both Wi-Fi and cellular networks, which is not in
compliance with the App Store Review Guidelines.
The steps to reproduce are:
1) Launch the application on two devices
2) Tap the "Play" button on both devices
3) Connect the devices
The application hangs at a blue screen and no additional
content is loaded.
30. Dealing With Rejection
We've been rejected twice for bugs found when the two phones are really close to each other at the start of
the game. We found the cause of these bugs to be interference to the Bluetooth antenna and the
magnetometer, which arises when the two phones are close together in certain positions. While we have
introduced new code to ensure these failures are handled gracefully from a user's perspective, it would still be
best if you test this app as it is intended to be used: each phone held by a different player, standing a few feet
to a few yards apart. Thanks, and enjoy!
34. BUT COME SAY HELLO!
Thomas Ang - @madhattermobile
David Neumann - @everyoneminus1
Editor's Notes
- Has been around for about 5 years Internal foresight and research department
a history of being recognized by the industry for our great educational apps DocStudio App – featured in Apple Store TVO On Demand – featured in Google Play Store Ping Pong – featured in Apple Store Caterpillar Count for Leap Motion – featured as one of the best educational apps for back to school Hurricane Maker – multi-player educational installation for WGSI
Going beyond just how to get featured, let’s look at how to create an engaging experience. At the heart, themes of staying active and being social at any age is a key message
Going beyond just how to get featured, let’s look at how to create an engaging experience. At the heart, themes of staying active and being social at any age is a key message
Our main themes that we wanted to stretch across all narratives were: being active and being social. For us, transforming your cell phone into a ping pong paddle and creating a multi-device experience achieved this
For most users, a multi-device iOS game that changes your phone into part of the physical game is a brand new concept. Wrapping it in something simple and familiar like Ping Pong breaks down some of the hesitation people have to try it
In researching our Ping Pong idea we found another developer had done a ping pong app. We took a look at it and found areas we believed could be done better, and we did them. Most notable, gameification. We felt that the app didn’t give the user a reason to play for more than 1-2 minutes. We added colours and arrows, increasing frequency and points to turn a gimmicky app into an engaging experience
In researching our Ping Pong idea we found another developer had done a ping pong app. We took a look at it and found areas we believed could be done better, and we did them. Most notable, gameification. We felt that the app didn’t give the user a reason to play for more than 1-2 minutes. We added colours and arrows, increasing frequency and points to turn a gimmicky app into an engaging experience