Creating a multiplayer 3D shooter on Webgl without experience and money
This is the first part of the story about how a small team of web developers developed a multiplayer 3d shooter without experience in gamedev, big money and staff.
Disclaimer: some of the solutions described in this article may cause facespalm.

In 2011, we were a small St. Petersburg web studio of 4 people. Timlid / Seoshnik, programmer (or rather considered himself a programmer), designer and sales manager. At that time, the team leader and programmer had been engaged in websites for 3 years, but did not achieve much success in this field. Although we already had several regular customers on promotion and service, the lion's share of the income was eaten by taxes, office rent and other expenses. The remaining cents for four people was clearly not enough. Chronic lack of money and lack of prospects depressed. The designer has already speeded up the skis, and the rest of the team barely held on. It was in such an atmosphere that the idea that was amazingly naive came to my mind: “Why are we all doing projects for all uncles, and let's do something of our own, for example, a browser game and we will burn it on VKontakte”. Everything except the designer,
Like most "beginner" game developers, they decided to do MMORPGs. I must say that none of us had any experience in gamedev. Except for the small lineage2 freechard that the programmer kept and finished home-made chronicles there. Doping was mainly limited to server game data; there wasn’t enough for more - neither intelligence nor knowledge. One way or another, it gave some ideas about the server side device. The experience of administration and communication with the contingent of players was firmly convinced of one thing: you cannot trust the client - everything that can be done on the server must be done on the server.
Let's get back to our project.
Responsibilities were distributed as follows:
Timlid - became a game designer;
Manager - took over the sound;
Programmer - remained a programmer.
Initially, it was assumed that this would be a kind of mixture of fallout and looter (on the 7.62 engine), with isometry, but real time.
The scene was supposed to be post-apocalyptic St. Petersburg.
The technical implementation was then presented as follows: The
game location consists of img and div tags.
The overlap was set by a z-index, which was calculated based on the position of the object along the y axis.
There was no character; his duties were then performed by a white square.
Communication with the server through comet connections.
Management through mouse clicks.
Comet connections were quickly abandoned in favor of web sockets. Then they were still completely raw and were not supported by half of the browsers for which the flash crutch was stuck (then we naively believed that a beta release is possible in six months or a year and cross-browser compatibility is needed now).
When all this was realized and the square character learned to move around the screen, a new task surfaced - it was necessary to somehow limit the freedom of its movement. It was decided to mark the boundaries of objects using stop segments, as well for the future, separate types of segments were provided that block shooting and visibility.

When clicking with the mouse, a line was drawn from the current coordinates of the character to the point of click. Further, all stop segments were checked for intersection with the route segment. If no intersections were found, then the client received the coordinates of the destination point and started moving, the same process took place on the server. But in case of intersection, the character remained motionless. From this the following task arose - finding a workaround.
It took many days and nights to find a solution. At first there were attempts to do a real-time search, but an acceptable speed of calculations was not achieved. Then, googling, we decided to use pre-calculated ways. To do this, point points were placed at the corners of objects and a generator was written that looked for all possible routes from each point to each, then the shortest one was selected from them, which was recorded.
Now the server, if it is impossible to go in a straight line, took all available points from the departure point and from the destination point, selected all the routes connecting them, and from them already selected the shortest one and started moving. Now the square famously maneuvered between all the obstacles itself, and most importantly, the calculations now took a split second.

There were closed areas inside the objects that it was impossible to get into, but it didn’t bother much
The turn has come to visualize the character. The difficulty was as follows: It was assumed that the character can have 3 positions - standing, sitting, lying and all this was multiplied by 8 orientations in space.
Various types of weapons were supposed: pistols, rifles, machine guns and various armor.
The first thought is to do it all on sprites, but even with the new-fangled css3 transform, the number of sprites seemed enormous, and the possibilities for customization are very limited. We began to look for other solutions. Something was needed to draw the character on the fly.
Such a solution was found - WebGL .
The first experience was the designer of games CopperCube. We exported an empty scene with an animated character and stuck it in its entirety instead of a white square. When running, the corresponding animation was turned on, the character rotated in space, as you like. Not bad, but can the whole scene be built on WebGL?
The decision was made and it remained to choose a tool. CopperCube was a ready-made designer engine, but closed, paid, and how to make a network game in it, and even with server side mechanics, was completely incomprehensible.
We needed something lower level that would allow us to create our own game mechanics, but at the same time save us from working with WebGL directly (no one understood anything in our team in 3D programming then).
Having tested a number of libraries, we stopped at three.js. Despite the fact that the documentation was then slightly better than nothing, there were a huge number of demos on the network where you could see how certain things were being done. Actually, this determined the choice.
The rest of the year was spent on transferring the client in 3D.

