Jump to content

Toying with NodeJS for multiplayer feature of my game. Have plently of questions.


Aristy
 Share

Recommended Posts

Hey,

Initially I used https://github.com/belohlavek/phaser-es6-boilerplate for the boilerplate of my game. I configured Gulpfile.js for my taste a bit and everything worked properly. However, I needed to rely on NodeJS/socket.io to develop a backend server so I could add multiplayer functionality. I watched some tutorials/read some guides and eventually came up with a solution. (Actually, checked some open source Github repos and tried to learn from them.)

This brought me an issue that I can't solve without having knowledge about NodeJS ecosystem. Right now, when I start developing:

1. I enter mygameclient folder, run npm start, and some plugin in this file (https://github.com/belohlavek/phaser-es6-boilerplate/blob/master/gulpfile.js) hosts my game at port 3000.

2. I enter mygameserver folder, run npm start, a plugin called Nodemon executes server.js, server.js runs on port 8080 which contains socket.io listeners/static endpoints for Express. (https://gist.github.com/sogko/b53d33d4f3b40d3b4b2e)

The whole thing became a mess. I want to make sure NodeJS runs on port 80, loads index.html when I enter localhost:80/index.html.

Questions

1. Should I ditch Browsersync and rely on Nodemon? What is Nodemon? Can I just rely on a basic NodeJS server instead? Can I host everything (game files, socket.io connections) on port 80?

2. How do you install a NodeJS as a production backend? Do you need to rely on web services such as Nginx?

3. Right now my game makes a socket connection on Phaser.update, which means it transfers data 60 times per second. Would that be overkill or this is how it is supposed to work?

4. Is it possible to "Observe" player.x and player.y data, and run an event whenever those attributes are changed? (e.g player.moving((player) => this.socket.emit("moving", player));

5. When I develop monsters, should I develop every monster related information on backend? For example, "A monster cannot go out of world bounds in Phaser." if I configure it. But, a monster must be syncronized between all clients so it's data must be kept in backend. In this case, do I need to develop "A monster cannot go out of world bounds" feature on backend? How is it being done generally? First client hosts the monsters/AI and others just see what first client sees?

Thanks alot.

Link to comment
Share on other sites

 

Hey Aristy,

1 hour ago, Aristy said:

1. Should I ditch Browsersync and rely on Nodemon? What is Nodemon? Can I just rely on a basic NodeJS server instead? Can I host everything (game files, socket.io connections) on port 80?

Nodemon is just a monitor (get it, nodemon?), it just restarts your process when it crashes, check out the docs. I normally use supervisor for the same requirement, its not that I've got anything against Remy I just like the feature set better :)

Port 80, yes you can, but I'll come to that in a bit.

1 hour ago, Aristy said:

2. How do you install a NodeJS as a production backend? Do you need to rely on web services such as Nginx?

Many people do, there are many many reasons for this. The three that are probably most important to me are

1. nginx works great as a reverse proxy , helping to separate the big bad outside world from my proces

2. nginx is great at serving static assets, node not so much, so it makes sense that for static client assets that nginx does the heavy loading and keeps my JS process clear to do what it is good at

3. nginx is dead easy to set up as a load balancing and I've rarely needed anything more

1 hour ago, Aristy said:

3. Right now my game makes a socket connection on Phaser.update, which means it transfers data 60 times per second. Would that be overkill or this is how it is supposed to work?

Depends on the game, I think many people throttle it to less. Also, when you say 'makes a connection', you mean 'sends a packet' right? websockets remain open, thats how the server can send you stuff. (socket.io falls back to polling when sockets are unavailable, but ignore that for now :) )

1 hour ago, Aristy said:

4. Is it possible to "Observe" player.x and player.y data, and run an event whenever those attributes are changed? (e.g player.moving((player) => this.socket.emit("moving", player));

Yes, there are a few different ways. Getters and setters are probably your best bet.

 

1 hour ago, Aristy said:

5. When I develop monsters, should I develop every monster related information on backend? For example, "A monster cannot go out of world bounds in Phaser." if I configure it. But, a monster must be syncronized between all clients so it's data must be kept in backend. In this case, do I need to develop "A monster cannot go out of world bounds" feature on backend? How is it being done generally? First client hosts the monsters/AI and others just see what first client sees?

Again, depends on your game.

Link to comment
Share on other sites

1 hour ago, Aristy said:

1. Should I ditch Browsersync and rely on Nodemon? What is Nodemon? Can I just rely on a basic NodeJS server instead? Can I host everything (game files, socket.io connections) on port 80?

2. How do you install a NodeJS as a production backend? Do you need to rely on web services such as Nginx?

3. Right now my game makes a socket connection on Phaser.update, which means it transfers data 60 times per second. Would that be overkill or this is how it is supposed to work?

4. Is it possible to "Observe" player.x and player.y data, and run an event whenever those attributes are changed? (e.g player.moving((player) => this.socket.emit("moving", player));

5. When I develop monsters, should I develop every monster related information on backend? For example, "A monster cannot go out of world bounds in Phaser." if I configure it. But, a monster must be syncronized between all clients so it's data must be kept in backend. In this case, do I need to develop "A monster cannot go out of world bounds" feature on backend? How is it being done generally? First client hosts the monsters/AI and others just see what first client sees?

Thanks alot.

Matt deserves gold for his post. But, just to add, this is how easy it is for the nginx reverse proxying setup. And yes, using a reverse proxy whether it's nginx or haproxy infront of nodejs is a MUST. I use nginx just to take advantage of the rate limiting features. It will protect your server big league. A great library I use is https://github.com/jhurliman/node-rate-limiter which helps prevent packet dos as well. You can adjust those settings to fit your game (how much data does the client send, etc). I have it set to around socket.Flood1 = new RateLimiter(35, 'second', true); which works for a WASD style game (think of treasureArena).  

To expand on 3: I'd say 95% of the time it's overkill. For example if you have a player who can move with WASD.. when the player presses W and holds it down, you're not going to send down the entire keypress event through the server. You just need to send 0 or 1 each time. This is just one example though.

1 hour ago, Aristy said:

5. When I develop monsters, should I develop every monster related information on backend? For example, "A monster cannot go out of world bounds in Phaser." if I configure it. But, a monster must be syncronized between all clients so it's data must be kept in backend. In this case, do I need to develop "A monster cannot go out of world bounds" feature on backend? How is it being done generally? First client hosts the monsters/AI and others just see what first client sees?

Server shouldn't care if a monster is off the screen so no. That's all clientside stuff. You should be storing atleast HP, X,Y values on the server to validate server-side damage. Your monster synchronization is up to you and depends on the game. Instanced Based, MMO, or even if Peer to Peer based (which is a totally different ball-game)

 

Edit: When I say the server shouldn't care if a monster is off the screen that doesn't mean you shouldn't check the range between a player and a monster though :P

Link to comment
Share on other sites

4 hours ago, mattstyles said:

Nodemon is just a monitor (get it, nodemon?), it just restarts your process when it crashes, check out the docs. I normally use supervisor for the same requirement, its not that I've got anything against Remy I just like the feature set better :)

Port 80, yes you can, but I'll come to that in a bit.

Oh, I thought it was Browsersync/Livereload clone, which monitored my files and restarted the server.

Actually, I relied on all those tools before. HaProxy, Nginx, Apache, Supervisord, Redis etc. When I make our game a bit more production friendly, I'll most likely write a Supervisord conf and our classic monitoring services on top. (NR, Bugsnag etc.) I know the whole PHP ecosystem in this regard (my last app has millions of daily hits, for instance) however, coming to NodeJS was a bit weird experience, specially because I wanted to start with a boilerplate and then I had to configure that boilerplate. It is not rocket science (e.g Express' API is almost identical to some micro PHP frameworks) but the whole workflow got me a little confused.

5 hours ago, mattstyles said:

1. nginx works great as a reverse proxy , helping to separate the big bad outside world from my proces

Okay.

5 hours ago, mattstyles said:

2. nginx is great at serving static assets, node not so much, so it makes sense that for static client assets that nginx does the heavy loading and keeps my JS process clear to do what it is good at

I spent like a hour today with that today. As long as I can get rid of "app.use(express.static('build'))" nonsense I will be happy.

5 hours ago, mattstyles said:

3. nginx is dead easy to set up as a load balancing and I've rarely needed anything more

How do you scale a game written in nodejs/socket.io? Getting N amount of identical NodeJS/Nginx servers and putting a HaProxy load balancer in front of them?

5 hours ago, mattstyles said:

Depends on the game, I think many people throttle it to less. Also, when you say 'makes a connection', you mean 'sends a packet' right? websockets remain open, thats how the server can send you stuff. (socket.io falls back to polling when sockets are unavailable, but ignore that for now :) )

Sorry, it wasn't clear. What I meant was sending packets. My game will be a Trivia Crack clone so I don't need 60 FPS backend. However, before I start developing the actual game, I want to get my hands dirty with all the technology around, learn some good case uses so I can develop something quality for my company.

 

5 hours ago, mattstyles said:

Yes, there are a few different ways. Getters and setters are probably your best bet.

I was actually thinking about Object.observe. I'll think about getters and setters but I don't like the fact that you need to rely on getters and setters from now on. 

5 hours ago, mattstyles said:

Again, depends on your game.

Let's say we're developing a 2D top-down ARPG. Two players are trying to kill a Monster by shooting bullets, and that Monster has collision with players, obstacles on the screen, world bounds and bullets. Meanwhile, the AI chases the closest player, shoots players, collides with other objects.

If I kept every data about this monster on backend: then I should make sure I keep positions of obstactles on the backend too, otherwise collisions will be clientside.

If I keep data on client side, then there is a possibility that at certain frames (both player A and player B are 100 pixel away to monster. Monster chases A on A's game, but decides to chase B on B's game) may lead to incorrect data. Syncronization may be completely broken after few more frames.

If I keep data on player A's client, and simply publish everything to B (monster location, monster AI etc.) I feel like it would be better since I can develop AI directly in client, rely on Phaser's collisions without any hassle, and there is no way syncronization would be broken. (unless player1 logs out)

I'm trying to be a game developer (seriously, I feel like I've seen everything regarding generic web development and nothing provides challenge anymore) and there are loads of challenges here. From writing AI's to making multiplayer RPG games, dealing with latencies, or even installing NodeJS properly, lol.

Ps. http://rainingchain.com/, this is more or less the game I want to make when I get better.

Link to comment
Share on other sites

5 hours ago, WombatTurkey said:

Matt deserves gold for his post. But, just to add, this is how easy it is for the nginx reverse proxying setup. And yes, using a reverse proxy whether it's nginx or haproxy infront of nodejs is a MUST. I use nginx just to take advantage of the rate limiting features. It will protect your server big league. A great library I use is https://github.com/jhurliman/node-rate-limiter which helps prevent packet dos as well. You can adjust those settings to fit your game (how much data does the client send, etc). I have it set to around socket.Flood1 = new RateLimiter(35, 'second', true); which works for a WASD style game (think of treasureArena).  

To expand on 3: I'd say 95% of the time it's overkill. For example if you have a player who can move with WASD.. when the player presses W and holds it down, you're not going to send down the entire keypress event through the server. You just need to send 0 or 1 each time. This is just one example though.

Server shouldn't care if a monster is off the screen so no. That's all clientside stuff. You should be storing atleast HP, X,Y values on the server to validate server-side damage. Your monster synchronization is up to you and depends on the game. Instanced Based, MMO, or even if Peer to Peer based (which is a totally different ball-game)

 

Edit: When I say the server shouldn't care if a monster is off the screen that doesn't mean you shouldn't check the range between a player and a monster though :P

Do we have Reddit Gold feature in this forum? :)

