Ahoy, I'm Jhomas, a Canadian game developer starting out making online cooperative games, which are my favourite genre (if it counts as one?). Co-op SNEK Online is, if you haven't guessed, a local and online cooperative snake game with levels, achievements and various game modes. You eat dots to get long and try not to die. There is also a friendly competitive mode where you try to get long enough to beat your friends by blocking them in.
SNEK (as I will refer to it from now on), is available on steam if you would like to give it a go!
The rest of this post is intended to shed some light on the process of making a multiplayer game and give you some easy tips to get going more quickly!
A quick aside: SNEK is a cooperative game. It is not Call of Duty, WoW or anything of the sort. It is a game you play with friends, likely while talking via discord/skype etc. Because of this, a TONNE of concepts and worries from most networking tutorials can be thrown away. I used this to my advantage as much as possible, but it took me a while to realize what concepts I could toss and which I should keep. Therefore, the rest of this article is mainly applicable to online cooperative games.
Concepts to Discard
With the above in mind, let's toss out some concepts we don't need!
You are all friends, if someone is cheating, just let them, it'll probably be funny.
The Distrust of Your Peers
You can trust your peers to be sending you valid data and events. Peers can do their own hit detection against power ups etc, and tell everyone else when they get them. So long as you keep the overall game state (what level you are on, points, doors that are open/closed) authored by the host, leave the rest up to the individual peers.
Because we trust our peers, let them dictate where they are and what they are doing! Don't send along inputs to the host etc, just have every peer control their character as normal and then send the x/y to all other peers.
I do NOT mean that lag is fine and you don't have to deal with it / think about it. I mean that you don't have to do the whole "move players backwards in time to correctly hit test bullets etc" as, you are all on the same team and you care about the fairness of your own local state, not the fairness of the entire networked state.
Game / Room / Instance / Alias
Construct has the concept of games, rooms, instances and user aliases. This is very flexible and can let you make any type of online game, but for our purposes we want to make connection as simple as possible. We want people to be able to play with two things: a room name and a password. Enter those into two text boxes, hit go and you're playing.
To accomplish the above, we need to "condense" the game/room/instance/alias logic into two user facing strings, we can do this by:
- Alias: A random number `str(random(5000000))`
- Game Name: Whatever you like, your game name + your favourite animal let’s say
- Instance: This is the password entered by the host who setup the game
- Room: This is the room name entered by the host who setup the game
- Max Peers: 4 / The max # of people in ANY game configuration. Don't bother with a # of players picker, just let anyone join who has the correct combo.
I'm sure I have horrified some people with the above as most of it goes against 100% of the guidelines set out by any network engineer. My only defense is that networked games are hard. I'm sure everyone has played at least one game with very obviously bad/buggy network code. People can't connect, some players don't load the right level, a player gets stuck, someone's clothes/armour is wrong or just completely missing, people flying through the air etc.
This is why I say throw out EVERYTHING you don't need. All those concepts we just tossed is weight off our shoulders, both in our minds and in our game’s code. If you need any of those concepts, use them, but again, in our friendly co-op game we don't!
Where do we go from here?
We just threw out or condensed a large portion of Construct’s multiplayer game features, some of which are quite integrated into the multiplayer plugin. So how are we going to make a multiplayer game with syncing players, power ups, collisions and all the rest? Well, we continue to break rules.
The first thing we need to do is create a system to easily call a function on every players’ computer. You can do this by broadcasting a reliably ordered message (with a tag) of the function name + all the parameters in a string to each player. Even if you're making a different type of multiplayer game, this functionality is quite useful!
We have all the peers playing out their games as if they were playing single player & sending along their positions to all other players. Each player stores this newX/newY. Then on every tick interpolates each player (ala `lerp()`) from the current x/y to the new x/y. You can also send along the velocity of each player to better update the physics/movement vectors which can help with collision detection etc.
And That's It
With these two systems in place you can more or less make a whole game. In SNEK when a player collides with a dot locally, they immediately eat it and send a message to everyone else to destroy the dot and start the eating animation. In this case I don't care if two SNEKs eat the same dot somehow, I just ignore that fact and they both get points. However, if this was a key or unique item I would likely either: Continue to let two people have the item (this is a "happy bug" anyways) or give it to the player who joined first / has the highest alias #. I would not resort to having specific code that has to check who on the hosts machine got there first. I avoid that sort of host checking as much as possible, as every extra time you require it, it needs both host specific and peer specific code.
Fun Tips for Your First Multiplayer Game
A lot of getting better with networking game code is practice, a change of mindset and testing with friends. Besides these (hopefully) obvious things I will try to outline as many quick tips for getting a online multiplayer game out the door.
Budget double the time
As soon as you take a game idea and decide to add online multiplayer, think of your game as two games, at once. Two games = twice the work.
Make a few tiny test games & play them with your friends
This can be said for most things: start small, really small. Consider making online multiplayer games a whole new skillset. Even if you are comfortable with Construct, try to take the time to make a few tiny terrible games and play them with your friends. This experience alone will show you a lot of the big problems you will inevitably face ie: disconnects, lag, people being unable to connect, game state desyncing, having games blow up spectacularly etc.
Deal with lag sooner rather than later
Lag can break the game state, lead to janky / wrong collisions and just make your game look bad. Your first playtests will almost definitely run into this, but you can find these issues when testing locally by using Constructs built in `simulateLag` functions! These are not a perfect simulation but they still do a great job of making what you thought was great network code crumble!
Don't also make it have local multiplayer
If you do, add one to the total number of games you are making. You're at three now by the way (I did this without realizing).
While testing join a room/game automatically
This will easily speed up your development twofold. Remove those text boxes and just always rejoin the same game/room name on startup when some debug variable equals 1!
Remember how we are somehow making three games now? We should now be testing three times as much to compensate. This can be difficult to set up, but your testers WILL see and find oddities in both the game and the online experience that testing by yourself never will.
Remember what type of game we are making
SNEK was able to do away with almost all of the host checking functionality because the game contains almost no keys/locks, has very few game states and is designed to only be played amongst friends. If you are going to let people play publicly or in any way competitively, this will change your outlook on how the multiplayer should be architected entirely. It can be hard when you are starting out, but accepting that not all advice/tutorials are applicable to you and your game can be a huge leg up!
In the beginning I just took Constructs multiplayer tutorials, ripped them apart and put them back together as the games I wanted to make. This worked to a point, but eventually I needed to really dig in and understand how everything was working both in the Construct multiplayer plugin and in the ether of the internet. The links below will get you started!
A great read on how an old game discovered and dealt with all the fun issues the internet presents
The Internet Sucks: Or, What I Learned Coding X-Wing vs. TIE Fighter
This guide is really good, who knew!
Construct Multiplayer Concepts
Super set of posts that provide a primer on everyth