Editors of objects and maps were also ported.

Almost a year has passed since the start of development, but the results have not yet been impressive. Gamedise gave out ideas, outline the interface, a description of the characters and future locations, but it didn’t reach the embodiment. There was no intelligible plot at the beginning either. There was a general idea - as a result of an apocalypse, or a sudden unknown attack, clear water became worth its weight in gold. And they decided to call the game on this basis WasteWater (sewage).
The manager, who took upon himself the sound, did not start working, he also stopped working on sites, and as a result, our paths diverged. So two of us remained from the original composition.
But most importantly, we didn’t have game content, moreover, there wasn’t even an idea where to get it.
The obvious became obvious - MMORPGs never will be done by our forces.
Then they decided to simplify everything to team shooting. In general terms, the game should now look like this:
Lobby, where the player could deal with such things as: buying equipment, equipping a character, pumping skills.
Battle mode, where the player was hit by pressing the red button "To battle".
They left the top view, and decided to redo the management on WASD. Looking ahead, I’ll say that WASD turned out “not like everyone else”. If usually with this form W is always up, and S is always down, then we have everything regarding where the character is looking. Such control is unusual, but it gives more tactical opportunities and you get used to it after a couple of fights.
The gameplay was supposed to become more dynamic, so the character's lying and sitting positions were thrown out.
Only the key feature remained the same - all locations should be based on the places that actually exist in St. Petersburg.
This did not solve the problem of lack of content, but significantly reduced the minimum amount required for launch.
We started to rewrite the client. By summer, a lobby prototype with working equipment was ready. The character has so far been taken from action quake (mod for q2, grandfather cs).

All summer was spent on the combat system. The WASD control was screwed on top of the old mouse-pointing control system: the character pathfinding was disabled, and the click point was emulated in front of the character at a certain distance. If the player moved the mouse or the character reached the calculated coordinates, then the point was calculated again. Pathfinding is useful for mobs. Their models were also taken from some q2 mode. A primitive AI was written, chasing the player, but all the main work to achieve the goal was done by the pathfading system. Despite all the primitiveness, the observation of this artificial life was bewitching.

The shooting was attached, still silent and flameless, but the mobs could already be mowed in bursts, and they learned to bite painfully in response.
The attack / shot algorithm was also based on segments and checks for suppression - a conditional segment was taken from the shooter to the maximum range of the current weapon and collisions were checked. "Living" objects are also indicated in the form of crossed segments.
In general, by the fall of the prototype was more or less ready.

Meanwhile, the game design did not waste time in vain and combed the sites where ready-made 3D models were sold in search of content suitable for us. He managed to collect something, but this was not enough.
With reduced costs, we got some free finances and decided to hire freelancers.
The first order was a new character with animation. And the first pancake, as usual, came out lumpy - taking the advance the contractor did not show anything intelligible by the agreed date. If we only knew what fairy-tale characters we still had to work with ...
By the end of the year, we found artists who made us a character and animated it, but a new problem surfaced. The fact is that from 3DsMax in which the work was done, at that time there was no direct export of animation to three.js, so I had to use md2 as an intermediate format, which was already distilled into native json via an online converter.
In addition to the drawbacks common to frame-by-frame animation — heavy weight, and memory consumption, md2 had one more thing — vertex coordinates were rounded, which led to the whole model floating. This was not so noticeable on the low-poly Quake characters, but on ours, more detailed, it looked just disgusting.

Exporting somehow differently failed to get an extraordinary volume with which the browser simply could not cope, giving out "shit." Then we were not mentally ready to redo everything again, and indeed there was still no clear idea of how to redo it, so we decided to leave it as it is for now.
We were also unlucky with 3D environment modelers. At first they took up the new lobby, managed to make it grief in half - only from the second freelancer.