We're playing a third party applications to for installing our servers and provisioning them. They give us all the security updates and do all performance tweaks in minutes. I'll check if they have a NodeJS installer though, otherwise I'll install everything myself.

Link to comment
Share on other sites

16 minutes ago, Aristy said:

If I keep data on client side, then there is a possibility that at certain frames (both player A and player B are 100 pixel away to monster. Monster chases A on A's game, but decides to chase B on B's game) may lead to incorrect data. Syncronization may be completely broken after few more frames.

To help with this (not a clientside solution obviously, what you said is indeed correct) -- Set a agro / lockon property for each monster object. During your monster AI loop,  assign the agro property to the player's id who is in range. Then, notify all clients that monster is aggroing towards that character.

This will be expensive though as you will need to track all x, y positions on the server.... This is just one way to do it though

 

 

Link to comment
Share on other sites

I meant to elaborate a little but ran out of time earlier:

1. Run everything through port 80?

Have a read of this, regarding 12-factor apps. It's a little heavy going and bare in mind that the company the initial author founded has a vested interest in encouraging those 12 factors, but, stick with it. I've been around the business for a long time and those 12 tenets will set you in good stead, at least to understand them. Also bare in mind that most of the companies I deal with on a daily basis produce a lot of different apps regularly and not many of them hit all 12. The following is something I have been thinking about writing up for a while, its kinda disjointed at the moment but hopefully it might help. edit: just seen your latest post as I'm writing so I'll condense, pretty sure you know most of this anyway.

