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 :(
I'd use a custom EventEmitter that supports "parents", e.g. bubbling event propagation. Then I would do it the following way:
{mob: @,x: x, y: y}
(the event then bubbles up to the world).If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With