使用 Node.JS、MongoDB 和 Socket.IO 的实时多人游戏:游戏循环和异步调用
Real time multiplayer game using Node.JS, MongoDB and Socket.IO : Game loop and async calls
我目前正在使用 Node.JS、MongoDB 和 Socket.IO 构建一个 HTML5 游戏。这个项目的目的不是真正创建一个完整的、完全可玩的游戏,而是理解和实现多人游戏编程的一些基本概念并习惯 MongoDB。
这是我使用的基本服务器架构。服务器通过 Socket.IO 监听客户端,每次收到消息时,都会将其推送到队列中。每当玩家想要移动或以某种方式有效地改变游戏时,都会收到一条消息。我真的很含糊,因为向你详细展示这个游戏是什么并不重要。所以服务器接收来自所有客户端的消息并在内存中保存一段时间。
服务器每隔 50 毫秒按顺序处理队列中的所有消息并使游戏状态前进,将更改广播给客户端,然后清空队列并再次开始监听客户端。
我在构建这个游戏循环时遇到了一些困难,因为我不确定 MongoDB 是做什么的以及它是否及时完成,因为所有调用都是纯异步的。假设以下代码在我的游戏循环中,这是我的担忧:
for (var i=0; i<queue.length; i++) {
if(queue[i].message.type === "move") {
//The server has first to ensure that the player can effectively move,
//thus making a query to MongoDB. Once the result has been retrieved,
//the server makes an update in MongoDB with the new player position
}
//At this point, due to the async nature of MongoDB,
//I cannot ensure that the queries have been executed nor that the message was effectively handled
}
//Here again, I cannot ensure that the game state gracefully advanced
//and then I cannot broadcast it.
我认为游戏循环必须是连续的,但我不确定是否可以使用 MongoDB 来做到这一点,而且我不确定 MongoDB 是否是正确的工具工作。
我正在为 MongoDB 使用官方 Node.JS 驱动程序,因为我对嵌套文档比对对象数据建模更感兴趣。
对于在这种情况下构建顺序游戏循环,您有任何线索吗?还是我在超出其目的的情况下使用 MongoDB?
看起来很简单。
解决方案是不使用 for 循环,因为您只想在前一条消息完成后开始处理下一条消息。为此,使用像 async
和 eachSeries
函数这样的库可能更容易。
https://github.com/caolan/async#each
async.eachSeries(queue, processMessage, allDone);
function processMessage(message, callback) {
// do stuff with message, don't forget to call callback when you have complete all async calls and are done processing the message!
// eg
if(message.type === "move") {
mongo.insert({player: message.player, x:message.x, y:message.y}, function (err, res) {
// error check etc
callback();
}
}
}
function allDone() {
// called when all messages have been proccessed!
// setTimeout(processNewQueue, 50);
}
我目前正在使用 Node.JS、MongoDB 和 Socket.IO 构建一个 HTML5 游戏。这个项目的目的不是真正创建一个完整的、完全可玩的游戏,而是理解和实现多人游戏编程的一些基本概念并习惯 MongoDB。
这是我使用的基本服务器架构。服务器通过 Socket.IO 监听客户端,每次收到消息时,都会将其推送到队列中。每当玩家想要移动或以某种方式有效地改变游戏时,都会收到一条消息。我真的很含糊,因为向你详细展示这个游戏是什么并不重要。所以服务器接收来自所有客户端的消息并在内存中保存一段时间。
服务器每隔 50 毫秒按顺序处理队列中的所有消息并使游戏状态前进,将更改广播给客户端,然后清空队列并再次开始监听客户端。
我在构建这个游戏循环时遇到了一些困难,因为我不确定 MongoDB 是做什么的以及它是否及时完成,因为所有调用都是纯异步的。假设以下代码在我的游戏循环中,这是我的担忧:
for (var i=0; i<queue.length; i++) {
if(queue[i].message.type === "move") {
//The server has first to ensure that the player can effectively move,
//thus making a query to MongoDB. Once the result has been retrieved,
//the server makes an update in MongoDB with the new player position
}
//At this point, due to the async nature of MongoDB,
//I cannot ensure that the queries have been executed nor that the message was effectively handled
}
//Here again, I cannot ensure that the game state gracefully advanced
//and then I cannot broadcast it.
我认为游戏循环必须是连续的,但我不确定是否可以使用 MongoDB 来做到这一点,而且我不确定 MongoDB 是否是正确的工具工作。
我正在为 MongoDB 使用官方 Node.JS 驱动程序,因为我对嵌套文档比对对象数据建模更感兴趣。
对于在这种情况下构建顺序游戏循环,您有任何线索吗?还是我在超出其目的的情况下使用 MongoDB?
看起来很简单。
解决方案是不使用 for 循环,因为您只想在前一条消息完成后开始处理下一条消息。为此,使用像 async
和 eachSeries
函数这样的库可能更容易。
https://github.com/caolan/async#each
async.eachSeries(queue, processMessage, allDone);
function processMessage(message, callback) {
// do stuff with message, don't forget to call callback when you have complete all async calls and are done processing the message!
// eg
if(message.type === "move") {
mongo.insert({player: message.player, x:message.x, y:message.y}, function (err, res) {
// error check etc
callback();
}
}
}
function allDone() {
// called when all messages have been proccessed!
// setTimeout(processNewQueue, 50);
}