我正在构建一个浏览器游戏,其中包含玩家周围环境的迷你地图.我需要跟踪其他玩家的位置,并在有人移动时更新此迷你地图.我在NodeJS和CouchDB中实现它.我的设计如下:
我有一个数据库,可以更改所有游戏数据.在这个数据库中,我有一个文档,其中包含二维数组中的基本地图数据,网格上的每个方块都由此数组中的元素表示.因为我可以有不同万吨的用户都同时动一下地图,我需要一些方法,以确保我没有得到一个读作别人在写它(如果一吨的用户正在阅读我能得到错误的信息和写入单个文件).我决定在这个数据库中有单独的文档,它们代表各个方块,每个文档都有那个正方形"播放"的播放器和与该方块相关的其他一些数据.实质上,地图文档仅用作方形文档的查找表.这使我能够在不必重写整个地图文档的情况下更改单个文档,从而解决了同时读取和写入的问题.
但问题是,我需要获取一个迷你地图供用户用作参考.这个迷你地图将包含周围广场的文件.由于我同时需要所有这些,我想我会从数据库中获取所有9个方块并将其返回到单个ajax响应中.我的问题是减少了阻塞IO的数量.现在,我有一个嵌套循环,从数据库中请求我需要的方块.这是我的代码(传递位置和地图):
var miniMap = new Array();
var keyMap = new Object();
var numDone = 0;
for(i = position.y - 1, y = 0; i < position.y + 1 && i < map.length; i++, y++){
miniMap[i] = new Array();
for(v = position.x - 1, x = 0; v < position.x + 1 && v < map.length; v++, x++){
keyMap[map[i][v].id] = {'x': x, 'y': y};
gameDB.getDoc(map[i][v].id, function(er, doc){
var tPos = keyMap[doc._id];
miniMap[tPos.y][tPos.x] = doc;
numDone++;
});
}
}
Run Code Online (Sandbox Code Playgroud)
不过我的问题是getDoc是非阻塞的,所以我不知道它何时将方形数据设置为miniMap.我想过做这样的事情:
while(numDone < 9){
sleep(10);
}
callback(miniMap);
Run Code Online (Sandbox Code Playgroud)
这将让我等到CouchDB完成我的所有数据,但JavaScript没有睡眠功能.我发现的最接近是setTimeout的,但也无阻塞我永远是100%肯定,我选择的超时时间将足以让CouchDB的完成得到我的数据.
所以基本上我想要一个条件,测试它,然后如果条件为假则再次将它返回到事件堆栈.我想到的唯一解决方案是使用递归的setTimeout回调来执行以下操作:
function testCallback(data, condition, callback){
if(data < condition){
setTimeout(function(){
testCallback(data, condition, callback);
}, 10);
}else{
callback(data);
}
}
Run Code Online (Sandbox Code Playgroud)
这看起来非常糟糕......有没有更好的方法可以做到这一点?我应该放弃这种方法并强制进行多次ajax调用以获取更新数据吗?我应该采取阻止方法吗?
只需使用另一个回调:
function getMiniMap(....., callback) { // supply the callback that sends the data
var miniMap = new Array();
var keyMap = new Object();
var numDone = 0;
...
numDone++;
if (numDone === 9) { // as soon as everything has been collected...
callback(miniMap); // ... call the send callback and supply it the miniMap
}
});
}
}
}
Run Code Online (Sandbox Code Playgroud)
哦,你的数据库模型非常糟糕,我对你的游戏知之甚少,但除非这需要在多个Node进程上运行,否则最好将Map等保存在JS数组中并且只写入DB当服务器需要保存状态时.
哦,你也可以keyMap用匿名函数调用替换你:
(function(x, y) {
gameDB.getDoc(map[i][v].id, function(er, doc){
var tPos = keyMap[doc._id];
miniMap[tPos.y][tPos.x] = doc;
numDone++;
});
})(x, y); // pass in a copy of x and y
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
16604 次 |
| 最近记录: |