Apps are processes that run, complex apps are a set of processes coming together, they are NOT a set of complex processes. Processes should be made as simple as possible, perfection is achieved when there is nothing left to take away. Node, C, python, whatever, its all just a process that runs that transforms inputs into outputs. Your node process, and whatever runs your client process in the browser are no different. The unix philosophy champions composability, so your processes are separate and distinct, from which you can create joins or couplings as you see fit. This is equally true of application programming as it is of architectural concerns.

So, to bring it back to the task at hand: I think to make this work well you need a build process (even with JS), something that takes your source and transforms it into something ready to run, this could be as simple as setting a few environment variables when your source is deployed, so long as it is reproducible and predictable you can do whatever you need.

To scale up your processes you either throw more compute power at the problem or scale horizontally by starting identical processes and using whatever balancer/routing you like to spread out the load. Those processes might rely on other services, such as authentication or managing a db or several, whatever, they all get joined together by your build and deploy tools. Containers (Docker, Rkt etc) can be a great help.

My usual setup for small apps would run something like:

Client source -> babel/browserify etc to produce executable code -> usually index.html, styles.css, main.js, assets. That stuff is usually purely client stuff so eventually it'll end up being served by nginx/varnish. The build process also sets some environment variables, I use envify so my JS can 'read' environment variables at build time, the build process then punts out dev or production builds. A deploy script then handles the actual deploy or docker build, additionally setting up any nginx/varnish conf depending on where it will be deployed to (my deploy environments are usually all the same anyway, for obvious reasons).

