Save 37% off PRO during our Black Friday Sale! »

Mongoman A Node.Js Powered Pacman Clone

Mongoman A Node.Js Powered Pacman Clone

How to implement a multiplayer pacman clone called mongoman using node.js, websockets, html5 and mongodb. There will be a live gaming session (I'm bringing gear to host it)


Christian Kvalheim

July 06, 2012


  1. Christian Kvalheim - twitter: @christkv Mongoman A Node.Js Powered

    Pacman Clone Friday, July 6, 12
  2. WHO AM I •Wrote node.js driver for mongodb •Working for

    10gen (you know the MongoDB company) •Based in Barcelona •I run • mongodb-spain/ Friday, July 6, 12
  3. WHY PACMAN NOSTALGIA Friday, July 6, 12

  4. History of Pacman Friday, July 6, 12

  5. The original pacman Friday, July 6, 12

  6. 32 years later Friday, July 6, 12

  7. A RANT Friday, July 6, 12

  8. The evolution of Game 1980S Friday, July 6, 12

  9. The evolution of Game 1990S Friday, July 6, 12

  10. The evolution of Game 2000S Friday, July 6, 12

  11. The evolution of Game 2010S Friday, July 6, 12

  12. The HTML5 state 2012 1980ish Friday, July 6, 12

  13. Really this is Gaming ? •1980’s technology = Canvas •WEBGL

    IS NOT A STANDARD •NaCl IS NOT A STANDARD •Flash will have to stay for awhile YES REALLY Friday, July 6, 12
  14. Building Pacman MongoMan Friday, July 6, 12

  15. Challenges •Latency, Latency, Latency •Spend minimal time in the Eventloop

    •Process locality on server •Checking settings •Idle garbage collection •Socket noDelay •Minimize GC work Friday, July 6, 12
  16. MongoMAN Friday, July 6, 12

  17. Game Architecture Express.JS WEBSOCKET AKIHABARA SOUNDJS CLIENT SERVER Friday, July

    6, 12
  18. Technology •Node.JS •Akihabara for game engine •SoundJS for the audio

    •websocket npm package •Socket.IO was a lot slower •Mongo capped collections •findAndModify for board allocation Friday, July 6, 12
  19. Akihabara •Retro 2D game engine •“Simple” to adapt example game

    to Mongoman •Uses canvas only so not the fastest game engine out there but plenty good enough :) Friday, July 6, 12
  20. Websocket npm package •Pure websocket implementation •No fallback compatibility •Supports

    binary frame protocol for Websockets •Fast Friday, July 6, 12
  21. SoundJS •Manages all the complexity of audio in the browser

    •Mixes audio •Simple to use API Friday, July 6, 12
  22. Mongo Capped collections •Positives •Fifo based limiting memory exposure •Documents

    don’t move in memory •Predictable time to write/ read from collection •Supports Indexes •Tailable (like tail -f) Friday, July 6, 12
  23. Mongo Capped collections •Negatives •Documents cannot grow so we need

    to prime each document Friday, July 6, 12
  24. Node.JS Cluster •Express serves up the basic html pages and

    handles the hiscore list. •Organized using the cluster api in Node.js 0.6.X •1 parent process and X child processes handling game •If a child dies a new one is born Friday, July 6, 12
  25. Cluster code // Fork workers (one pr. cpu), the web

    workers handle the websockets for (var i = 0; i < numCPUs; i++) { var worker = cluster.fork(); worker.on('message', function(msg) { if(msg != null && msg['cmd'] == 'online') { console.log("================================ worker online"); console.dir(msg); } }); } // If the worker thread dies just print it to the console and for a new one cluster.on('death', function(worker) { console.log('worker ' + + ' died'); cluster.fork(); }); Friday, July 6, 12
  26. Session workaround •Could not use express sessions as they don’t

    work with the websocket module •Wrote own session handling using capped collection •A bit HACKY but works •Using named cookie to tie sessions together •I should probably fix it Friday, July 6, 12
  27. Websocket session grab code // Parse the cookie var cookie

    = connectUtils.parseCookie(request.httpRequest.headers['cookie']); // Grab the session id var sessionId = cookie['connect.sid']; // Grab the username based on the session id and initialize the board state.sessionsCollection.findOne({id:sessionId}, function(err, session) { if(err) throw err; session = typeof session == 'undefined' || session == null ? {} : session; initializeBoard(state, session, self); }) •Uses connect npm package for nice to have cookie parser functions •Using capped collection as well Friday, July 6, 12
  28. .findAndModify( {number_of_players: {$lt:5}, pid:}, [], {$inc: {number_of_players: 1}, $push:{players:connection.connectionId}},

    {new:true, upsert:false}, function(err, board) { // Code to deal with the board or the non existance of the board } Initializing a board •Using findAndModify to pick a board •Atomic operation to add player to existing board •Process bound Friday, July 6, 12
  29. Sample ghost state machine FIGURE 1. State diagram for Pac-Man

    ghost AI A state machine can also be represented by a table, but in general, the state diagram is more intuitive, making it easier to consider how the system works as a whole. A table can be useful in Friday, July 6, 12
  30. Our simplified one FIGURE 1. State diagram for Pac-Man ghost

    AI A state machine can also be represented by a table, but in general, the state diagram is more intuitive, making it easier to consider how the system works as a whole. A table can be useful in YOU Friday, July 6, 12
  31. Simple example of state mongoman ghost ghost ghost ghost server

    movement collision +ghost +powerpill ghostdead Friday, July 6, 12
  32. All messages are belong to •Messages from server •initialize •dead

    •mongowin •ghostdead •powerpill •movement Friday, July 6, 12
  33. Current state of affairs •Collision detection managed on server •Pills

    are not managed on server •Might need to move the entire board to server Friday, July 6, 12
  34. Friday, July 6, 12

  35. One for all, all for one •Websocket connections are bound

    to a specific process •Avoids overhead •Would need separate IO queues, would cause latency Friday, July 6, 12
  36. Garbage collection •Keeping a lot in memory •disable v8’s idle

    garbage collection •“–nouse-idle-notification” •avoid v8 needing to iterate over a massive list of objects that are not collectable •lowers latency and pauses Friday, July 6, 12
  37. Connections •Ensure you use noDelay(true) •Sends packets as fast as

    they arrive not doing any buffering •Set to true by default Friday, July 6, 12
  38. Native BSON parser in Node •Using bson native parser •avoid

    intermediate memory allocation •uses less memory •slightly faster •Waiting for a patch to take the performance up massively Friday, July 6, 12
  39. Light speed that #@!@#$ •Your max resolution is 2X times

    the ping time to the server •20ms = 40 ms delivery = 25 fps •135 = 270 ms delivery = 4 fps •Now you know why it’s a WOW EU server or US server Friday, July 6, 12
  40. Friday, July 6, 12

  41. •Websockets still fresh •Few browsers support binary •Understand memory/cpu at

    high connection count •Avoid process switching is possible •Latency is the mind killer •If you users are in Germany have a local server for Germany Keep in mind Friday, July 6, 12
  42. •How much data are you pushing across the wire •What’s

    the ping time to the client •Profile both the browser and the server using available tools •Chrome development tools •Collect stats wire usage etc. Profile the game Friday, July 6, 12
  43. Whats on the horizon Friday, July 6, 12

  44. •WebGL Coming in iOS at some point soon as well

    as Android •In the near future we can use for real 2+ years I recon •Supported by Firefox, Chrome and Safari and even Opera but not IE (probably NEVER) WebGL and mobile Friday, July 6, 12
  45. •Initial support in Chrome •Pros •No waiting for ack •Lower

    latency •Cons •Lost messages •No resend UDP might be coming Friday, July 6, 12
  46. Next project in the works •Write a tank AI to

    do battle •DCPU-16 support •Want to help ? •I need graphics and coding help :) •Launching as soon as it’s ready Friday, July 6, 12
  47. Game TIME Friday, July 6, 12

  48. Demo game •Join in the game, DDOS My Mac Mini.

    •SSD: mongoman •Password: mongoman •IP: Friday, July 6, 12
  49. Where to get the code • mongoman Friday, July 6,