Skip to main content

Darek Greenly

Personal blog, expect game dev and web stuff

Multiplayer JavaScript game dev log #1

As a guy who used to create tiny, tiny games, I thought that adding “multiplayer” to my tool-belt could be the next step forward. JavaScript is the main language for me now (as I got hired as web developer) so Node.js is the way to go. But… I quickly remembered the last time I wanted to create something with Node.js - sweat, pain, some sleepless nights and unfinished apps. Maybe that was just my ignorance back then, and general lack of discipline? I watched couple of courses about Node.js to refresh my knowledge and opened up new window in Visual Studio Code.

Yeah… Multiplayer Javascript

So whats the plan? Express? How do I WebSockets, client connections, rooms, server-side, client-side, i hit my face with both open hands in despair again. I imagined all the work that will need to be done BEFORE actually making any game or “app”. Quick google for “multiplayer game server node js” revealed to me couple of bootstrap options.

Pomelo (which I believe I saw earlier somewhere) looked mature, but after opening their GitHub issues It was clear to me that I wouldn’t fit their community - most of the issues were in Chinese.

Lance was next in line. Went through the features list - lookin’ good! But let’s continue the research.

Then I found Colyseus. I admit, I fell for the “match-making” point from their feature list. This feature could probably be done with more or less time in other engines too. It has a client-side JS implementation in different repo, It also has client integration with Unity3D and Construct2. Colyseus is new, right now at version 0.5, still being worked on… Ah, what the hell! Let’s clone that example and see how it works. I don’t have that much time to prepare a full-blown research with pros and cons of each library.

So in couple of hours I managed to make a working chat room. My example project uses Webpack with webpack-dev-server for the client-side code, to speed up development and manage my js/html code better. I try to follow all the rules and good practices now, can’t allow myself to write spaghetti code anymore. So I start writing with ES6 and use neatly arranged modules. After a minute I hit that roadblock again:

import something from 'path'
^^^^^^

SyntaxError: Unexpected token import

Node doesn’t understand import… Let’s transpile it! Should I transpile it? That’s adding another build tool, more time, more complexity… Quickly I broke the cycle of though and found this article ”Don’t transpile JavaScript for Node.js”, and I also got a reply on Twitter, extending on this topic:

tl;dr - use require/module.exports, leave transpiling for the client-side code.

So I did. And with clean heart I could continue.

Gameplay

What kind of game I could create now? Recently I’ve designed Monstrous Escape, I’d love to play this game online with someone :) But first things first, let’s start smaller please. Don’t let that be ANOTHER project with overflowing list of TODO features never-to-be-finished… How about a simple “war” cards game. The rules are simple, every player is dealt with cards, each round they show their topmost card on the pile, the player with higher card takes all cards until one player is left with no cards in his deck. The game is really simple and really boooring to play in real life, but in code it manifests itself as an already thick layer of complexity. There are a bunch of object here: Player, Card, Deck, Pile. Those last two are actually the same thing, Containers of cards, but both will be rendered differently in the browser. There should also be a round cycle.

I got my notebook and drew out some basic interactions between objects in any state of the gameplay. I want it to be universal. It should be easy to use that “cards API” to create any kind of cards game - using classic set of cards or any custom tabletop/boardgame kind of game. Maybe this tiny API will evolve into “tabletop API” someday? Tabletop Simulator JS! … one can dream.

Stop! React time.

So I’ve got this chat module, which works but is essentially still a spaghetti code. A tiny perfectionist inside me wonders “what could we do to make it better and scalable?“. A rhetorical question, he already knows the answer. A colleague from our office talked a lot about React and Redux recently. I practiced some React days ago but never gotten to use Redux. I needed to store every piece of information in one neat package, only one. No more storing variables around many different classes, modules, files. With React, I can write “dumb” components, whose job is only to visually present the data from state, and with Redux I’m managing the state itself. Before I go any further I just had to re-write what I currently had - tiny chat app - and use React/Redux combo.

I opened redux.js.org and before finding installation instructions I noticed that they have a big list of free “Getting started” videos. Watched them all, feels good.

For now I’m sure that I’m going to use React on the client-side of the code. On the server-side Colyseus already has some kind of state machine that I could use. I just used my recent knowledge of reducers and wrote a couple of those to manage a list of: players, cards, containers and various game state variables…

After couple of days I realized that It was a bad idea.

RTFM or ask for help…

I’ve lost a couple of days trying to understand, why some state changes were not sent to the client. Colyseus has a setState() function, which I assumed is to be used when I want to update the whole state. So I wrote my server-side reducers logic all around it… and nothing happened. Only the initial game state was sent to the client, only once the client joined the room. Nothing else.

I have a tendency to just go boldly into the example code, without reading any documentation. I just go back to it, when a function name is not fully self-explanatory or when I know I need to achieve something, but I don’t know what function to use. This time I made the same mistake. Unlucky for me, Colyseus is pretty new and they don’t have a full documentation on it, only some example code and tutorial. But my code still didn’t work, so I went to their gitter chat as my last resort:

hey @Zielak, setState should be used only once, whenever you use it, the client will receive only one big "add" operation. To receive detailed information the state should be mutated

MUTATED! That’s my problem, I manipulated server-side state the same way I did with Redux on the client - “replace, don’t mutate”… Changing 1/4 of my server code to be mutations finally gave me some results. In the below video you’ll see one client - host, the other client is off screen. Only the host can start the match, but both players can increase or decrease that silly test number.

Colyseus game working with 2 players.

To be continued.

At first I wanted to write one post about my progress from start to finish. As it turns out, there’s a long way from here to that finish line. I kept writing this draft bit by bit, it stayed in “unpublished” posts for a couple of days now. I’m just going to post it, and mark it part 1 of that multiplayer  javascript cards game attempt!

See you later.

Comments