Server source -> sometimes this needs a transform too, which is particularly annoying for server code. Same thing happens, build process builds it and hands that stuff off to a deploy script/s to create docker/rkt instances or sets env and deploys somewhere.

Additional services -> all follow the same process. They are built by a repeatable automated procedure, controlled via env variables (or, at least, some sort of buildable config) to keep the code separate from the environment in which it will run.

Environment variables are created at build time which handles how these processes communicate.

If processes are thread intensive then I won't worry about sticking them on the same box and get concurrency through balancing on the same input, the proxy binds to 80 and distributes out. If they're CPU intensive then they go on separate boxes of course, or throw money at the problem. I've never had to have multiple balancers, but the process would be the same.

Sorry, realised this got hella long, and I'm still not sure I helped!

Link to comment
Share on other sites

10 hours ago, Aristy said:

I was actually thinking about Object.observe. I'll think about getters and setters but I don't like the fact that you need to rely on getters and setters from now on. 

Oh, Object.observe has been nuked, you could use a lib (probably some are still called a polyfill, but for a non-existent feature!) but presumably they just work by emitting events from setters. Proxies or Reflect might help, you'll need a shim for ubiquitous support for those and they sound a little like they might be overkill.

Link to comment
Share on other sites

I actually just started Phaser recently too, using that same boilerplate repo. I used this repo as the template for getting multiplayer working: https://github.com/xicombd/phaser-multiplayer-game

It was actually surprisingly easy to get working. Just run the server he has, and take the pieces from his client example (such as the event handlers and connecting to the server via socket.io) and stick them where appropriate in your own client. Then you can modify the events sent/received as needed for your game.

I am lucky in that the game I'm working on is tile based, and the user can only move from tile to tile (like Pokemon). I simply emit a "player move" event to the server every time a user begins moving to a new tile.

 

For your questions:

