我找到的解决方案是使用一些消息系统(在我的例子中是 Redis pub/sub)来让每个玩家实例知道当前状态。
每个玩家都有一个工人实例来处理他自己的回合(包括计时器)。当它完成时,无论是通过玩家的移动还是通过超时,它都会推进回合计数器并通过 pub/sub 通知所有实例具有新的回合号。所有实例都收到消息并将轮数与其自己的玩家编号进行比较。如果匹配,则实例处理转弯并重复循环。
我将尝试提供一个示例(更多的是伪代码):
// pub & sub are Redis publisher & subscriber clients, respectively
function Game (totalPlayers, playerNumber) {
this.turn = 0
this.totalPlayers = totalPlayers
this.playerNumber = playerNumber
// Subscribe to Redis events
sub.on('message', function (channel, message) {
message = JSON.parse(message)
switch(message.type) {
case 'turn':
this.onTurn(message.turn)
}
})
sub.subscribe(this.channel, function() {
this.checkStart()
})
}
Game.prototype.checkStart = function () {
// This checks if this instance is for
// the last player and, if so, starts the
// main loop:
if(this.playerNumber == this.totalPlayers - 1) {
pub.publish(this.channel, JSON.stringify({type: 'turn', turn: 0})
}
}
Game.prototype.onTurn = function(turn) {
this.turn = turn
if(this.turn == this.playerNumber) {
this.timer = setTimeout(this.endTurn.bind(this), this.turnTime)
}
}
Game.prototype.endTurn = function() {
this.turn = (this.turn + 1) % this.totalPlayers
pub.publish(this.channel, JSON.stringify({type: 'turn', turn: this.turn})
}
我在使用这种方法时遇到了一些问题,主要问题是初始状态,如果玩家几乎同时连接,这不太正确。发送信息并确保所有实例同步也是一个好主意。
如果有人遇到同样的问题,我希望我说清楚。