iPhone Game Development - Chris Craft [99]
Note
With Bluetooth, real-world conditions may affect actual performance. Conditions such as the proximity of the two devices and the use of other Bluetooth hardware (headsets, wireless mice/keyboards, etc.) in close proximity will impact latency and packet loss. Also, some devices will perform better than others as “host” devices. An iPod touch does not have to manage extra background processes such as cell phone communications. Also, the 2G iPod touch and the iPhone 3GS have a faster CPU.
We created a small app based on P2P Chat to perform the test. Here is a short breakdown of the key pieces of the application and how it works so you will understand how we arrived at our results. First, we need a packet to round-trip for the test:
typedef struct {
int player;
int count;
double time;
} Packet;
Once the GKSession is established, a message can be sent to the peer. The following code is used to send the message:
localPacket.player = playerNumber;
localPacket.count = ++currentCount;
localPacket.time = CFAbsoluteTimeGetCurrent();
localData = [localData initWithBytes:&localPacket length:sizeof(Packet)];
[self.gameSession sendDataToAllPeers:localData
withDataMode:GKSendDataUnreliable error:&sendError];
When the peer receives a packet from a peer, it returns the package back to the sender. When the peer receives a packet that it created, measurements can be recorded. Listing 7.1 shows how this was accomplished.
Cross-Reference
To download all of the code listings in this chapter, go to www.wileydevreference.com and click the Downloads link.
Listing 7.1
The Method receiveData Will Be Called Any Time Data Is Received from a Peer
#pragma mark GKSessionDelegate
- (void) receiveData:(NSData *)data fromPeer:(NSString *)peer
inSession:(GKSession *)session context:(void *)context {
Packet packetData;
[data getBytes:& packetData length:sizeof(Packet)];
if (packetData.player == playerNumber) {
// This packet originated here
if (lastCount+1 != packetData.count) {
// This throws out missed or late packets
packetData++;
double elapsedTime = CFAbsoluteTimeGetCurrent() - packetData.time;
totalElapsedTime += elapsedTime;
NSString *remoteStatus remoteStatus = [NSString stringWithFormat:
@”Average time: %f”, totalElapsedTime / packetCount];
textView.text = remoteStatus;
lastCount = packetData.count;
}
}
else {
// This packet originated on the peer we need to return it
remotePacket = received;
remoteData = [remoteData initWithBytes:&remotePacket
length:sizeof(Packet)];
[self.gameSession sendDataToAllPeers:remoteData
withDataMode:GKSendDataUnreliable error:nil];
}
}
Tip
In peer-to-peer you are writing one app that needs to behave slightly differently on each device. It is not obvious at first how to choose the device to be the host versus the client. We use the session: didReceiveConnectionRequestFromPeer method to make that determination for us. This message is sent to only one of the two devices, which helps you decide which device does what:
- (void)session:(GKSession *)session
didReceiveConnectionRequestFromPeer:(NSString *)peerID {
// This method will only be called on one device
playerNumber = 2;
}
After running the test, we discovered that in peer-to-peer