1. I am using Browsersync just fine for the client code. It came with the boilerplate repo we're using and hasn't been a problem. I had to update the gulp file to also copy over some new folders I added for assets and stuff. The repo I linked above for the server is using NodeJS it's basic built-in web server (not Express). It's running on port 8080 by default and haven't had issues. In production, my plan is to have the game server separate from the server serving pages and client code. I would guess most people do this. If you need to turn off the server for maintenance or whatever, you don't want your website to also go down. Same if your game server crashes for some reason. I am going to make the website with Laravel and host it at DigitalOcean on a VPS. I am hosting the NodeJS server on Heroku.

2. Again see the repo I linked above. Heroku makes it real easy - just git push to your heroku remote and it will auto deploy. You will have to do a few things like set your environment variables, use a database add-on if needed, and add a Procfile.

3. You won't want to make a new connection on every update. Make the connection once at load time and keep it open. I am not sure how games usually handle player movement data when players are free-moving. I would assume several times a second the client will send the player's current location and direction to the server if it has changed. 60 times a second is probably overkill. Once a second is probably fine.

4. Instead of seeing if they're moving this exact millisecond, maybe just store their old X,Y and see if it matches their current X,Y. If not, send the new one to the server.

5. If you want all clients to see the same NPCs in the same places, then their behavior is probably best handled on the server. Simply send data to the client saying to display this sprite at this location.

 

In general, you want as little to happen on the client as possible in multiplayer games. Allowing the client to set their own player's position without any checks, for example, is what leads to speed hacks. Allowing the client to manage NPC behavior and AI also means they can manipulate it do whatever and then your server isn't checking to make sure it's actually what it should have done.

I'm about to attempt to update that boilerplate repo to the most recent version of Phaser. Let me know if you've tried to update it too and ran into any problems!

Link to comment
Share on other sites

On 28.04.2016 at 0:54 AM, mattstyles said:

Have a read of this, regarding 12-factor apps. It's a little heavy going and bare in mind that the company the initial author founded has a vested interest in encouraging those 12 factors, but, stick with it. I've been around the business for a long time and those 12 tenets will set you in good stead, at least to understand them. Also bare in mind that most of the companies I deal with on a daily basis produce a lot of different apps regularly and not many of them hit all 12. The following is something I have been thinking about writing up for a while, its kinda disjointed at the moment but hopefully it might help. edit: just seen your latest post as I'm writing so I'll condense, pretty sure you know most of this anyway.

First of all, thank you for the amazing answer once again. I've never heard of this before. My last app (web based) conforms most of the articles. (not all)

On 28.04.2016 at 0:54 AM, mattstyles said:

Client source -> babel/browserify etc to produce executable code -> usually index.html, styles.css, main.js, assets. That stuff is usually purely client stuff so eventually it'll end up being served by nginx/varnish. The build process also sets some environment variables, I use envify so my JS can 'read' environment variables at build time, the build process then punts out dev or production builds. A deploy script then handles the actual deploy or docker build, additionally setting up any nginx/varnish conf depending on where it will be deployed to (my deploy environments are usually all the same anyway, for obvious reasons).

My flow is similar.

My app's root folder looks like this: /build/, /src/, /assets/, server.js

I start development by running npm start, which runs my customized Gulpfile. Gulp watches all the assets and generates /build/ folder. (e.g copy phaser, babel/lint/minify sources) Meanwhile Nodemon runs the server.js at port 80. I import Express/Socket.io/Hogan Express on server.js and enable Express to serve static files with expiration dates for static files. Then I listen for the GET "/" requests and render my ./build/game.html by passing certain parameters such as host, socketPort etc. The game.html has a script tag which then assigns those parameters into window object, and Phaser during Boot period reads those values and keeps them in my Config class.

When I'm done, I push to our private Github repository. A commit hook signals DeployHQ. DeployHQ deploys the game, runs the SSH commands I wrote, pings our Hipchat channel about the deployment. Also, Supervisord will always keep "npm start" up and running all the time.

Our server was provisioned using Serverpilot and had PHP enabled on port 80. So I temporarily had to stop Nginx from running so NodeJS can take port 80 on production. I'll check if there is a service which installs Nginx/NodeJS and configures it properly so I don't have to rely on npm on production.

I could do this myself, but as said, I'm still newbie on NodeJS so I don't even know NodeJS's configuration settings. For example, in PHP we have alot to configure (PHP, FPM, Nginx) so app works fast without hogging all the resources under high load. (Most of them are learned the hard way. ;D) I don't worry alot about scaling the game but having a proper production setup is my biggest challenge at the moment.

