2013-10-26 28 views
0

在我正在開發的遊戲中,我想讓用戶可以選擇異步和實時回合比賽。我從後者中遺漏的一件事是,我怎麼知道誰是第一個回合。我試圖找到一種方法來檢測誰先連接並自動設置該玩家的回合。不幸的是,這兩個玩家似乎都在同一時間進行連接,因爲在找到一個匹配後,expectedPlayersCount的結果爲1,而在didChangeState事件中這兩個玩家的結果都是0。所以我無法分辨誰是第一個參加比賽,因爲看起來這一切都是同時發生的。 作爲臨時修復,我只是使用他們的ID。 ID最低的那個是第一回合的那個。不過,我試圖找到一種更好的方式,因爲採用這種方法時,玩家A在與玩家B對抗時總是獲得第一個回合,這在我的遊戲中佔有很小的優勢。確定首先獲得連接的玩家

這種方法就是我開始新遊戲時所說的。我傳遞一個realTime布爾值來指定遊戲中心封裝器返回的遊戲是GKMatch還是GKTurnBasedMatch。

//Calculate the level group to find other players in the same group 
NSInteger levelGroup = (self.player.levelValue/STLevelSkillInterval) * STLevelSkillInterval; 

//Find a match for the local player 
[self.gameCenter findMatchWithPlayerAttributes:levelGroup realTime:realTime group:0 onCompletion:^(GKTurnBasedMatch *turnMatch, GKMatch *realTimeMatch) { 

    [self handleTurnMatchFound:turnMatch realTimeMatch:realTimeMatch completionBlock:onCompletion]; 

}]; 

...

這裏這種方法是負責處理找到比賽結束後遊戲中心響應。 create和synchronize方法在CoreData中存儲匹配實例,並通過從Game Center和後端獲取相應的信息來填充其數據。所以如果在完成這個時候預期的球員數量達到了0,我就會立刻將比賽開始時稱爲完成區塊。否則,我只保存完成塊,以便以後在其他玩家連接到匹配時使用它。這個部分的問題是它從來沒有達到0,不是兩個玩家中的任何一個。

- (void)handleTurnMatchFound:(GKTurnBasedMatch *)turnMatch realTimeMatch:(GKMatch *)realTimeMatch completionBlock:(void(^)(STMatch *match, NSError *error))onCompletion 
{ 
    if (turnMatch != nil) 
    { 
     [self createAndSynchronizeLocalMatch:turnMatch onCompletion:^(STMatch *localMatch) { 

      onCompletion(localMatch, nil); 

     }]; 
    } 
    else if (realTimeMatch != nil) 
    { 
     [self createAndSynchronizeRealTimeLocalMatch:realTimeMatch onCompletion:^(STMatch *localMatch) { 

      if (realTimeMatch.expectedPlayerCount == 0) 
      { 
       onCompletion(localMatch, nil); 
      } 
      else 
      { 
       self.findRealTimeMatchCompletionBlock = onCompletion; 
      } 

     }]; 
    } 
    else 
    { 
     onCompletion(nil, nil); 
    } 
} 

...

這是處理球員的狀態變化的方法。所以基本上我只是用來自連接播放器的值更新實時匹配的本地實例,然後我稱之前存儲的完成塊。

- (void)match:(GKMatch *)match player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state 
{ 
    if (state == GKPlayerStateConnected) 
    { 
     STMatchParticipant *placeholderParticipant = [self.realTimeMatch getMatchParticipantWithPlayerId:nil]; 
     placeholderParticipant.playerId = playerID; 
     placeholderParticipant.statusValue = GKTurnBasedParticipantStatusActive; 

     //This will sync the information for the connected player only 
     [self syncAllPlayerInfoForRealTimeMatchOnCompletion:^(NSArray *players) { 

      self.findRealTimeMatchCompletionBlock(self.realTimeMatch, nil); 

     }]; 
    } 
    else 
    { 
     //Notify the observers that the participant has disconnected from the match 
     STMatchParticipant *participant = [self.realTimeMatch getMatchParticipantWithPlayerId:playerID]; 

     for (id<STTurnBasedMatchDelegate> observer in self.matchesObservers) 
     { 
      if ([observer respondsToSelector:@selector(realTimeMatch:participantDidDisconnect:)]) 
      { 
       [observer realTimeMatch:self.realTimeMatch participantDidDisconnect:participant]; 
      } 
     } 
    } 
} 

我將不勝感激任何意見。

+0

有關您編寫的代碼問題的問題必須描述特定的問題 - 幷包含有效的代碼以重現問題 – 2013-10-26 03:21:42

+0

對不起。我編輯了我的問題,並在代碼中添加了一些註釋。謝謝。 – mdonati

回答

1

而不是試圖確定誰先連接,爲什麼你不只是讓所有的球員使用arc4random選擇一個隨機數?

int randomNumber = arc4random%1000000; 

具有最大數字的玩家可以先玩。您必須確保所有玩家互相發送隨機數,以便每個人都可以比較並決定誰是第一個。 在上面的例子中,範圍將高達100萬,所以選擇相同隨機數的兩名選手的機率很低。

如果兩個玩家選擇相同的隨機數,你可以計算他們的playerId的散列值,並讓擁有較大散列的玩家成爲第一個。

if ([GKLocalPlayer localPlayer].playerID.hash > otherPlayerId.hash) 

由於playerId字符串很短,發生散列衝突的機率非常低。你仍然可以檢查這個碰撞並且適當地處理它(也許再次哈希;))。