📜 ⬆️ ⬇️

History of participation in the Game Jam. Snowbox

image At the end of 2017, I had the opportunity to test my strength and enthusiasm as a participant in one of the many world-wide Game Jams.

Since this was my first experience in a similar project, I learned a few useful lessons and a couple of pleasant surprises. Well, I also received a toy that you could play with your colleagues on the pre-Fridays.

Under the cat a description of how the intensive 30 days of development and the slow 20 days of waiting for the results.

Note: The article is a narrative, with a small amount of technical details.

Prologue


I have long wanted to try myself as a game developer, and in the last year this desire became more and more obsessive. By the end of the year, I decided to start doing something - to attend game development meetups, read books, and even make a small prototype of the game.

So one day Selim, my colleague, offered to participate in one of the numerous Game Jam and I thought that this was the best opportunity to explore the game kitchen without any long-term commitments. This is not a prototype, but not a long-running Project. In addition, tight deadlines are often one of the best motivators. And the main advantage is that the output in any case is something holistic and complete, which always inspires new achievements.

So we decided to take part. Two java-developers, absolutely no experience in igrodelaniya. But you need to start sometime?

Training


The selected Game Jam was thematic, and the organizers had to announce the topic strictly before starting the development. The contestants were given 1 month to create the game.

We registered a week before the start and, due to the lack of a topic, spent time with anxious waiting and inaction. Perhaps it was better to spend this time choosing a genre and game mechanic. And then wrap it in the appropriate style.

At hour X, the organizers announced the contest theme - Throwback (return back) and the countdown began.

Selim had the only wish for the game - the presence of a game server and necessarily real time. He was interested to learn the charm and complexity of the development of the server part. Also, the game was supposed to be simple, otherwise we could not have time to complete it.

Regarding the topic, thoughts were first about either retro or prehistoric times. The retro theme is not interesting to me, so I tried to invent something about dinosaurs or ancient people. However, I was not able to come up with something simple and multiplayer on this topic.

And then I came up with the idea to make a sandbox game, while literally - a reference to children's entertainment on the beach. We build castles, run and rush into rivals with sand (I hope not everyone had such a difficult childhood), well, disgruntled parents are punished for it. All this in 2D with a top view.

Selim thought that it was too cruel in the eyes and suggested replacing sand with snow, and castles with ice fortresses. On this option, we stopped. As time and effort we could add new functionality and variety.

Development. Week 1


Our roles in the project are divided by themselves. As I said, Selim was interested only in server development. And I was interested in trying to develop UI, because, in my opinion, it is the most different from developing business applications. The interface of the game was planned web.

Brief description of the technologies used
Client-server interaction was completely built on web-based software because we needed to send messages from the server to the client asynchronously and regularly. Messages from the client were also transmitted via a web socket, but simply because of the “why not”. All messages were in Json format.

A Spark micro framework was used on the server for working with web sites. And as a physics engine, box2d was used, as one of the most popular. He was responsible for calculating the physics on the server.

The client was written in pure JS, without using any frameworks, since I am not strong in them, besides, this makes little sense for a small project. Phaser 2 was used as a game engine - a young and promising JS engine. Unlike the physical engine on the server, its main purpose was graphics and simple physical calculations. KnockoutJS was also used for data binding .

The IDE used products from JetBrains: Intellij IDEA and a trial version of WebStorm (just a 30-day version, at the time of Game Jam).

Development began with a joint meeting at the weekend. In the first 2 hours, I picked up "temporary" sprites and implemented a running boy who could throw snowballs. There could be a “was / became” picture, but it is devoid of all sorts of meaning - visually what it was, then it remained.

Having a working UI, it remained only to fasten the server interaction. Therefore, the rest of the day was devoted to integration: discussion of the API, setting up the connection, implementation of the interaction. By the end of the day, our little man could move 1 pixel to the side, when you press a key. It was a modest, but still a success.

Further development continued only in his spare time, with 6 days a week separately at home, and one day off together. This was quite enough thanks to a simple API and a rigid distribution of roles.

To repeat the success of the first day (run and throw snowballs), but through the server, it took us a week. Many technical factors equally influenced this, including problems with tools that were poorly designed for our client-server interaction model. I would like to dwell on this model in more detail.

