I would advise to create your own server for your game like you did with NodeJS. Most of the solution I know are quite hard to use and cannot do eveything you want to.
For example, Blizzard game's Hearthstone is based on Unity for the client and have a custom made server side.
Here are some advice on how to create your game server.
It seems to work fine until the physics part comes in: the server must trust the clients when they say there's something being hit or explode, then broadcasts it to the other clients.
When creating your server you must make every important decision server-side and not client-side.
It is the server who start the party, so the server must have the following information
- The size of the map
- The number of player
- Data about each player (Health point, position, size, attack speed...)
- Any other information required to make decisions
Now, the client should always send very small signal to the server like the following
- Move left
- Join party
- Shoot
- Rotate right
- etc...
Based on user's action and user's data, the server can run a "simulation" of the game.
- Check if the action is allowed
- If it's allowed, simulate the action. If it's not, put it in a queue
- Send to users informations about what is happening (Player one hit, player two dies, player four moves left etc..)
With this, the server knows when something happens and decide what happens. You do not rely on client side information, you only recieve the player's desired actions.
However, as you said, because of latency and other network factors, your client cannot be too dependent of the server. In modern games, the client have the same data about the player than the server and do not always rely on the server to display on screen what is happening.
If you played some online games, you may have noticed that when a connection with the server is lost, there's a small amount of time during which you can continue to play (move, shoot, etc..) but nothing moves except you.
This is because the client continue to "run" the game based on your action even without server's informations.
However, to avoid any huge difference between what is displayed by the client to the player and what is happening in the server's simulation, the client and the server "synchronize" at regular interval.
For example, if you decide to move left, the client knows your move speed so it can display the movement without relying on the server.
When the synchronization occurs, the server send to the client critical information and the client change any currently displayed informations with what the server send.
Whith the left movement example, if your movement speed is different on the server and on the client, when the client receives a synchronisation order, you'll notice that your player will be "teleported" from the displayed position to another. This can also occurs if some packet are lost or because of high latency.
Handling lantency is a huge challenge when creating an online game both on server and client side and it's not the topic of this question.
To summarize, your server should
- be homemade
- Only receive actions from clients
- Simulate the game
- Send clients information about what is happening
- Synchronize at regular interval with clients
Hope this help =)
Here are some explanation on how to add logic inside your server.
Small disclaimer before, I've never used NodeJS so I don't know if this is achievable using NodeJS, I usually use C++.
Now for your game, I'll assume that the player can only use the action MOVE.
When a user connect to you server, you can launch the game.
Because your user can move, it means that there's a 2D map, that your user have a size and an initial position and a speed.
So your server should start a new "GameParty" and initialize the above data.
For the example, let's assume the following defaults value are set.
map_width = 512;
map_height = 512;
user_width = 2;
user_height = 2;
user_speed = 1;
user_posx = 20;
user_posy = 20;
When a client wants to MOVE, he send a packet to the server saying he wants to move. You can use any protocol you want for client<->server communication, I use a binary protocal but let's say you use Json
{action: move; value: left};
With this, your server will know that the user wants to move to the left.
So, you just have to decrease user_posx
by the value user_speed
to have, server side, your new position. If this position are on the edge of the map, you have two choice, making the user appear on the other edge of the map of forbid the action.
At regular interval of time, your server will send to the client the player's current position.