Meanwhile, my CEO had alot of research and we're currently discussing which apps/services we need to rely on. Can I get your opinions about those?

nLblVZp.png

Apart from those, we also talk about using Loopback instead of Express and WS instead of Socket.io. It is going to be a huge challenge for us to tackle them all but I'm sure we'll overcome it as long as I believe our stack looks good. What do you think about this? Do you have any suggestions (app, service, framework, *aas, anything) which may come handy?

Oh, I also have a question regarding my game. Yesterday I made a very basic game, where random gold icons appear in the world and they have collision enabled with Player sprite. It worked normal on my local environment but when I pushed it to production I realized I get more than 30 points instead of 1. It is because there is around 150ms latency so collision callback sends plently of packets in a short time before a response is arrived. (which kills the gold sprite)

I tried giving an identifier to golds, kept them in an array in server, whenever a packet arrived, I checked if identifier exists in the array, if so, removed it and gave points, otherwise just did a return to stop execution. However, I literally get flooded with packets since client sends a packet on every frame as long as there is a collision. Many of the packet requests pass "if identifier exists in the array" check before identifier can be removed from the array. Is it possible to solve it using a technique in backend without having to kill the Gold entity on first collision or throttle requests? I don't want to kill the Gold entity on first collision because it will be client-side and if both players collide with gold at the same time, both of them will trigger the kill event (where I play a sound) but only one of them will receive the points. They may act like "But I was the first, I heard the sound!" which becomes a big problem on high latencies.

I also have plently of more questions (like improving my current OOP model) but I'm not sure if I should create a new thread or just reply to this one. (EDIT: Nevermind, I will create a new topic with a more suitable topic name)

Thanks for all the help so far, I appreciate it.

On 29.04.2016 at 11:23 AM, mattstyles said:

Oh, Object.observe has been nuked, you could use a lib (probably some are still called a polyfill, but for a non-existent feature!) but presumably they just work by emitting events from setters. Proxies or Reflect might help, you'll need a shim for ubiquitous support for those and they sound a little like they might be overkill.

Yes, saw it on MDN after posting. :)

Link to comment
Share on other sites

You don't have to have node listen at port 80, things often complain about attaching to 80 when you aren't sudo anyway, you can fire up node to listen on any port and just make sure you route it through. I normally use nginx/varnish to handle the routing, then its fairly trivial to set up some other routing too, but I guess you could just use iptables or some other way. Ideally your deploy script should probably handle the port assignment and make sure things are set up right.

I have some other preferences on tech but I normally use all similar pieces to you. I'm a fan of LevelDB for fast key:value storage and rethinkDB for anything else but until you hit perf or dev issues there is little in it. I use Koa instead of Express as I prefer the middleware style, Express is more mature and the incubator status means it is probably 'safer' for a larger, longer-lived application. I've written wrappers for both Socket.io and WS with little to choose between them, socket.io is a wrapper on top of engine.io, which is a wrapper on top of WS so it depends how barebones you need/want to go with it.