Client-server interaction model


Initially, it was decided that the server would be responsible for any movement, and the client would only send commands, such as pressing a key, and draw what came from the server. Later this philosophy was slightly refined, but the server remained central to the end.

In the first implementation, the server sent updates to the client every clock cycle. Those. for example, if a key is held down, the player’s position changes every few milliseconds and a new position is sent to the client.

With the help of such a simple algorithm, we implemented the player movement. But striving for the best prompted us to change the algorithm to an event one: only important events sufficient for synchronization are sent to the server, as well as to the client.

For example, for a player to move up the map you need 4 events:

  1. Client : up key pressed;
  2. Server : the player began to move from the point [x, y1 ], at an angle α, at a speed ν;
  3. Client : key pressed up;
  4. Server : the player finished moving at [x, y2 ].

This approach has both advantages and disadvantages.

Minuses


pros


From these lists it is clear that if you work hard on the implementation of the client, then there are practically only advantages. For our project we managed to achieve this and the client-server interaction worked without any complaints. But we must pay tribute, it took quite a lot of strength and nerves.

Development. Weeks 2 and 3


After a week, when we managed at the very least to master integration and make support for several types of messages between the server and the client, it was time to add something more to the game than just a running boy.

Therefore, we decided to add a running girl! Along the way, I had to make a character selection window for the girl. And since the window still had to be done, it’s a sin not to add the input of the name. In addition, I had to stretch the images, by analogy with the 9-patch approach .

image
It looked like the first version of the login window

Because of all this, such a simple and important task of adding a girl, took away a couple of evenings, but it was clearly worth it. And then gray days with similar tasks went on: new simple functions, error correction, minor visual improvements.

As my progress progressed on the client side, the problem of uneven server and UI development speeds up. And since the server is a central part of any interactions, without the ready and working functionality on the server, the development of the client has stalled.

Therefore, I implemented a simple mock server right in the client. Many things in it were implemented very clumsily, incl. through the use of the global state of the game world. This was enough to develop a UI completely independent of the server and saved me a lot of time.

The mock server had another definite plus. There were bots in it that could not shoot, so there was a chance to win at least someone.

Selim at this time struggled with the server. On the server, he connected the physics engine box2d to simulate physics in the game. This engine has a lot of nuances, and their study took a lot of time. The biggest difficulty in developing was the lack of visualization of the game world. Our client rendered only what was needed. And some elements of the "server world" were hidden from the client side. In addition, there were no complete guarantees that the client renders everything correctly.

One of the important subtasks that Selim had to solve was the checking of collisions of objects. On the client, collisions were checked only for fixed elements. On the server, it was necessary to do everything in an honest way so as not to infringe the rights of moving objects.

During the development of collisions, I remember one funny bug that could claim to be a special functional: when a player threw a snowball, he was thrown back by “return”. This happened because in box2d, by default, anyone can collide with everyone, and repulsion always happens.

This problem was solved by the introduction of masks, i.e., an indication of classes of objects that cannot collide with each other. For example, for a player and his snowballs, the mask was made the same.

Selim decided not to waste time on special handling of collisions of snowballs with each other and marked this collision with a comment:

// for the unlikely event that we collide with a sibling snowball

As practice has shown, the frequency of this "unlikely" event tends to the frequency of throwing snowballs, because when you are facing each other, the trajectories of snowballs coincide. Because of this, other people's snowballs constantly beat off with their own. Our opinion about this behavior diverged, so we left as is.

While Selim was having fun with collisions, I debugged the synchronous movement of objects on the server and client. There were minor bugs in our own implementation, but Phaser presented the biggest surprise. In his physics engine, the real speed of the objects is adjusted to the FPS and stop the world. This is done to improve the smoothness of the movements. Unfortunately, this smart behavior did not agree with synchronous work with respect to the server and had to do its own implementation of moving objects.

Description of the specifics of the speed in the Phaser or "race with a shadow"
In order to check and debug speed, I added another player object to the card, which moved at conventionally the same speed, but nearby. This shadow player and normal player used different motion algorithms. And so I arranged the competition and compared the stability of speed.

