📜 ⬆️ ⬇️

How many times have I not abandoned the development of my second game


Picture to attract attention

Reassured after the shock of the fact that my first game did not explode the Internet, I decided to make another one. The first thought, with which the development of the second game began, arose in my head and without deliberation became the cornerstone in the foundation of the game: “if a game with endless gameplay did not become popular, then you need to make a content-dependent game with levels”.

Since I already had a little experience in creating a game, I armed myself not with a keyboard, like last time, but with a pencil and paper, and I began to “invent” the game. On different A4 sheets, I wrote down my thoughts in different directions: game mechanics, the setting, the interface, the rules, interesting thoughts, memorable games from childhood, and so on; at the same time I am parallel to the wool of the Google Play Market looking for inspiration. In the end, after a few days, it was decided that the game would become a puzzle, namely, a puzzle. During this time, my brain and fingers were bored with programming, as a result of which I wanted to make at least some kind of prototype game. This led me to a more intensive elaboration of the idea of ​​the puzzle, and as a result the variant with the following rules was adopted as a worker: the playing field consists of square puzzle pieces (hereinafter referred to as tiles), on which multicolored lines are placed; tiles can be interchanged; goal of the game: to assemble a puzzle in the only way in which lines of one color are closed in a certain pattern.

Tip number 1: write down everything that comes to mind (on paper, in the diary, on the phone (as a temporary storage I liked Google Keep), anywhere), and then repeatedly filter, selecting the most valuable.
')

Prototype


The prototype was written on a bunch of html + js (used canvas) for a couple of evenings. Since I haven’t done anything serious on canvas before, it was decided to bribe in order to get more in-depth acquaintance with this technology.


Fig. 1. The first version of the prototype.

It does not look very, I know. It is for this reason that all my motivation quickly faded away, and the game was abandoned for several months. Abandoned, but not completely: I continued to write down all the game ideas that came to my mind, and sometimes I reread them.

At the same time, in order to somehow justify my inaction, I began to constantly read various near-game articles. Habr (articles and digests of the gaming industry with collections of articles) and some popular sites with articles from the world of game development helped me in their search.

Tip number 2: a quick transition to programming without a sufficiently developed paper prototype can knock out for a long time. If this happens and you cannot bring yourself to return to the project, then continue the work indirectly: the easiest options are reading articles about game development and writing down thoughts.

Drawing - cardinal change of activity


After several months of inactivity in the field of creating a game, I quit my job. The decision to leave matured long ago and in no way connected with the creation of the game, but thanks to the appearance of free time I was able to return to my project. Returning to the game again, I realized that her meager appearance strongly demotivates me. I coped with this problem by arming myself with several graphic editors: having painted a slightly more beautiful design, I killed several birds with one stone:

1. Changed the occupation.
2. Increased faith in myself (I myself drew design for the game).
3. Invented that the lines can be roads, and tiles - pieces of land. So began to emerge the essence of the game.
4. I saw that the center of the tile must be closed by some image, since different options of roads were ugly docked in the center. So in the center of the tiles appeared at home.

Tip number 3: take a break from programming, change your occupation (designing on paper, thinking through monetization, design, game mechanics, reading) otherwise you can quickly cool off to the Idea. Changing the type of activity in the initial stages can reveal problems or subtleties that need to be dealt with at the start of a project.


Fig. 2. When the design of the game is a programmer.

It doesn't look much better, but if it helps to continue working on the project, then why not.
Further, the prototype was supplemented with the basic functionality of the game: a screen with a list of levels and a screen for directly passing levels were created. But in order to pass different levels, they must first be created. And I gladly tried myself in a new role - I started creating levels.

Each level was carefully preserved in json-format until the size of the levels grew and it became difficult to edit them. I had to deal with an extraordinary task: the creation of a level designer. It was the simplest editor, from which I copied the json level and pasted directly into the code of the game (brrr, I apologize to all readers for this horror). But the frequent thoughts that the code and architecture of the game (and the architecture of the designer in particular) are not perfect, forced me to redo many pieces of the game again, and sometimes several times.

Tip # 4: re-read your code; look for what can be simplified, improved, accelerated. This will not only keep your interest, but make your code cool.

Development


