2010-12-20 6 views
12

Je construis un jeu par navigateur avec une mini carte des environs du joueur. J'ai besoin de suivre où sont les autres joueurs et de mettre à jour cette mini-carte chaque fois que quelqu'un bouge. Je l'implémente dans NodeJS et CouchDB. Ma conception va comme suit:Comment émuler "sleep" dans NodeJS?

J'ai une base de données pour toutes les données de jeu changeantes. Dans cette base de données, j'ai un document qui contient les données cartographiques de base dans un tableau bidimensionnel, chaque carré de la grille étant représenté par un élément dans ce tableau. Comme je pouvais avoir des tonnes d'utilisateurs différents qui se déplaçaient simultanément sur la carte, j'avais besoin de m'assurer que je ne lisais pas comme quelqu'un d'autre m'écrit (je pourrais obtenir des informations erronées si une tonne d'utilisateurs lisent et écrire sur un seul document). J'ai décidé d'avoir des documents séparés dans cette base de données qui représentent les carrés individuels, et chaque document a les joueurs qui sont "sur" ce carré et d'autres données associées à ce carré. Essentiellement, le document de carte est utilisé uniquement comme une table de recherche pour le document carré. Cela me permet de modifier un seul document sans avoir à réécrire l'intégralité du document cartographique, ce qui résout le problème des lectures et écritures simultanées. Mon problème, cependant, est que j'ai besoin d'obtenir une mini carte pour l'utilisateur à utiliser comme référence. Cette mini carte aura les documents des carrés environnants. Puisque j'ai besoin de tout cela en même temps, j'ai pensé que je voudrais simplement saisir tous les 9 carrés de la base de données et le renvoyer dans une seule réponse ajax. Mon problème est cependant de réduire la quantité d'IO de blocage que je fais. À l'heure actuelle, j'ai une boucle imbriquée qui demande les carrés dont j'ai besoin de la base de données. Voici un coup d'oeil à mon code (position et carte sont passés dans):

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

Mon problème, cependant, est que GetDoc est non-blocage, donc je ne sais pas quand il établira les données carrés à minicarte . Je pensais faire quelque chose comme ceci:

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

Cela me laisse attendre jusqu'à ce que CouchDB est fini obtenir toutes mes données, mais JavaScript ne dispose pas d'une fonction sommeil. Le plus proche que j'ai trouvé était setTimeout, mais il est également non-bloquant et je ne serai jamais sûr à 100% que le temps que j'ai choisi pour le timeout sera suffisant pour permettre à CouchDB de finir d'obtenir mes données. Donc, fondamentalement, je veux avoir une condition, la tester, puis la renvoyer à la pile d'événements si la condition est fausse. La seule solution que je pensais était d'avoir un rappel setTimeout récursif qui ferait quelque chose comme ceci:

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

Cela semble assez terrible ... Y at-il une meilleure façon que je puisse faire cela? Dois-je abandonner cette approche et forcer plusieurs appels ajax pour obtenir des données à jour? Devrais-je opter pour une approche bloquante?

Répondre

5

Il suffit d'utiliser un autre rappel:

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

Oh, et votre modèle de base de données est vraiment mal, je ne sais pas grand-chose au sujet de votre jeu, mais à moins que cela doit fonctionner sur de multiples processus de nœud, il Il serait préférable de conserver la carte etc. dans un tableau JS et d'écrire uniquement dans la base de données lorsque le serveur doit enregistrer l'état.

Oh, et vous pouvez également remplacer votre keyMap par un appel de fonction anonyme:

(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

Je suppose que je fais la partie de la carte tout faux. Garder tout en mémoire au lieu de la base de données sera certainement un moyen plus facile de faire les choses. Je pense que je vais aller de l'avant et tout mettre dans mon document de carte et enregistrer seulement l'état quand j'ai besoin de redémarrer ou quelque chose. Merci pour l'aide!! – tjameson

+1

Consultez également [Redis] (http://redis.io/). Vous démarrez redis-server, puis utilisez le module redis dans le noeud. Vous donnez une clé de chaîne, puis un objet json, et BAM tous les enfants et les données sauvegardées. Chargez-le et utilisez la clé pour le remettre dans la mémoire en tant qu'objet. – BigOmega

+0

Vous pouvez également envisager [Firebase] (http://firebase.com) comme alternative à Redis ou à un magasin de données relationnel pour ce type d'informations d'état. Firebase va synchroniser l'état en temps réel avec tous les clients attachés. Il a été conçu pour votre type d'application. – DrFriedParts

1

Étant donné que nous parlons de système ed événement, je pense que ce serait plus propre si vous pouvez émettre un événement fait de la charge quand numDone == 9 et l'attraper de votre main et procéder à partir de là.

Vous pouvez mettre toute la carte en rouge même si le jeu doit être exécuté sur plusieurs nœuds.