At first I tried to solve the problem of uneven speed with the help of the engine settings and physics that we use. But, as I understand it, this behavior does not change. It was possible to switch to a more complex implementation of physics, but did not want to do this for the sake of speed alone. In addition, this implementation also did not give an absolutely stable speed.

The next step I tried to implement moving objects myself, but from the engine I took control and the time delta between each cycle of the world. In Phaser there are several models of time and on one of them just the standard implementation of speed is based. But, for some unknown reason, not one of these times has any stability and they cannot provide constant speed. This is a known issue and is not planned to be fixed in version 2: github.com/photonstorm/phaser/issues/798 .

I spent 2 days on the “competition” of the player and the shadow and never found a working variant. Therefore, in the end, I did all my processing speed based on standard time in JS. It is very surprising that such an important function received such strange support in the engine and had to sell its own bicycle.

With such jokes and jokes, we have passed the second and third weeks imperceptibly. In addition, each week began with the phrase “well, by next week we must prepare a playable version” - every time it seemed to us that we were just about to be ready. The complete lack of experience and the presence of tremendous optimism is the worst way to estimate timelines.

A week before the change, at the developer meeting, we could not even show the normal version and had to show the mock server.

Of course, with such a speed of development there was nothing to dream about the originally conceived list of functionality, and even more so about nice to have things. Therefore, we had to forget about the "sandbox" and stop at the simplest 2D shooter.

Development. Week 4, last


In the last week of development, we focused on fixing bugs. It is better to have something modest and working than a multifunctional, but falling apart. There were many problems and most of them dealt with ill-fated integration. Here and there, small flaws popped up, greatly worsening the impression of the game.

In addition to fixing bugs, I also brought a final gloss to the UI: adding music and sounds, playing with fonts and improving small details.

Of all the functionality, this week was added only a system of points, as well as limiting the stock of snowballs and their restoration.

On the last day of Game Jam, we managed to play a little with our colleagues. Despite the general positive feedback, this gaming session was unsuccessful because of a critical bug - the snowballs were flying on the server and on the client at different speeds. Because of this, hitting other players was more of an accident.

Description of the cause and correction of the error
This bug we made at the last moment, reducing the number of FPS on the server from the experimental 1000 to 100.

It should be noted that up to this point, we did not manage to achieve fully synchronous movement on the client and the server - there were occasional jumps in motion. By changing the FPS we tried to increase server responsiveness.

When I began to investigate this bug, I discovered 2 patterns:

  • player movement worked correctly and steadily;
  • Snowball movement on the client has always been faster than on the server.

The value of the speed of objects comes to the client from the server, i.e. it could not be a banal mismatch of values. Also, the reverse increase in FPS to 1000 improved the situation.

I spent a lot of time trying to correct this error. But nothing helped. And in the end, the reason was found with the help of Google - box2d indirectly limits the maximum speed, moving the object to no more than 2 pixels in one step of the world. Those. at 100 FPS, the maximum speed is 200 pixels / s (p / c), and at 1000 FPS - 2000 p / s. This value is specified in a constant and cannot be changed dynamically. This fully explained the reason for the slowing down of our snowballs, since their speed should have been 700 p / s, which required a stable FPS above 350.

To fix this problem, I increased the FPS to 500, but for a reason. In box2d, the step function of the world needs to be transferred how much time has passed since the previous step. Before my change, we always calculated this difference before calling a function. But now, knowing the desired frequency, one could always indicate a constant delta of 2 ms. With a strong time lag from the real world, the steps had to be repeated one after another, until the time of the world caught up with the lag. Then a little sleep and everything is new.

This fix, as expected, solved the snowball speed problem. In addition, we finally have a problem with non-synchronous movement on the server and client. At that time, this miraculous healing was a complete surprise for us, but now I understood the reason: despite the maximum 1000 FPS, no one has canceled the slow operation of the server, and especially the garbage collection. Those. at some points in time FPS could freely fall below the required 350 FPS, which led to arbitrary speed jumps.

So, happy from the closed bug and working toys, 2 hours before the deadline, we were ready to surrender. It remained only to send the game to the project site.

I expected the game to be laid out smoothly and in vain. It was necessary to create a project page, make a description, distribute screenshots and much more. We managed to, as expected, butt. Although later, the organizers still individually accepted late projects.

image
Screenshot with the final version of the game