Summer came and with him I had a strong desire to find a job. I moved to sites with vacancies, began to send my resume five years ago to different companies and in the process of this lesson I realized that over 5 years the industry has changed a lot, and all this time I lived in my cozy little html and jQuery. After reading the requirements for vacancies and talking to recruiters, I realized that I did not know the new products, which did not allow me to feel confident in my abilities.

It was necessary to do something, and I took up self-education, while not forgetting about the game. Guided by the requirements for vacancies, I made a list of technologies, tools and other frameworks, which, in my opinion, I should have met, and began to study them. First, I initialized the git repository in the project directory. After a day of work, I could not imagine how I used to work without him. Then he began to divide his overgrown super-object, which contained all the logic of the game, according to the modules of RequireJS. This made it possible to get rid of duplication of the code in the game and the designer (long live DRY !), Increased the readability of the code, allowed us to make a universal code for the future to quickly port the game to different social networks and, finally, returned me faith in my powers. I gradually deleted more and more points from the list (closures, Promises, Web Workers, gulp, etc.), and it became more and more pleasant to look at the code.

Tip number 5: develop! If you do not do this, then your competitors will do it, and you will go to a landfill.

Procrastination


At one point in time, another trouble struck me: I have a tendency to irrational procrastination, so gradually I began to waste more and more time. I decided to pull myself together and try some way to make myself work. And then I caught the eye of the Pomodoro equipment. It works like this: four working approaches for 25 minutes with five-minute breaks, after which you take a fifteen-minute break. Having installed the application on the phone, I did not notice how I worked all day without any problems with motivation. The next day I finished the technique: I made an agreement with myself that the break should be spent outside the computer to rest my eyes. A miracle happened: the next day, I repaired / corrected / smeared / disassembled / disassembled the equipment in the house as much as I did in a whole year (subjective feeling). Naturally, at some point during the breaks there was nothing to do and I came up with another trick: I began to push-ups, squat, do exercises for the press (exercises that can be done at home without any simulators).

Council number 6 : if you suffer from procrastination, distraction, laziness, then try to deal with it in various ways. Satisfaction from the victory over bad habits delivers only pleasant emotions, while problems with motivation and fantasy disappear.

Descent from heaven


My inner perfectionist keeps telling me that I have to do the game alone. If I listened to him, then I would never have started this game. By July, I ceased to inspire the graphics drawn by me, and I matured to look for an artist. First, I found examples of images that I like, then I compiled TK in my own words and went through the following search circles for illustrators:

1. Habr. He wrote to people who make games or draw. Bottom line: to no avail.
2. The community of artists / illustrators Vkontakte. Result: I found an artist who disappeared after a month of work, leaving me with unfinished sketches. Bottom line: to no avail.
3. Specialized sites where you can see the works of artists and contact them: on one of the sites I found many suitable candidates, sent TK, selected two (plus later found another one on the same site), agreed to work together, a month later I was ready for the interface and two worlds (two styles for the level screen and the game screen).


Fig. 3. Artwork ordered from artists. UPD: The default font is used.

Tip number 7 : look for an artist immediately after creating a prototype for creating sketches (for money / for interest), if you do not consider yourself a professional illustrator. This is great fun interest. Since the appearance of the professional design of the game, I have not had problems with motivation and efficiency.

Interesting Facts


Fonts


The font for the game was found 5 days before the launch of the game, before the game was used Tahoma. At first, I thought that I would set the task of selecting the font for the artist, but then I looked at Habré for articles about fonts and, having adopted a couple of sites with free fonts, I began to select myself. It took 2 days and brought to the piggy bank a dozen nice fonts, and now one of them pleases the eye of users.


Fig. 4. The screen of the game of the Ice World with a selected font.

UPD:

Fig. 5. The screen of the levels of ancient Rome with a selected font.

Music


On one site where you can find an artist for almost any task, I found a person with a lot of positive feedback and ordered background music and several effects from him. After 2 days, I got everything I needed, paid for the work of the performer and realized that the music needed to be played. Despite little experience in this area, I refused to go cycling and began searching for ready-made solutions. I compared the two options (SoundManager2 and Ion.Sound) and chose the one I liked (Ion.Sound). Testing and selection took another 2 days.

There should be only one solution per level.


