Как мне эмулировать «сон» в NodeJS? - PullRequest
12 голосов
/ 20 декабря 2010

Я строю браузерную игру с мини-картой окрестностей игрока.Мне нужно отслеживать, где находятся другие игроки, и обновлять эту мини-карту всякий раз, когда кто-то движется.Я реализую это в NodeJS и CouchDB.Мой дизайн выглядит следующим образом:

У меня есть база данных для всех изменяющихся игровых данных.В этой базе данных у меня есть документ, который содержит основные данные карты в двумерном массиве, где каждый квадрат на сетке представлен элементом в этом массиве.Поскольку у меня могло быть множество разных пользователей, перемещающихся по карте одновременно, мне нужен был какой-то способ, чтобы я не читал, поскольку кто-то другой пишет на него (я мог бы получить неверную информацию, если тонна пользователей читает изапись в один документ).Я решил иметь отдельные документы в этой базе данных, которые представляют отдельные квадраты, и у каждого документа есть игроки, которые находятся на этом квадрате, и некоторые другие данные, связанные с этим квадратом.По сути, документ карты используется только как справочная таблица для квадратного документа.Это позволяет мне изменять один документ без необходимости перезаписывать весь документ карты, решая проблему одновременного чтения и записи.

Однако моя проблема заключается в том, что мне нужно получить мини-карту, чтобы пользователь могиспользовать в качестве ссылки.Эта мини-карта будет иметь документы на окружающие площади.Поскольку мне нужно все это одновременно, я решил просто взять все 9 квадратов из базы данных и вернуть их в одном ответе ajax.Моя проблема, однако, заключается в уменьшении количества блокирующих операций ввода-вывода, которые я делаю.Прямо сейчас у меня есть вложенный цикл, который запрашивает нужные мне квадраты из базы данных.Вот мой код (позиция и карта переданы):

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++;
        });
    }
}

Моя проблема, однако, в том, что getDoc не блокирует, поэтому я не знаю, когда он установит квадратные данныев мини-карту.Я думал о том, чтобы сделать что-то вроде этого:

while(numDone < 9){
    sleep(10);
}
callback(miniMap);

Это позволит мне подождать, пока CouchDB закончит получать все мои данные, но JavaScript не имеет функции сна.Самым близким, что я нашел, был setTimeout, но это также неблокирует, и я никогда не буду на 100% уверен, что выбранное мной время ожидания будет достаточно, чтобы CouchDB мог завершить получение моих данных.

Итакв основном я хочу иметь условие, проверить его, а затем вернуть его снова в стек событий, если условие ложно.Единственное решение, о котором я подумал, было иметь рекурсивный обратный вызов setTimeout, который бы делал что-то вроде этого:

function testCallback(data, condition, callback){
    if(data < condition){
        setTimeout(function(){
            testCallback(data, condition, callback);
        }, 10);
    }else{
        callback(data);
    }
}

Это кажется довольно ужасным ... Есть ли лучший способ, которым я мог бы сделать это?Должен ли я отказаться от этого подхода и заставить несколько ajax-вызовов получать обновленные данные?Должен ли я пойти на блокирующий подход?

Ответы [ 2 ]

5 голосов
/ 20 декабря 2010

Просто используйте другой обратный вызов:

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
                }
            });
        }
    }
}

Да, и ваша модель базы данных действительно плохо, я не знаю много о вашей игре, но если для этого не нужно запускать несколько процессов Node, было бы лучше сохранить карту и т. Д. в массиве JS и записывать в БД только тогда, когда серверу необходимо сохранить состояние.

Да, вы также можете заменить 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
1 голос
/ 09 октября 2011

Учитывая, что мы говорим о системе, основанной на событиях, я думаю, что было бы чище, если бы вы просто выдавали событие load done, когда numDone == 9, и перехватывали его из своего основного и продолжали оттуда.Вы можете перерисовать всю карту, даже если игра должна быть запущена на нескольких узлах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...