📜 ⬆️ ⬇️

Browser online game development

Hi, habrovchane. My name is Eugene, by profession I am a backend developer and I write in c # in the segment of enterprise applications. In this publication, I want to tell you about my experience in a field that is not quite relevant for me - the development of video games, and more specifically, about the development of a browser-based online game.

I'm used to referring myself to those lucky people whose hobbies coincide with work - I love software development. Therefore, it is absolutely normal for me, after returning home, to sit at the computer again, open Visual Studio and continue to develop something — I do not need a rest from this activity. There is only one problem - I need a project that interests me and that I could manage alone in my free time - in the evenings and on weekends.

About a year ago, I was shown a fairly popular browser-based online game - sliterio. After reading, I had an obsession - I wanted to do something similar in approach, but with a little more advanced gameplay. After a couple of months, the idea was formed in the theme of this publication - the game World of Frogs.
')


The essence of the game - you control a frog, you can attack other players, as well as computer-controlled objects - flies, cockroaches, marsh frogs. Flies do not know how to attack and die with one blow, cockroaches attack only defensively, marsh frogs attack both flies and players.

Defeating the enemies you gain experience, grow in levels, learn new abilities and become stronger.

The main points from which I repelled:

  1. On the client side, no Flash , only html + js ;
  2. One machine should pull as many online players as possible;
  3. The possibility of horizontal scaling;
  4. Low threshold of entry into the game and quick start;
  5. Slightly more varied gameplay than sliterio;
  6. Beautiful and memorable domain;

Further details on each of the items.

1) Client code


I did not want to get bogged down in inter-browser differences, as well as in the implementation of primitives, so I immediately pushed the idea of ​​working directly with the canvas away — I started by searching for the graphic library (of course, free).

Initially, the view fell on pixi.js - this is the engine, on which a lot of documentation, which is positively responded in terms of performance and generally praise in every way.
However, delving into the search, I stopped at phaser.js (there were already articles on Habré about it) - this is a higher-level library that allowed me to forget about many nuances and focus directly on the game logic.

The engine made it possible to screw animations, background texture, camera, world borders and much more without any problems. And everything would be fine, but when it came time to check the work on other computers, with other operating systems, the following problems emerged:

1.1 The main problem is the background texture (tilesprite) terribly slow on windows 7
I found this out from the work computer after the first deployment to the hosting - the FPS was very, very low - around 5 . And so it was in all browsers except, surprisingly, IE - everything worked pretty well in it, albeit not perfect.

I didn’t think about the fact that it slows down the background at once - first of all, I found out using the typing method that the game suddenly stops braking when the browser window size decreases. I did not manage to google something for such symptoms, so I, for the sake of prevention, decided to introduce some of the practices that the Mozilla guys advise - in particular, the use of the Object Pool (reuse of game objects). I haven't achieved much success with this kind of optimization, and the profiler still showed that rendering consumes the most resources.

Then, resorting to the gradual disabling display of various elements of the game, I identified the culprit - tilesprite .

Going along tilesprite, I found out that I don’t have one problem, and the reason is that the canvas is redrawn completely with any change - i.e. the small object has moved - we redraw the entire canvas, including the background, which gives us a high drawing expense.

In an attempt to solve this problem, I rendered the background on a separate canvas with a smaller z-index so that it was redrawn separately, regardless of moving objects — it did not give any special results.

In the end, I decided to abandon phaser.js and work directly with canvas created to render the background - as a result, the FPS has grown to about 20 .

1.2 Different phaser versions - different performance in different operating systems
After changing the principle of rendering the background with performance, everything became much better, but 20 FPS - this is still not the desired 60 - there was something to be done. By poking a finger into the sky, it was found that phaser version 2.4.6 runs faster on windows 7 , and version 2.6.2 runs faster on windows 10 . On both Linux and Mac, both versions performed equally well.

I had to add a condition that connected one or another version of the library depending on the user's browser - this increased the FPS on my working machine to 25-30 . I never managed to raise the FPS higher - I decided to stop at this, because after interviewing friends / acquaintances who have a seven, the impression is that the problem is rare and not so serious as it was originally.

Described in these two points are not the only ones, but the main and most remembered problems associated with phaser.js - everything else went smoothly in general.

It is also worth noting that on different machines with windows 7 the performance was different - in some places and without all my gestures everything was fine, somewhere there were problems similar to what I watched - I could not establish any correlation

