4

这是一个相当复杂的问题,但我会尽量简单明了地解释它......

我正在使用 Firebase 构建一个基于网络的多用户游戏。我保留了游戏中每一轮的列表。在一轮结束时,每个用户都会看到一个“开始”按钮,当他们准备好开始下一轮时,他们会单击该按钮。当至少 50% 的用户点击“开始”时,该回合开始。

我有一个gameRef游戏的 Firebase 参考,一个roundListRef代表轮次列表的参考,以及一个roundRef代表当前轮次的参考。

我附加了一个child_added回调,roundListRef以便在添加新一轮时,它成为每个人的当前轮:

roundListRef.on('child_added', function(childSnapshot, prevChildName) {
    roundRef = childSnapshot.ref();
});

我可以从那里轻松跟踪newRoundVotesactivePlayers计算 50%。如果达到50%,则增加一个新的回合,触发每个人的child_added事件,新的回合将从那里开始……

gameRef.child('newRoundVotes').on('value', function(snapshot) {
    var newRoundVotes = snapshot.val();

    gameRef.child('activePlayers').once('value', function(snapshot) {
        var activePlayers = snapshot.val();

        if (newDriveVotes / activePlayers >= 0.5)
            addNewRound();
    });
});

我的问题是,我如何确保只添加一个新回合,并且每个人都在同一回合中?

例如,假设有 10 名玩家和 4 人已经投票开始下一轮。如果第 6 位玩家在第 5 位玩家触发他的事件之前投票child_added,则也将为第 6 位玩家添加一轮。

问题类似于.set()vs .transaction(),但不完全相同(根据我的理解)。

有没有人有办法解决吗?

4

2 回答 2

6

我认为如果提前知道回合名称,您可能可以通过交易解决这个问题。例如,如果您只使用 /round/0、/round/1、/round/2 等。

然后你可以有一些代码,如:

function addNewRound() {
    var currentRound = Number(roundRef.name());
    var nextRound = currentRound + 1;

    // Use a transaction to try to create the next round.
    roundRefList.child(nextRound).transaction(function(newRoundValue) {
        if (newRoundValue == null) {
            // create new round.
            return { /* whatever should be stored for the round. */ };
        } else {
            // somebody else already created it.  Do nothing.
        }
    });
}

这适用于您的场景吗?

于 2012-08-02T22:35:06.367 回答
1

您可以稍微修改您的想法并使用圆形计数器作为跟踪并发的地方。

currentRound = 0;
currentRoundRef.on('value', function(snapshot) {
   currentRound = snapshot.val();
   roundRef = roundListRef.child(currentRound);
});

function addNewRound() {
    currentRoundRef.transaction( function(current_value) {
       if( current_value !== currentRound ) {
          // the round timer has been updated by someone else
          return;
       }
       else {
          return currentRound + 1;
       }
    }, function(success) {
       // called after our transaction succeeds or fails
       if( success ) {
          roundListRef.child(currentRound+1).set(...);
       }
    });
}
于 2012-08-02T22:40:14.110 回答