Started working on the first map. Initially, they wanted to use the Ozerki metro station and the surrounding area, but abandoned this venture at the design stage. The fact is that this area has a significant height difference, and although the client has become three-dimensional, the server logic has remained 2D. In other words, the situation when a character stands on top of a mountain and shoots a character standing at the foot, while the bullets fly not down, but high above the target’s head, looked ugly.
A flatter place was needed, and the intersection of Lanskoye Shosse and Omskaya Street was chosen as such a place, except for the high-voltage power lines passing through it.
We marked out the location plan for Yandex.Maps and switched to implementation. We started with a sketch of the future terrane, a new web designer took up this work. The area of the real territory was about a hectare and soon the designer had to improve the computer, because the old two-core with 4GB of memory could not cope with the amount of data.
This has already hinted that simply pulling a single texture onto a plane will not work, unless of course the quality is squeezed to the state of laundry soap. We decided to cut everything into small pieces and assemble it like a mosaic, repeating segments where possible. Tile, decals? No, we did not know such words then.
The card assembly was mainly dealt with by gamedes, becoming, in combination, also a level designer. As it turned out, collecting a card in this way was very difficult. The slightest mistake led to the fact that half the card had to be reassembled again. Self-written editor, which was more a tool of torture than a development tool, intensified the suffering.

With a titanic effort, the map was nevertheless collected.
In parallel with the work on the map, work was underway with sound. A pair of tracks were purchased for the lobby and the combat mode.
The author of these tracks ordered other game sounds: shots, steps, and the like.
Background music was simply hung on the audio tag, and game sounds were implemented through the new-fangled web audio api, which at that time was still raw and supported only in chrome and its relatives, but it already provided rich opportunities, in particular, it allowed positioning the sound in space in accordance with the position of its source in the 3D scene.
May 8, 2013 we launched prealpha testing on living people. There were few experimental subjects, but they still managed to collect some feedback and play by themselves.

1. The animation system must be changed;
2. An obstacle system built on stop segments does not work well: players cling to subtle obstacles;
3. The manual stroke itself is labor intensive and does not fully correspond in the case of complex geometries;
4. There is no scalability - you have to sort through all the stop segments available on the map;
5. Terrane mosaic of planes draws down FPS, and joints are visible everywhere;
6. The full server-side movement of the character on the real Internet does not work as well as we would like - the delay between the click of a button and the reaction of the game is visually visible;
7. Grafon as a whole is "niochen".
It became clear that almost everything needs to be redone. But a negative result is also a result. Mostly all this gave at least some experience and understanding of how to do it.
The next year and a half, we reworked our game, but more on that in the next article.
Work on the game continues, only the main of the plans is implemented.
Screenshot from the lobby in 2015:

Screenshot from the map “Spit of Vasilyevsky Island” 2015:

Thank you for your attention.
Disclaimer: some of the solutions described in this article may cause facespalm.

2011. How it all started
In 2011, we were a small St. Petersburg web studio of 4 people. Timlid / Seoshnik, programmer (or rather considered himself a programmer), designer and sales manager. At that time, the team leader and programmer had been engaged in websites for 3 years, but did not achieve much success in this field. Although we already had several regular customers on promotion and service, the lion's share of the income was eaten by taxes, office rent and other expenses. The remaining cents for four people was clearly not enough. Chronic lack of money and lack of prospects depressed. The designer has already speeded up the skis, and the rest of the team barely held on. It was in such an atmosphere that the idea that was amazingly naive came to my mind: “Why are we all doing projects for all uncles, and let's do something of our own, for example, a browser game and we will burn it on VKontakte”. Everything except the designer,
Like most "beginner" game developers, they decided to do MMORPGs. I must say that none of us had any experience in gamedev. Except for the small lineage2 freechard that the programmer kept and finished home-made chronicles there. Doping was mainly limited to server game data; there wasn’t enough for more - neither intelligence nor knowledge. One way or another, it gave some ideas about the server side device. The experience of administration and communication with the contingent of players was firmly convinced of one thing: you cannot trust the client - everything that can be done on the server must be done on the server.
Let's get back to our project.
Responsibilities were distributed as follows:
Timlid - became a game designer;
Manager - took over the sound;
Programmer - remained a programmer.
Initially, it was assumed that this would be a kind of mixture of fallout and looter (on the 7.62 engine), with isometry, but real time.
The scene was supposed to be post-apocalyptic St. Petersburg.
First steps
The technical implementation was then presented as follows: The
game location consists of img and div tags.
The overlap was set by a z-index, which was calculated based on the position of the object along the y axis.
There was no character; his duties were then performed by a white square.
Communication with the server through comet connections.
Management through mouse clicks.
Comet connections were quickly abandoned in favor of web sockets. Then they were still completely raw and were not supported by half of the browsers for which the flash crutch was stuck (then we naively believed that a beta release is possible in six months or a year and cross-browser compatibility is needed now).
Obstacles
When all this was realized and the square character learned to move around the screen, a new task surfaced - it was necessary to somehow limit the freedom of its movement. It was decided to mark the boundaries of objects using stop segments, as well for the future, separate types of segments were provided that block shooting and visibility.

