Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In a NodeJS game with each object as a class, how should events be treated?

When dealing with multiple classes in a Javascript/NodeJS game, I'm having trouble figuring out which class should emit events and which classes should listen for the. I am following this guide to creating event-driven games: http://pragprog.com/magazines/2011-08/decouple-your-apps-with-eventdriven-coffeescript

I'm writing a small game and have split my classes into the following controllers:

world - creates the game world and progresses through a number of 'turns' to determine some simple game logic (i.e. a character should move, a tower should shoot).

tower - a tower sits on a 10x10 grid and has a range. When an object comes into range, it can shoot.

mobs (enemies) - a mob spawns on the 10x10 grid and moves every 3 seconds. At some point, it wanders in range of a tower.

I have been reading about EventEmitters all day but can't seem to figure out the right way to architect my events. Should the mobs fire an event when they move, and the tower listen for a 'move' event? Or should the world control all of the events and the tower/mobs listen to the world?

See below for example code.

Background: I've been working on a simple TowerD game for NodeJS and decided to implement the server first. I'm storing all entities in MongoDB and using geospatial calculation to determine if objects are in range to shoot. Currently i'm using a rudimentary 3 second loop to 'tick' the game and progress logic but I'd like to move to a truly event-driven model and am struggling.

World:

exports.World = class World extends EventEmitter

  constructor: ->
    ### Initial config ###
    @gameTime = 3000  # every 3000ms, the game progresses

    ### Start the game!! ###
    @game = setInterval ->
      world.gameLoop()
    , @gameTime

    ### Load the map ###
    # First level: Hidden Valley
    @maps = []
    @maps.push new map 'hiddenvalley'

### Load the mobs ###
    # First map has one mob: Warrior
    @mobs = []

    # Let's create two of them  
    @mobs.push new mob @maps[0].mobs[0]
    @mobs.push new mob @maps[0].mobs[0]

(see full world.coffee: https://github.com/bdickason/node-towerd/blob/master/controllers/world.coffee)

Tower:

exports.Tower = class Tower
  constructor: (name) ->
    name = name.toLowerCase() # In case someone throws in some weird name

  # Check for anything within range
  checkTargets: (callback) ->
    mobModel.find { loc : { $near : @loc , $maxDistance : @range } }, (err, hits) -> 
      if err
        console.log 'Error: ' + err
      else
        callback hits

(see full towers.coffee: https://github.com/bdickason/node-towerd/blob/master/controllers/towers.coffee)

Mobs:

exports.Mob = class Mob extends EventEmitter

  move: (X, Y, callback) ->
    @loc = [@loc[0] + X, @loc[1] + Y]
    newloc = @loc
    mobModel.find { uid: @uid }, (err, mob) ->
      if(err)
        console.log 'Error finding mob: {@uid} ' + err
      else
        mob[0].loc = newloc
        mob[0].save (err) ->
          if (err)
            console.log 'Error saving mob: {@uid} ' + err
    console.log 'MOB ' + @uid + ' [' + @id + '] moved to (' + @loc[0] + ',' + @loc[1] + ')'

(see full source of mobs.coffee: https://github.com/bdickason/node-towerd/blob/master/controllers/mobs.coffee)

Full source of project: https://github.com/bdickason/node-towerd

Any event help would be appreciated. I've poured over about 15 nodejs games on github and haven't found anyone using this pattern yet :(

like image 834
Brad Dickason Avatar asked Nov 04 '22 16:11

Brad Dickason


1 Answers

I'd use a custom EventEmitter that supports "parents", e.g. bubbling event propagation. Then I would do it the following way:

  • When a mob moves, it fires an "move" event on itself with a parameter like {mob: @,x: x, y: y} (the event then bubbles up to the world).
  • The world listens for "move" events. When it receives one, it checks in the database to look up the towers that need to be notified and emits the event on them.
like image 129
thejh Avatar answered Nov 09 '22 04:11

thejh