As I mentioned earlier, the goal of the game begins with the words: “assemble the puzzle in the only way”. This formulation concealed the most fascinating task of all that I had to face in the process of creating the game. At the same time, it took a very long time: the polishing of the algorithm for checking the number of possible combinations of the collection level constantly haunted me.

Task setting: there is a field of N cells on which N tiles are placed. On each tile there can be roads of different types and different directions. A field is considered to be collected if the tiles are arranged so that each road connects to a neighboring road of the same type.

A field must be assembled uniquely for several reasons:

1. To hints worked correctly.
2. To avoid claims and disputes about exactly how the collected level looks.

Starting to create levels without a constructor, I missed a couple of moments in which levels could be assembled in several ways. Therefore, having thought a little (unfortunately, a little), I piled the first version of the autosampler level, which recursively went through all possible combinations of arrangement (permutations) of tiles and at the end produced the number of permutations at which the level was assembled. At first, when the number of tiles in a level was 9-12, this algorithm worked in less than a second, but when I reached the 16-tile levels, I ran into a very long execution time. Let me remind you that all this works in a browser on js in one stream. In some cases, when I left the execution of the algorithm for the night, the browser tab could hang for a long time and no longer respond. In order not to clutter up the place in the article, I will describe the following optimization with the list:

1. Added an array of already verified permutations (saved into it a json string) and did not double check the same options.
2. Rewrote recursion cycles - the execution time has not changed significantly.
3. Began to think how to get rid of N! with all permutations. I remembered how I invented in my head an algorithm for solving Sudoku in my head. He began to draw an algorithm on paper and simultaneously stumbled upon an article Algorithm X or what is common between a wooden puzzle and a dancing Link? . I implemented algorithm X (I did not implement anything fundamentally new, so if the description of the algorithm is interesting, then it can be found in the above article).
4. Made a "caching" of all possible characteristics necessary for the operation of the algorithm.
5. Rewrote algorithm X with a cycle instead of recursion - the execution time has not changed significantly.
6. Replaced the array of already verified permutations with a tree in which each i-th nesting level corresponds to all checked tiles in the i-th position. Subjectively, this greatly reduced the running time of the algorithm at best.
7. I tried to solve in several threads using Web Workers - the execution time increased by a few seconds.

As a result of all the optimizations, it was possible to achieve collection time from 25 tiles to one and a half minutes. Next thought: rewrite the algorithm in a programming language that can work with multithreading.

gulp.watch


At the stage of active development, I ran gulp watch in the console and encountered a mysterious behavior for myself. Everything worked correctly until I started to edit css. After starting watch after 2-3 changes in the css-file, gulp stopped saving the output file (it created an empty file with the correct name in the right directory and that was it). The search for a solution took half a day and did not lead to anything. The remaining files were processed correctly. If someone came across and can explain in the comments, I will be glad:
gulpfile.js
var cssmin = require('gulp-cssmin'), rename = require('gulp-rename'); gulp.task('css', function() { gulp.src(['css/style.css']) .pipe(cssmin()) .pipe(rename({suffix: '.min'})) .pipe(gulp.dest('build/')); }); gulp.task('watch', function() { gulp.watch('css/style.css', function() { gulp.run('css'); }); }); 

When deleting lines with cssmin and rename, the situation did not change.


RequireJS and gulp


Thanks to RequireJS, I managed to achieve modularity of the project, but before launching, I realized that I needed to optimize the code, so I had to tinker with different options for optimizing the project on RequireJS using gulp. The requirejs was globally installed. Next, the following modules were considered as candidates for use in gulp: gulp-requirejs, gulp-requirejs-optimize, and gulp-shell. Examples of using:
gulp-requirejs:
 var rjs = require('gulp-requirejs'); gulp.task('optimize', function() { rjs({ name: 'script', baseUrl: '.', out: 'build/script.js' }); }); 

gulp-requirejs-optimize:
 var requireJSOptimize = require('gulp-requirejs'); gulp.task('optimize', function() { gulp.src('script.js') .pipe(requireJSOptimize(function() { return { name: "script", baseUrl: '.' } })) .pipe(gulp.dest('./build/')); }); 

