0

在我正在开发的游戏中,我想让用户能够在异步和实时回合制比赛之间进行选择。后者缺少的一件事是我怎么知道谁先轮到了。我正在尝试找到一种方法来检测谁首先连接并自动设置该玩家的回合。不幸的是,两个玩家似乎同时连接,因为在找到匹配后,expectedPlayersCount 为两个玩家产生 1,并且在 didChangeState 事件中,相同的变量也为他们两个产生 0。所以我无法判断谁是第一个参加比赛的人,因为这一切似乎都是同时发生的。作为临时修复,我只是使用他们的 ID。ID 最低的那个是第一个回合的那个。但是,我'

这个方法是我开始新游戏时所说的。我传递了一个实时布尔值来指定游戏中心包装器返回的游戏应该是 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];
            }
        }
    }
}

我将不胜感激任何评论。

4

1 回答 1

2

与其尝试确定谁先连接,不如让所有玩家使用 arc4random 选择一个随机数?

int randomNumber = arc4random%1000000;

数字最大的玩家可以先玩。您必须确保所有玩家互相发送他们的随机数,以便每个人都可以比较并决定谁是第一名。在上面的示例中,范围将高达 100 万,因此两个玩家选择相同随机数的几率很低。

如果两个玩家确实选择了相同的随机数,您可以计算他们的 playerId 的哈希值,并让具有较大哈希值的玩家排在第一位。

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

发生哈希冲突的可能性非常低,因为 playerId 字符串很短。您仍然可以检查这种冲突并适当地处理它(也许通过再次散列;))。

于 2013-11-16T09:18:35.067 回答