2013-07-12 1 views
11

申し訳ありませんが、これには多くのネットワークコーディングが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]]); 
// } 
} 
+0

どのようにGKSessionオブジェクトをセットアップしましたか? GKSession * gk_session = [[GKSession alloc] initWithSessionID:nil displayName:nil sessionMode:GKSessionModePeer]; – ldindu

+0

編集が追加されました – RaysonK

+0

[_session setDataReceiveHandler:self withContext:nil];あなたがここに自己を渡している、ハンドラは、他のピアからデータを受け取ったときにセッションを呼び出すオブジェクトです。ハンドラは次のシグネチャを持つメソッドを実装する必要があります。 - (void)receiveData:(NSData *)fromPeer:(NSString *)peer inSession:(GKSession *)セッションコンテキスト:(void *)context;私はあなたが正しいハンドラを渡しているかどうか、不思議に思っていますか? – ldindu

答えて

0

私はあなたが高速に電話していると思います。サーバが接続を認識すると、実際に接続を確立するためにクライアントに確認が送信されます。クライアントは成功したことを知ります。

これが発生する前にパケットを送信している場合、パケットは失われます。

[self performSelector:@selector(sendPacketToAllClients) withObject:nil afterDelay:1.0]; 

の代わり:

はちょうどこの行う

[self sendPacketToAllClients]; 

を私は接続がクライアント上の小さな遅延で別の瞬間に設立されたのと同じ問題を抱えていました。最善のことは、クライアントからのパケットをサーバーから受信する準備ができていることと、そこから通常通りに進むことです。両方のデバイス(サーバおよびクライアント)で

- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state 

を:

また、デバッグしてみてください。

0

私はGKSessionにも問題がありました。私は、今日(このサイトで)GKSessionは、Multipeer Connectivity Frameworkの使用を支持して廃止されることを知りたいと考えていました。運があれば、Wenderlich は新技術を使用したチュートリアルを行います。 :)

システムにはGKSessionといくつかの類似点がありますので、頭を囲むのは難しくありません。

Apple's doc link

関連する問題