When clicking with the mouse, a line was drawn from the current coordinates of the character to the point of click. Further, all stop segments were checked for intersection with the route segment. If no intersections were found, then the client received the coordinates of the destination point and started moving, the same process took place on the server. But in case of intersection, the character remained motionless. From this the following task arose - finding a workaround.
Obstacle avoidance
It took many days and nights to find a solution. At first there were attempts to do a real-time search, but an acceptable speed of calculations was not achieved. Then, googling, we decided to use pre-calculated ways. To do this, point points were placed at the corners of objects and a generator was written that looked for all possible routes from each point to each, then the shortest one was selected from them, which was recorded.
Now the server, if it is impossible to go in a straight line, took all available points from the departure point and from the destination point, selected all the routes connecting them, and from them already selected the shortest one and started moving. Now the square famously maneuvered between all the obstacles itself, and most importantly, the calculations now took a split second.

There were closed areas inside the objects that it was impossible to get into, but it didn’t bother much
Webgl
The turn has come to visualize the character. The difficulty was as follows: It was assumed that the character can have 3 positions - standing, sitting, lying and all this was multiplied by 8 orientations in space.
Various types of weapons were supposed: pistols, rifles, machine guns and various armor.
The first thought is to do it all on sprites, but even with the new-fangled css3 transform, the number of sprites seemed enormous, and the possibilities for customization are very limited. We began to look for other solutions. Something was needed to draw the character on the fly.
Such a solution was found - WebGL .
The first experience was the designer of games CopperCube. We exported an empty scene with an animated character and stuck it in its entirety instead of a white square. When running, the corresponding animation was turned on, the character rotated in space, as you like. Not bad, but can the whole scene be built on WebGL?
The decision was made and it remained to choose a tool. CopperCube was a ready-made designer engine, but closed, paid, and how to make a network game in it, and even with server side mechanics, was completely incomprehensible.
We needed something lower level that would allow us to create our own game mechanics, but at the same time save us from working with WebGL directly (no one understood anything in our team in 3D programming then).
Having tested a number of libraries, we stopped at three.js. Despite the fact that the documentation was then slightly better than nothing, there were a huge number of demos on the network where you could see how certain things were being done. Actually, this determined the choice.
The rest of the year was spent on transferring the client in 3D.

Editors of objects and maps were also ported.

year 2012. Lower the bar
Almost a year has passed since the start of development, but the results have not yet been impressive. Gamedise gave out ideas, outline the interface, a description of the characters and future locations, but it didn’t reach the embodiment. There was no intelligible plot at the beginning either. There was a general idea - as a result of an apocalypse, or a sudden unknown attack, clear water became worth its weight in gold. And they decided to call the game on this basis WasteWater (sewage).
The manager, who took upon himself the sound, did not start working, he also stopped working on sites, and as a result, our paths diverged. So two of us remained from the original composition.
But most importantly, we didn’t have game content, moreover, there wasn’t even an idea where to get it.
The obvious became obvious - MMORPGs never will be done by our forces.
Then they decided to simplify everything to team shooting. In general terms, the game should now look like this:
Lobby, where the player could deal with such things as: buying equipment, equipping a character, pumping skills.
Battle mode, where the player was hit by pressing the red button "To battle".
They left the top view, and decided to redo the management on WASD. Looking ahead, I’ll say that WASD turned out “not like everyone else”. If usually with this form W is always up, and S is always down, then we have everything regarding where the character is looking. Such control is unusual, but it gives more tactical opportunities and you get used to it after a couple of fights.
The gameplay was supposed to become more dynamic, so the character's lying and sitting positions were thrown out.
Only the key feature remained the same - all locations should be based on the places that actually exist in St. Petersburg.
This did not solve the problem of lack of content, but significantly reduced the minimum amount required for launch.
We started to rewrite the client. By summer, a lobby prototype with working equipment was ready. The character has so far been taken from action quake (mod for q2, grandfather cs).

All summer was spent on the combat system. The WASD control was screwed on top of the old mouse-pointing control system: the character pathfinding was disabled, and the click point was emulated in front of the character at a certain distance. If the player moved the mouse or the character reached the calculated coordinates, then the point was calculated again. Pathfinding is useful for mobs. Their models were also taken from some q2 mode. A primitive AI was written, chasing the player, but all the main work to achieve the goal was done by the pathfading system. Despite all the primitiveness, the observation of this artificial life was bewitching.