gulp-shell:
 var shell = require('gulp-shell'); gulp.task('optimize', shell.task(['r.js -o baseUrl=. preserveLicenseComments=false name=script out=build/script.js'])); 

In the end, I chose the option with gulp-shell, because he only showed in the console the correct time to complete the task, and, accordingly, when used in dependencies of another task, he worked correctly. The build time of the final js file for one social network is 7-8 seconds.

VK API


Since with the last game I suffered with changing the code when I tried to host the game on Odnoklassniki and Facebook, I knew in this project at the initial stage of development that all API calls needed to be moved to a separate module. RequireJS allowed me to make a separate startup js-file for the social network, which defines the functions and methods that call the various methods of the social network API. Part of the startup file:
 requirejs.config({ baseUrl: '.', paths: { 'vk_api': '//vk.com/js/api/xd_connection.js?2' } }); requirejs([ 'vk_api', 'script' ], function(vk_api, script) { script.environment = 'vk'; /** * Tests social network's API * @return Promise */ script.testSocNetwork = function(callback) { return new Promise(function(resolve, reject) { VK.init(function() { if(typeof callback ==='function') { callback(); } resolve(); }, function() { reject(); }); }); } /** * Shows invite friend dialog */ script.inviteFriends = function() { VK.External.showInviteBox(); } /** * Gets array with IDs of friends and call callback with this array by argument * @return Promise */ script.getFriendsIds = function(callback) { return new Promise(function(resolve, reject) { VK.api('friends.getAppUsers', function(data){ if(!('response' in data)) { reject(); return; } var response = []; for(var f in data.response) { response.push(data.response[f]); } if(typeof callback === 'function') { callback(response); } resolve(); }); }); } /** * Shows buy ingame money dialog */ script.buyMoney = function(type) { VK.callMethod('showOrderBox', {type: 'item', item: type}); } /** * Shows request dialog */ script.makeExorcismWithPerson = function(uid, money) { VK.callMethod('showRequestBox', uid, script.i18n('makeExorcismWithPerson', {'MONEY_COUNT': money, 'MONEY_CASES': script.i18n('numeralForms')(money, script.i18n('casesMoney'))})); } /** * Adds callback for event onOrderSuccess */ script.bindOnOrderSuccess = function(callback) { VK.addCallback('onOrderSuccess', function() { if(typeof callback === 'function') { callback(); } }); } //... //Initializes game script.init(); }); 

Thus, it is possible to quickly deploy the game in other social networks, replacing API functions for specific cases.

The place where I blunted for an hour in the VK API


The code of the startup js file contains examples of calling the two Client API methods: showOrderBox and showRequestBox. Because of my carelessness and the blurred eye, I missed the point that in the first case, the associative array with parameters is passed to the VK.callMethod method as the second argument, and the second and third arguments are passed to the second argument.

Internationalization


In the call code of the showRequestBox method, you can see the use of the method that returns texts for output based on the selected language. At the moment there is only one interface language in the game, but there is a backlog for the future.

The structure is as follows:
The script super-object has the following properties:

language - the string in which the two-character name of the current language is stored;
phrases is an object in which two-character keys store objects with phrases in the appropriate language and a function that returns the desired form of a word, depending on the upcoming numeral.

Simply set an example:
 script.language = 'ru'; script.phrases = { 'ru': { 'numeralForms': function(number, titles) { var cases = [2, 0, 1, 1, 1, 2]; return titles[ (number % 100 > 4 && number % 100 < 20)? 2 : cases[(number % 10 < 5) ? number % 10 : 5] ]; }, 'ok': '', 'makeExorcismWithPerson': '    #MONEY_COUNT# #MONEY_CASES#!', 'casesMoney': ['', '', ''] }, 'en': { 'numeralForms': function(number, titles) { return titles[ (number === 1)? 0 : 1 ]; }, 'ok': 'OK', 'makeExorcismWithPerson': 'You get #MONEY_COUNT# #MONEY_CASES# for exorcism!', 'casesMoney': ['lightning', 'lightnings'] } }; 

The script.i18n method, when called, returns the corresponding phrase of the current language or the numeralForms function, if it is set as the first argument. The second argument can be passed an associative array with templates that will be substituted into the phrase. Examples:
 var money = 10; script.language = 'ru'; script.i18n('ok'); //   '' money = 123; script.i18n('makeExorcismWithPerson', {'MONEY_COUNT': money, 'MONEY_CASES': script.i18n('numeralForms')(money, script.i18n('casesMoney'))}); //   '    123 !' money = 1; script.language = 'en'; script.i18n('makeExorcismWithPerson', {'MONEY_COUNT': money, 'MONEY_CASES': script.i18n('numeralForms')(money, script.i18n('casesMoney'))}); //   'You get 1 lightning for exorcism!' 

Monetization


Monetization in the game was implemented as follows: for real money you can buy in-game currency - lightning, for which you can buy hints and crony - transitions to the next level.

Launch


The original release date was set for October 31st. Naturally, the game was not ready for this date. More precisely, in my opinion, she was not ready. Highlighting priority from the list of tasks, without which the launch would have been impossible, I began to work actively. For two weeks I managed to refactor and do everything that was necessary, and on November 16 I submitted an application to host a Vkontakte game for a friendly beta test. To my surprise, the game was approved about an hour after submitting the application, which I was notified by SMS message. Having tested the game on comrades for three days, I applied for free placement in the "New Applications" block. When submitting an application, you need to select the date of placement: the closest date was Monday, November 23 - I chose it.

Waking up on the morning of November 23, I first ran to the laptop to make sure that I made a very popular game. What I saw caused mixed feelings: on the one hand, over the night I had 3000 participants, and on the other, the game did not work. Quickly assessing the scale of the disaster, I discovered the following: access to the server via ssh could only be obtained via putty, neither Eclipse nor WinSCP connected to the server (and the logs turned out that the connection was established and everything, nothing happened after that) slowly gave statics, and apache, performing php, responded to requests for a long time. I called a friend of the administrator and asked to see what was the matter, and at the same time he himself climbed up to look at the characteristics of his VPS and the possibility of an upgrade. Looking at the server, a friend said that the characteristics of the server are sufficient for the described load. As it turned out, when buying a VPS, I missed the channel width item. For my tariff plan it was allocated 10 Mbps. I had to urgently buy and configure a new VPS from another host with a channel of 100 Mbps and transfer the game there. As a result, due to the need to leave for family matters, this procedure was completed only by the evening of November 23.

Tip # 8 : check all the characteristics of your hosting / VPS / personal server.

New applications


We should also tell about this sponsor of free traffic. On the application page there is a block “New applications”, which shows 4 games per page, sorted in descending order by the date of placement in this block. Those. On November 23, my game was first, 24 - second, 25 - third, 26 - fourth, respectively, and 27 was on the second page, which, together with Friday, dramatically reduced the number of clicks on the link. Subsequently, I twice saw the addition of two applications per day, which suggests that your application may be on the second page in less than four days.

Tip # 9 : It’s best to be placed in the New Applications block on Monday to get more participants.

Tip number 10 : if you watch released after my game, you can conclude that the Vkontakte audience loves games about precious stones and treasures.

Numbers


On Habré like numbers, I have them.

Spent money


NameRubles
13 months VPS at two different hosters4240
All graphics61300
Music3780
All advertising700
Total70020

Earned money


109 votes = 317.19 rubles without a contract = 385.86 rubles with a contract = 697.60 rubles for advertising an application without withdrawing votes from Vkontakte.

Visitor statistics




Statistics of installations / deletions of the game




Statistics of the number of participants




Statistics of game installation sources





Statistics by sex and age of visitors




Visitor geography statistics




Browser statistics




Screen resolution statistics




Conclusion


Games, and any projects of your own, must be done, because this is not only new knowledge, professional development, pumping engineering, organizational, design skills, but also fun.

UPD: after reading the comments I decided to add the article with the following postulates:
1. I know how much money I spent and how much I earned, and I specifically write about it, because such information is rare.
2. What motivated me when creating the game: I love puzzles, I like creating games, I'm tired of the power of the games that pump out money, I want to get a versatile experience.
3. Purpose of the article: to answer some questions that arise for novice developers, and to help cope with various difficulties encountered in the development process.
4. Taking this opportunity, I would like to ask people who have traveled the path of creating a social game to supplement my story with their own examples.

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


All Articles