2) Performance of one instance of the game server


Here it’s worth starting with what is the overall architecture of an application that serves as a game server. It was decided to use the following scheme:

In parallel, messages are received from different players via websocket and laid to process the main thread, which updates the game logic. The main stream works by iterations of 40ms , within which it updates the movement, visibility, respawn NPC, the progress of the use of abilities, etc.

Data is written to the database asynchronously - the game logic update stream lays the messages into a queue to another background thread, which groups them and writes them into the database in batches.

Serialization and sending messages to players also occurs asynchronously - the next background thread deals with this, to which messages are written to the processing queue as part of the iteration, and at the end of the iteration, messages are grouped for each user and sent to the client in a bundle.

If you map on the diagram, then the top-level server architecture looks like this:



Since I had more experience with the backend, there were no particularly memorable difficulties here - I caught the non-optimal places by a profiler - somewhere I applied micro-optimization of calculations, somewhere caching, somewhere optimization of a different kind.

The most serious boost to performance was the rejection of the use of SignalR , because it does not support the binary protocol, and the json serialization required more computing resources than the rest of the logic of the game server combined. Stopped as a result of using Fleck , because it supports the binary format, and also allows you to disable the Neigl algorithm.

3) Possibility of horizontal scaling


Being an optimist, I decided to plan in advance that everyone would like the game and would like to play a lot of people in it. Within the framework of one machine, you can work on optimizations for a long time, you can upgrade the hardware indefinitely, you can rewrite the application on a pure C with assembler inserts for micro-optimizations, but anyway, sooner or later you will come to the ceiling. It was decided to have an architecture that allows you to have a lot of low-power servers, each of which has an online ceiling of around 200-300 people.

In order not to have a bottleneck in the form of a network up to any one global proxy, as well as to ensure minimal ping, it was decided on the site side to select one specific server with a minimum of online, assign it to the user session and continue to ensure browser interaction user directly with the game server.

At the moment, in the choice of server from the pool, simple logic is used - the server is taken with a minimum of online. In the future, it is also planned to add logic to the accounting of the location of the client and server.

4) Low entry threshold and quick start


I have often had to see games that simply have to have the worst conversion due to interface congestion, or because of the need to enter a million fields in order to enter the game.

I wanted to provide one click input from the main page, i.e. no registration required. The same approach uses a similar approach, for one small difference - they still want the player to enter a nickname.

Since An online game usually implies the ability to distinguish one player from another, I decided to use the no-generation approach - when entering the game, a random adjective from a predetermined list is taken and combined with a random noun, which gives the nicknames Sleepless Bugay, The Greedy Chipmunk, etc. P…

image

In the future, if a player likes the game, he is given the opportunity to register, retaining his progress, and also changing his nickname to something more sane.

For a quicker immersion, an instructional video was added to the main page, and the tooltips were added to the game itself, which emerge when learning new abilities.

5) Slightly more diverse gameplay than in sliterio


As a former fan of the game WoW, I wanted to diversify the game, bringing into it such elements as a set of experience, growth in levels, obtaining new abilities as they grow, PvE, PvP.

The player is available to use 6 abilities (1st available immediately, 2-4 become available as they grow in levels, and 5-6 are designed as disposable power ups - they can be raised on the playing field):

  1. Beat the tongue - the frog shoots his tongue and causes little damage to the first target on the way;
  2. Jump - the frog jumps in the indicated direction and causes high damage at the landing site. High damage ability is compensated by the complexity of the hit, as well as a long delay between uses;
  3. Shield - for 3 seconds absorbs 2 next enemy attacks;
  4. Spit - a frog spits out a projectile, which inflicts medium damage to all enemies on the trajectory of movement);
  5. Healing - restores half the life;
  6. Acceleration - increases movement speed by 100% for 4 seconds;



To be able to stand out a bit, the ability to choose another model of the game character was added.

6) Beautiful and memorable domain;


Initially, the plans were to place the game on the .io domain , similarly to sliterio, agario and many other games of this format. The commonplace frog.io and frogs.io were busy, but something more appropriate in .io could not be found. Playing with domains containing frog, I came across a very successful option - frogs.world , on which the project now lives. A rather unusual first-level domain, but easily remembered.

Thanks for attention. I hope that my experience will be useful to someone.

Source: https://habr.com/ru/post/331852/


All Articles