Frage

I am building a game engine on Meteor JS and trying to create a way to link together a number of collections. The current 'schema' looks like this:

GameCollection = { <meta> } //This is a Collection (a Meteor MongoDB document)

Scene = {gameId: _id, <other resource ids and meta>} //This is a Collection

The issue is I need to create a map from one scene to anther. These paths needs to fork and merge easily. I am getting the feeling that I should be using a graph/triple database to represent this but I want to say within "Meteor's magic" and that means normal MongoDB Collections. If someone has a simple to use alternative I would still like to hear it, but I would prefer a Meteor-esk pattern. Pushes in the right direction would also be great!

I have three specific needs:

  1. If I am at this scene what scene or scenes do I lead to.
  2. If I am at this scene then give me the ids of all scene x number of steps into the future. Where 'x' is a variable (so I can send the lot of them down to the client)
  3. Count and give me all possible paths so I can give a visual representation of the game.

What I am specifically looking for is: is a graph database what I am looking and if not what schema pattern should I use with mongoDB?

UPDATE:

I have confirmed that neo4j will do what I need from a logical standpoint. But I would lose the benefit of working with Meteor Collections. This means losing reactivity which in turn breaks my live collaborative model. I really need a MongoDB alternative.

UPDATE 2:

I ended up trying to stick the relationship inside of the GameCollection. It seems to be working but I would like a cleaner way if possible.

map: [ { //an array of objects (relations)
  id: _id //key to a Scene
  toKey: _id  //leads to scene; toKey is ether 'next' or some num [0..n] for multi paths
}]
War es hilfreich?

Lösung

So I ended up going the denormalization route. I put an array of scenes into the GameCollection.

scenes: [{ id: random_id, next: 'next_id' || [next_ids], <other resource ids and meta> }]

Then I built this monster:

getScene = function (scenes, id) {
 return _.find(scenes, function (scene) {
  return (scene.id == id)
 })
}

getNext = function (scene) {
 if (!scene) { return null }
 if (scene.type == 'dialogue') {
  return scene.next
 }
 if (scene.type == 'choice') {
  return _.pluck(scene.next, 'id')
 }
}

scenesDive = function (list, next, container, limit, depth) {
 if (!depth) {
  depth = 0
 }
 myDepth = depth + 1
 var scene = getScene(list, next)
 if (container.indexOf(scene) != -1) { return } //This path has already been added. Go back up.
 container.push(scene)
 if (myDepth == limit) { return } //Don't dive deeper then this depth.

 var nextAoS = getNext(scene) //DIVE! (array or string)
 if (_.isArray(nextAoS)) {
  nextAoS.forEach(function (n) {
   scenesDive(list, n, container, limit, myDepth)
  });
 } else {
  scenesDive(list, nextAoS, container, limit, myDepth)
 }
}

I am sure there is a better way but this is what I am going with for now.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top