申し訳ありませんが、これには多くのネットワークコーディングがthis part of a multiplayer tutorialから発生しています。GKSessionとsendDataToAllPeersの問題:withDataMode:エラー:
基本的に、上記のリンク先のチュートリアルのとおり、GameKitを使用してマルチプレイヤーゲームを実装しようとしています。私は必要なネットワークコーディングをすべて入れて、それを多かれ少なかれ理解していますが、メソッドコールの行に沿ってどこかにぶつかってしまいました。基本的には、1台のデバイスがホストとして機能し、残りのデバイスがクライアントとして機能するという設定です。私は接続が確立されているホストとクライアントのための2つの別々のUIViewcontroller
を持っています。
これで、接続は確立されますが、クライアントではなく接続を認識するのはホストだけです。問題はここにある:
- (void)sendPacketToAllClients:(Packet *)packet
{
[_players enumerateKeysAndObjectsUsingBlock:^(id key, Player *obj, BOOL *stop)
{
obj.receivedResponse = [_session.peerID isEqualToString:obj.peerID];
}];
GKSendDataMode dataMode = GKSendDataReliable;
NSData *data = [packet data];
NSError *error;
if (![_session sendDataToAllPeers:data withDataMode:dataMode error:&error])
{
NSLog(@"Error sending data to clients: %@", error);
}
}
これは、実際のゲームが実装されますGameMultiplayer
、で実装されています。この方法は、ホストが接続要求を受信して接続できることを示すデータパケットを各クライアントに送信することです。 [_session sendDataToAllPeers:data withDataMode:dataMode error:&error]
が(if
文の法)と呼ばれた後に、このメソッドがトリガーされることになっている:
- (void)receiveData:(NSData *)data fromPeer:(NSString *)peerID inSession:(GKSession *)session context:(void *)context
{
#ifdef DEBUG
NSLog(@"Game: receive data from peer: %@, data: %@, length: %d", peerID, data, [data length]);
#endif
Packet *packet = [Packet packetWithData:data];
if (packet == nil)
{
NSLog(@"Invalid packet: %@", data);
return;
}
Player *player = [self playerWithPeerID:peerID];
if (player != nil)
{
player.receivedResponse = YES; // this is the new bit
}
if (self.isServer)
[self serverReceivedPacket:packet fromPlayer:player];
else
[self clientReceivedPacket:packet];
}
この方法は、(hereある)私は上記のリンクチュートリアルの次の部分であるとすることになっていますホストがすべてのクライアントに送信するパケットを受信し、このネットワークチェーン内の次のメソッドを実装します。しかし、このメソッドは決して呼び出されません。デバッグブレークポイントは起動されず、コンソールには何も表示されません。
多くのソース資料を提供する必要があるのですが、すでに実装されているネットワークコーディングが多いので、人々が見たいものにしておきたいと思います。また、[_session setDataReceiveHandler:self withContext:nil]
と_session.delegate = self
は、GameMultiplayer
で呼び出される別の方法で書かれているので、問題はありません。誰でも私が修正する必要があることを知っていますか?
EDIT:要求されたようGKSessionが初期化される場合には、ここにある:
@property (nonatomic, strong, readonly) GKSession *session; //This is done in the header file
@synthesize session = _session; //This is done in the main file
- (void)startAcceptingConnectionsForSessionID:(NSString *)sessionID
{
if (_serverState == ServerStateIdle)
{
_serverState = ServerStateAcceptingConnections;
_connectedClients = [NSMutableArray arrayWithCapacity:self.maxClients];
_session = [[GKSession alloc] initWithSessionID:sessionID displayName:nil sessionMode:GKSessionModeServer];
_session.delegate = self;
_session.available = YES;
}
}
セッションがホストビューコントローラで使用されているMatchmakingServer
、中に初期化されます。セッションはその後、アプリケーションのメインビューコントローラに渡され、次にGameMultiplayer
が初期化され、GKSessionがそのアプリケーションに送信されます。
- (IBAction)startAction:(id)sender
{
if (_matchmakingServer != nil && [_matchmakingServer connectedClientCount] > 0)
{
NSString *name = [self.nameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([name length] == 0)
name = _matchmakingServer.session.displayName;
[_matchmakingServer stopAcceptingConnections];
[self.delegate hostViewController:self startGameWithSession:_matchmakingServer.session playerName:name clients:_matchmakingServer.connectedClients];
}
}
し、メインビューコントローラは、ここでそのメソッド呼び出しを処理します:ホストビューコントローラは、メインビューコントローラに送信ところです
- (void)hostViewController:(MatchmakerHost *)controller startGameWithSession:(GKSession *)session playerName:(NSString *)name clients:(NSArray *)clients
{
[self dismissViewControllerAnimated:NO completion:^
{
[self startGameWithBlock:^(GameMultiplayer *aGame)
{
[aGame startServerGameWithSession:session playerName:name clients:clients];
}];
}];
}
、最後にそのメソッドの呼び出しがある場合、これはGameMultiplayer
:
- (void)startServerGameWithSession:(GKSession *)session playerName:(NSString *)name clients:(NSArray *)clients
{
_clients = clients;
const char* className = class_getName([[_clients objectAtIndex:0] class]);
NSLog(@"yourObject is a: %s", className);
self.isServer = YES;
_session = session;
_session.available = NO;
_session.delegate = self;
[_session setDataReceiveHandler:self withContext:nil];
_state = GameStateWaitingForSignIn;
[self.delegate gameWaitingForClientsReady:self];
// Create the Player object for the server.
Player *player = [[Player alloc] init];
player.name = name;
player.peerID = _session.peerID;
player.position = PlayerPositionBottom;
[_players setObject:player forKey:player.peerID];
// Add a Player object for each client.
int index = 0;
for (NSString *peerID in clients)
{
Player *player = [[Player alloc] init];
player.peerID = peerID;
[_players setObject:player forKey:player.peerID];
if (index == 0)
player.position = ([clients count] == 1) ? PlayerPositionTop : PlayerPositionLeft;
else if (index == 1)
player.position = PlayerPositionTop;
else
player.position = PlayerPositionRight;
index++;
}
NSLog(@"Players:");
Packet *packet = [Packet packetWithType:PacketTypeSignInRequest];
[self sendPacketToAllClients:packet];
// for (int i = 0; i < [_players count]; i++) {
// NSLog([NSString stringWithFormat:@"%@", [clients objectAtIndex:i]]);
// }
}
どのようにGKSessionオブジェクトをセットアップしましたか? GKSession * gk_session = [[GKSession alloc] initWithSessionID:nil displayName:nil sessionMode:GKSessionModePeer]; – ldindu
編集が追加されました – RaysonK
[_session setDataReceiveHandler:self withContext:nil];あなたがここに自己を渡している、ハンドラは、他のピアからデータを受け取ったときにセッションを呼び出すオブジェクトです。ハンドラは次のシグネチャを持つメソッドを実装する必要があります。 - (void)receiveData:(NSData *)fromPeer:(NSString *)peer inSession:(GKSession *)セッションコンテキスト:(void *)context;私はあなたが正しいハンドラを渡しているかどうか、不思議に思っていますか? – ldindu