0

私が取り組んでいるゲームでは、ユーザーが非同期とリアルタイムのターンベースの対戦を選択できるようにしたいと考えています。後者に欠けていることの 1 つは、誰が最初のターンを獲得したかをどうやって知るかということです。誰が最初に接続したかを検出し、そのプレーヤーのターンを自動的に設定する方法を見つけようとしています。残念ながら、マッチを見つけた直後に expectedPlayersCount が両方のプレーヤーに対して 1 を生成し、 didChangeState イベントで同じ変数が両方に対して 0 を生成するため、両方のプレーヤーが同時に接続されているようです。そのため、すべてが同時に行われるように見えるため、誰が最初に試合に参加したかを知る方法はありません. 一時的な修正として、私は彼らの ID を使用しています。最も低い ID を持つものは、最初のターンを持つものです。しかし、私は'

このメソッドは、新しいゲームを開始するときに呼び出すものです。ゲーム センター ラッパーによって返されるゲームが GKMatch または GKTurnBasedMatch のどちらであるかを指定するために、realTime bool 値を渡します。

//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 に達した場合、試合を開始できるので、すぐに完了ブロックを呼び出します。それ以外の場合は、完了ブロックを保存して、後で他のプレイヤーが試合に接続したときに使用できるようにします。その部分の問題は、2 人のプレイヤーのどちらでも、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 万であるため、2 人のプレイヤーが同じ乱数を選択する可能性は低くなります。

2 人のプレイヤーが同じ乱数を選択した場合、プレイヤー ID のハッシュを計算し、ハッシュが大きいプレイヤーを最初にすることができます。

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

playerId 文字列が短いため、ハッシュ衝突が発生する可能性は非常に低くなります。この衝突をチェックして、適切に処理することはできます (おそらく、再度ハッシュすることにより ;) )。

于 2013-11-16T09:18:35.067 に答える