15,000 downloads in 15 days with david neumann and thomas ang

34
Thomas Ang, Mad Hatter Technologies David Neumann, TVO FITC Screens 2013 | Friday October 4, 2013 15,000 DOWNLOADS IN 15 DAYS

Upload: fitc

Post on 10-May-2015

999 views

Category:

Technology


1 download

DESCRIPTION

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.

TRANSCRIPT

Page 1: 15,000 downloads in 15 days with David Neumann and Thomas Ang

Thomas Ang, Mad Hatter Technologies

David Neumann, TVO

FITC Screens 2013 | Friday October 4, 2013

15,000 DOWNLOADS IN 15 DAYS

Page 2: 15,000 downloads in 15 days with David Neumann and Thomas Ang

1. Solid understanding of multi-device development for iOS2. 4 concepts for creating an engaging experience

WHAT YOU WILL WALK AWAY WITH

Page 3: 15,000 downloads in 15 days with David Neumann and Thomas Ang

1. TVO’s IdeaShaker Innovation Lab2. Intro the Ping Pong App3. 4 engagement concepts4. Mad Hatter Technology5. Under the hood of the Ping Pong App6. Q/A

THE AGENDA

Page 4: 15,000 downloads in 15 days with David Neumann and Thomas Ang

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.

““

Page 5: 15,000 downloads in 15 days with David Neumann and Thomas Ang

IdeaShaker Portfolio

Page 6: 15,000 downloads in 15 days with David Neumann and Thomas Ang

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

Page 7: 15,000 downloads in 15 days with David Neumann and Thomas Ang

Engaging Experience

Understand the underlying themes that can be woven through your entire cross-media narrative

““

Concept 1

Page 8: 15,000 downloads in 15 days with David Neumann and Thomas Ang

Engaging Experience

Find the technologies that can deliver on your themes. Transmedia is great when done right.

““

Concept 2

Page 9: 15,000 downloads in 15 days with David Neumann and Thomas Ang

Engaging Experience

When packaging a brand new concept for a user, make sure you wrap it up in something they are familiar with.

““

Concept 3

Page 10: 15,000 downloads in 15 days with David Neumann and Thomas Ang

Engaging Experience

Almost everything has been done before. Do it better.

““

Concept 4

Page 11: 15,000 downloads in 15 days with David Neumann and Thomas Ang

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

Page 12: 15,000 downloads in 15 days with David Neumann and Thomas Ang

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.

““

Page 13: 15,000 downloads in 15 days with David Neumann and Thomas Ang

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

Page 14: 15,000 downloads in 15 days with David Neumann and Thomas Ang

Game Dev BasicsStates for single player

Page 15: 15,000 downloads in 15 days with David Neumann and Thomas Ang

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;

Page 16: 15,000 downloads in 15 days with David Neumann and Thomas Ang

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;

}

}

Page 17: 15,000 downloads in 15 days with David Neumann and Thomas Ang

Pairing//This was built foriOS 6

//Things have changed in iOS 7

GKPeerPickerController* picker;

picker = [[GKPeerPickerController alloc] init];

picker.delegate = self;

[picker show];

Page 18: 15,000 downloads in 15 days with David Neumann and Thomas Ang

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

Page 19: 15,000 downloads in 15 days with David Neumann and Thomas Ang

2 Player LogicStates for two player

Page 20: 15,000 downloads in 15 days with David Neumann and Thomas Ang

2 Player LogicGame 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;

Page 21: 15,000 downloads in 15 days with David Neumann and Thomas Ang

2 Player Logiccase 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;

Page 22: 15,000 downloads in 15 days with David Neumann and Thomas Ang

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;

}

Page 23: 15,000 downloads in 15 days with David Neumann and Thomas Ang

Sending Datatypedef 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;

Page 24: 15,000 downloads in 15 days with David Neumann and Thomas Ang

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];}

Page 25: 15,000 downloads in 15 days with David Neumann and Thomas Ang

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;

Page 26: 15,000 downloads in 15 days with David Neumann and Thomas Ang

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;

Page 27: 15,000 downloads in 15 days with David Neumann and Thomas Ang

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

Page 28: 15,000 downloads in 15 days with David Neumann and Thomas Ang

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

Page 29: 15,000 downloads in 15 days with David Neumann and Thomas Ang

Dealing With RejectionWe 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.

Page 30: 15,000 downloads in 15 days with David Neumann and Thomas Ang

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!

Page 31: 15,000 downloads in 15 days with David Neumann and Thomas Ang

Featured!

Page 32: 15,000 downloads in 15 days with David Neumann and Thomas Ang

THANK YOU!

Page 33: 15,000 downloads in 15 days with David Neumann and Thomas Ang

GOOD BYE!

Page 34: 15,000 downloads in 15 days with David Neumann and Thomas Ang

BUT COME SAY HELLO!Thomas Ang - @madhattermobileDavid Neumann - @everyoneminus1