I use pm2 to help start up processes, keep them running, report on them, persist them over restarts etc etc. npm spawns a new shell for each script which takes up some resources, you might want to ditch that step in production (to be honest, I'm not sure if pm2 relies on a subshell as well).

Sounds like you're building an exciting app, I hope the exciting bit refers as much to the game as it does to the tech :)

Link to comment
Share on other sites

1 hour ago, mattstyles said:

You don't have to have node listen at port 80, things often complain about attaching to 80 when you aren't sudo anyway, you can fire up node to listen on any port and just make sure you route it through. I normally use nginx/varnish to handle the routing, then its fairly trivial to set up some other routing too, but I guess you could just use iptables or some other way. Ideally your deploy script should probably handle the port assignment and make sure things are set up right.

I have some other preferences on tech but I normally use all similar pieces to you. I'm a fan of LevelDB for fast key:value storage and rethinkDB for anything else but until you hit perf or dev issues there is little in it. I use Koa instead of Express as I prefer the middleware style, Express is more mature and the incubator status means it is probably 'safer' for a larger, longer-lived application. I've written wrappers for both Socket.io and WS with little to choose between them, socket.io is a wrapper on top of engine.io, which is a wrapper on top of WS so it depends how barebones you need/want to go with it.

I use pm2 to help start up processes, keep them running, report on them, persist them over restarts etc etc. npm spawns a new shell for each script which takes up some resources, you might want to ditch that step in production (to be honest, I'm not sure if pm2 relies on a subshell as well).

Sounds like you're building an exciting app, I hope the exciting bit refers as much to the game as it does to the tech :)

Thanks alot for the response. I'll have a look at LevelDB but most likely we'll stick to Redis since our web stack consists it and we have some experience scaling it. I'll also make sure I check the rest of your stack and compare them to ours.

Well, I'm hoping so. I don't have alot of game development experience especially realtime multiplayer based ones but I'm doing my best to learn everything. There are loads of question marks in my mind but I'm solving them one by one and asking the ones where I need some expertise. I'm so glad for your replies. :)

If you don't mind, would you be able to reply to the "flood" part of my comment? I don't know what kind of tricks can be used to prevent that.

Link to comment
Share on other sites

Ah, the 'lots of messages' bit, can you move the logic around a little bit?

So that you only award points when the object is actually destroyed, you'll have to keep track of the destroyer in that case too.

Even better would probably be to only fire off the one packet when collision occurs, rather than all the time. Websockets are tcp (rather than udp) so you know they'll get there eventually but you could always ping out another sometime later if you haven't got a response.

Also, regarding the case of multiple hits on an object, I'm guessing this would be incredibly rare and is it really a problem? If your game involves collecting 9 coins and only ends when all 9 are caught then its going to matter if, suddenly, one player has 6 coins and the other has 5, but, if your coins are pretty much randomly spread around and there is some sort of other win-condition then distributing 'dual' points rarely probably isn't a problem (even though, technically, in the strict spirit of the rules it would be, but this isnt the olympics :)). In some cases awarding points to both players would be rewarding, its fun to think, "Hey, I just pipped that dude to the gold", when, in actual fact both players are thinking the same thing, so you've kept both players happy by bending the rules a little, so long as you weren't aware of the deception (i.e. if you didn't know your opponents score also raised) then, probably, all is good! Or maybe I am just sneaky...

If you're worried about latency then just remove the coin on the client but only award points to the one (or both) players so that the game feels more responsive than maybe it actually is. If your game relies on absolute accuracy or the chances of near-identical collision between multiple player and object are high then this approach probably won't be applicable, but it might be a good 'cheat' to get things feeling responsive.

There's an old Aussie proverb which might be relevant here:

"Don't let the truth get in the way of a good yarn"

Link to comment
Share on other sites

16 hours ago, mattstyles said:

Ah, the 'lots of messages' bit, can you move the logic around a little bit?

So that you only award points when the object is actually destroyed, you'll have to keep track of the destroyer in that case too.

Even better would probably be to only fire off the one packet when collision occurs, rather than all the time. Websockets are tcp (rather than udp) so you know they'll get there eventually but you could always ping out another sometime later if you haven't got a response.

Also, regarding the case of multiple hits on an object, I'm guessing this would be incredibly rare and is it really a problem? If your game involves collecting 9 coins and only ends when all 9 are caught then its going to matter if, suddenly, one player has 6 coins and the other has 5, but, if your coins are pretty much randomly spread around and there is some sort of other win-condition then distributing 'dual' points rarely probably isn't a problem (even though, technically, in the strict spirit of the rules it would be, but this isnt the olympics :)). In some cases awarding points to both players would be rewarding, its fun to think, "Hey, I just pipped that dude to the gold", when, in actual fact both players are thinking the same thing, so you've kept both players happy by bending the rules a little, so long as you weren't aware of the deception (i.e. if you didn't know your opponents score also raised) then, probably, all is good! Or maybe I am just sneaky...

If you're worried about latency then just remove the coin on the client but only award points to the one (or both) players so that the game feels more responsive than maybe it actually is. If your game relies on absolute accuracy or the chances of near-identical collision between multiple player and object are high then this approach probably won't be applicable, but it might be a good 'cheat' to get things feeling responsive.

There's an old Aussie proverb which might be relevant here:

"Don't let the truth get in the way of a good yarn"

Okay, thanks for the clear explanation!

 

 

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...