Voting


Under the terms of the contest, immediately after the completion of the development, a 20-day vote was opened. During this period, anyone could see the submitted projects, of which more than 200 had accumulated. Only participants were allowed to vote for the projects. Each game could be assessed in the following categories: general, graphics, sound, gameplay, innovation and relevance to the theme.

The voting stage has prepared for us a bad surprise associated with the multiplayer nature of our game. People watching the game, there was relatively little and the chance to meet the enemy sought to zero. Those. people came to an empty map, threw a couple of snowballs, ran a few meters and left in disappointment.

We tried to organize game sessions through the project forum. Also, Selim and I occasionally entered the game, hoping to entertain the bored lonely wanderer. It all gave almost no results.

It was interesting to watch some people test the game. I especially remember the case when a player entered several characters at the same time and built a pentagram of boys. I do not know what the author wanted to say, but I still have a screenshot from the process of its creation.

image

Another player "hacked" our game. We have a name length check, but only on the client side. Accordingly, he bypassed this protection and began to correspond with me in this way, each time entering a new character, and writing his phrase in the name of the little man.

Simultaneously with the vote, my colleagues and I played again, taking revenge for the unsuccessful game on the day the project was handed over. This time everything went very smoothly and we got a number of ideas on new features, which, however, it was too late to add.

In my opinion, the quality of the game, especially in terms of interaction with the server, turned out to be very good. No matter how many times we played it, we didn’t notice any problems, nor did we hear them from other players. For me personally, this was a surprise, given the quality and number of errors a few days before delivery.

20 days, the data on the evaluation of games, stretched for a very long time, but in the end they ended and the long-awaited time for results came.

image

Thus, we took 36th place out of a little more than 200 participants. That, on the one hand, is not bad for the first project, but on the other hand, it is somewhat unpleasant for vanity. Especially considering that the top 10 got good games, but not all of them deserved some special attention.

Lessons learned


For the sake of receiving lessons in semi-greenhouse conditions, this was all started. We tried to invent many things ourselves and limited ourselves to a minimum set of tools in order to experience problems and experience bad approaches in our own skin. But now having a knowledge base on how to do it is not necessary and why, it will be easier to study the theory.

The need of the artist . As practice has shown (not only ours), you can make a good game, without good graphics. However, selecting the right pictures, fonts, and user interface elements takes up most of the time. And the worst thing is that in the end they do not coincide with each other. From this, the warm lamp atmosphere is lost and the game does not look complete.

Game tests are very important . Due to problems with the speed of development, we could not test the playability of our implementation most of the time. When we were able to play normally, there was too little time to fix the problem areas. And we were very lucky that there were not so many such problems.
In my opinion, for games such tests on real users are much more important than for business applications, since, in addition to user convenience and problem solving, a certain level of emotion and involvement is also required.

Not all libraries are equally useful . Almost no one develops games on its own engine and there are engines for all occasions on the market. It was 2017 in the yard, and one would have expected their high quality. I chose the Phaser as one of the most recommended and young JS engines. After all the problems that we had with him, I am afraid to imagine how the engines look worse. No, on the whole, the impressions of working with Phaser are more likely positive, especially considering good documentation and examples. But working with him, not knowing a lot of nuances, is very hard. In the spring there is a new version and I hope for significant improvements. And also in my plans there is a mini-project on some other engine to compare.
And I will remember that problem with the maximum speed in box2d for a long time.

In the process of Game Jam it is quite possible to learn . Starting this project, we knew almost nothing about game development, or about the libraries we used. And most of the time was spent studying these things. Despite this, we still managed to bring the game to a completed state.

Not mandatory a lot of functionality . I'm a little surprised that many people like our game. Yes, they do not sit in it every evening, but enjoy one or two small sessions. But in our game there is neither an original idea, nor a large amount of functionality, nor any history. The same can be said about most of the games in Game Jam, which received positive ratings.

(Game) Jam is a great reason to try . It does not matter what: the idea, the new library, their strength. When there is a clear goal and your result should be seen by others, it is very motivating not to limp and give all the best. And even if the result turns out to be worse than expected, it will not be a pity to throw it away, draw lessons for yourself and move forward!

Links to resources:



Thank you all for your time and good mood!

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