The shooting was attached, still silent and flameless, but the mobs could already be mowed in bursts, and they learned to bite painfully in response.
The attack / shot algorithm was also based on segments and checks for suppression - a conditional segment was taken from the shooter to the maximum range of the current weapon and collisions were checked. "Living" objects are also indicated in the form of crossed segments.
In general, by the fall of the prototype was more or less ready.

Content
Meanwhile, the game design did not waste time in vain and combed the sites where ready-made 3D models were sold in search of content suitable for us. He managed to collect something, but this was not enough.
With reduced costs, we got some free finances and decided to hire freelancers.
The first order was a new character with animation. And the first pancake, as usual, came out lumpy - taking the advance the contractor did not show anything intelligible by the agreed date. If we only knew what fairy-tale characters we still had to work with ...
By the end of the year, we found artists who made us a character and animated it, but a new problem surfaced. The fact is that from 3DsMax in which the work was done, at that time there was no direct export of animation to three.js, so I had to use md2 as an intermediate format, which was already distilled into native json via an online converter.
In addition to the drawbacks common to frame-by-frame animation — heavy weight, and memory consumption, md2 had one more thing — vertex coordinates were rounded, which led to the whole model floating. This was not so noticeable on the low-poly Quake characters, but on ours, more detailed, it looked just disgusting.

Exporting somehow differently failed to get an extraordinary volume with which the browser simply could not cope, giving out "shit." Then we were not mentally ready to redo everything again, and indeed there was still no clear idea of how to redo it, so we decided to leave it as it is for now.
year 2013. First results
We were also unlucky with 3D environment modelers. At first they took up the new lobby, managed to make it grief in half - only from the second freelancer.

First location
Started working on the first map. Initially, they wanted to use the Ozerki metro station and the surrounding area, but abandoned this venture at the design stage. The fact is that this area has a significant height difference, and although the client has become three-dimensional, the server logic has remained 2D. In other words, the situation when a character stands on top of a mountain and shoots a character standing at the foot, while the bullets fly not down, but high above the target’s head, looked ugly.
A flatter place was needed, and the intersection of Lanskoye Shosse and Omskaya Street was chosen as such a place, except for the high-voltage power lines passing through it.
We marked out the location plan for Yandex.Maps and switched to implementation. We started with a sketch of the future terrane, a new web designer took up this work. The area of the real territory was about a hectare and soon the designer had to improve the computer, because the old two-core with 4GB of memory could not cope with the amount of data.
This has already hinted that simply pulling a single texture onto a plane will not work, unless of course the quality is squeezed to the state of laundry soap. We decided to cut everything into small pieces and assemble it like a mosaic, repeating segments where possible. Tile, decals? No, we did not know such words then.
The card assembly was mainly dealt with by gamedes, becoming, in combination, also a level designer. As it turned out, collecting a card in this way was very difficult. The slightest mistake led to the fact that half the card had to be reassembled again. Self-written editor, which was more a tool of torture than a development tool, intensified the suffering.

With a titanic effort, the map was nevertheless collected.
Sound
In parallel with the work on the map, work was underway with sound. A pair of tracks were purchased for the lobby and the combat mode.
The author of these tracks ordered other game sounds: shots, steps, and the like.
Background music was simply hung on the audio tag, and game sounds were implemented through the new-fangled web audio api, which at that time was still raw and supported only in chrome and its relatives, but it already provided rich opportunities, in particular, it allowed positioning the sound in space in accordance with the position of its source in the 3D scene.
Prealfa
May 8, 2013 we launched prealpha testing on living people. There were few experimental subjects, but they still managed to collect some feedback and play by themselves.

According to the results of prealpha, the following conclusions were made
1. The animation system must be changed;
2. An obstacle system built on stop segments does not work well: players cling to subtle obstacles;
3. The manual stroke itself is labor intensive and does not fully correspond in the case of complex geometries;
4. There is no scalability - you have to sort through all the stop segments available on the map;
5. Terrane mosaic of planes draws down FPS, and joints are visible everywhere;
6. The full server-side movement of the character on the real Internet does not work as well as we would like - the delay between the click of a button and the reaction of the game is visually visible;
7. Grafon as a whole is "niochen".
Total
It became clear that almost everything needs to be redone. But a negative result is also a result. Mostly all this gave at least some experience and understanding of how to do it.
The next year and a half, we reworked our game, but more on that in the next article.
Work on the game continues, only the main of the plans is implemented.
Screenshot from the lobby in 2015:

Screenshot from the map “Spit of Vasilyevsky Island” 2015:

Thank you for your attention.