📜 ⬆️ ⬇️

The results of the competition on the test task for programmers from ZeptoLab. New test task

The long-awaited results of the contest of forces Android and iOS developer-s in place in the Dream-Team team ZeptoLab, finally, summed up. Over the past six months, we promised what we did: we grew 2 times and conceptually designed our monastery:
image

How it was

image
')
During the same period, we managed to see enough works to once again only confirm the rule: there are very few standing specialists, and they are hiding. In order to contribute to the improvement of the situation, we decided to share our observations regarding the main points of game development on these two mobile platforms: for some points to give recommendations, a place for comments from Android and iOS gurus was also left and welcome.

Recall, our test task for programmers was to develop a prototype of the game “Arkanoid” using Objective-C for iOS and NDK for Android.

According to the sent tasks under iOS

Let's start with a brief review of Arkanoidov under iOS (they were sent significantly more) - the most memorable and revealing:


image
1. Original idea.
Convenient management.
Good handling of collisions.
Closer to the edges of the platform the ball changes its direction.

image
2. Beautiful graphics. Convenient management. Very fast gameplay. Good handling of collisions.

image
3. Simple graphics based on primitives.
Convenient management.
Good handling of collisions.
Pinch gesture affects
game speed.
As you progress
bottom texture floats
with the words "Wanna go Zepto"

image
4. The only task done in 3D and sent to us =)

image
5. The use of atlases.
Frame by frame animation.
Convenient management.
Beautiful graphics.

image
6. Beautiful test task, made in the style of old school Tetris.
Proper sound accompaniment.
Convenient management.

image
7. Very beautiful test task, it looks almost like a finished project.
Convenient management.
Good handling of collisions.
Quick gameplay.

image
8. The original task and the only thing that has a plot (the wizard with a stick protects the city from the orcs).
Nice time-lapse character animation.

Frequent errors:

1. Memory leaks. Unfortunately, almost all tasks that were done without using Automatic Reference Counting technology had memory leaks.
2. Handling collisions. In many tasks the ball was stuck in the cue ball or in the "bricks". Most noticeably this happened in very densely packed levels. And most often it was seen on the first run. In almost all tasks, processing depended on framerate.
3. Management. Sometimes control was hung up on a swipe gesture or accelerometer, and it became very difficult to manage chock. This item, of course, can not be fully recorded in the error, so we did not penalize him. But, nevertheless, in our opinion, the most convenient control, when the cue ball strictly follows the finger.
4. Application architecture. There are sometimes two extremes. Either when the main code of the entire application was in the same class, or vice versa, it was created under fifty classes, which is completely unnecessary for this application.
5. Gross errors in the code. They are most often associated with violation of the principles of the PLO. The benefit of such mistakes was extremely small.
6. Sometimes there were tasks performed using various third-party frameworks, for example Cocos2D. Such tasks were eliminated immediately.
7. There were also tasks that did not want to run without additional manipulations. This is most often associated with project settings. For example, resources have been added with global paths. If this error was corrected within 5 minutes, the task was not withdrawn from the competition.
8. Resolution. In the code, there were often many magic numbers linked to one specific resolution. On other resolutions, respectively, everything moved out.
9. Restart. One application at a loss just paused. To restart a level, you had to restart the entire application.
This is also not entirely a mistake, but it complicates the assessment of such a task.

From pleasant:

Some tasks pleased us with nice little things: sound design, stylish graphics, beautiful animation. It is certainly a pleasure to look at a beautifully designed project, and such a project is well remembered, but we would recommend to postpone the addition of various beauties until the main task algorithm is polished. Because, first of all, it was precisely the organization and readability of the code, the collision handling algorithm, the convenience and control implementation, and, of course, the number of errors that were made.

For tasks sent by Android

Despite the fact that the availability of IDE for Android development is somewhat higher, and the hardware requirements are lower compared to Xcode for iOS, about a quarter of the total flow was sent to test tasks for this OS. This can be partly explained by the lack of a normal integrated debugger for the native environment in the default IDE (we all mean Eclipse), in part by the requirement for the programmer to know at least 2 programming languages: C ++ and Java, or be able to quickly understand them.

The fact that many understood in the development of Android for the first time, it was clear from the source code sent. Also, many programmers honestly mentioned this in letters and at the interview. We didn’t judge such tests more strictly, as we didn’t give the developers a concession for the fact that this is their first Android project. All were on an equal footing.

Working for the first time with the native environment, the examples supplied with the Android NDK were used as the basis for the project - a great way to get a working draft, so that you can start from something. More experienced programmers used their libraries and practices that other libraries are pulling. As a result, the amount of project source code sometimes grew by orders of magnitude, and we had enough material for analysis. By the way, the volume of the source code in the most "light" project - 14 kilobytes versus 1.6 megabytes (only the code!) In the most "heavy". By the way, the author of the easiest code joined our team.

One of the main requirements for the program was correct operation under any screen resolution. In the case of Android, this requirement is more significant compared to iOS, since The list of device permissions is “slightly” more: (useful article on this topic: opensignalmaps.com/reports/fragmentation.php ) and for all of them 2 conditions must be met:

1. Invariance of physics and gameplay in general. Simply put, if you record user actions (for example, touching the screen, if such a control method was chosen) in relative coordinates and play them on another device, the level passing should not change.
2. Acceptable changes in the visual part.
Different authors dealt with these conditions in different ways.

A simple image scaling is obviously not suitable, since it entails displaying an ellipse instead of a round ball (or a rectangle instead of a square, which played the role of a ball in some tasks)

Some programmers implemented the size of the playing field in pixels for the smallest resolution, and on large devices they displayed the playing field in the center or corner of the screen.

By the way, the very task of displaying a ball using OpenGL code on different devices is nontrivial in itself. Some used a texture that, when enlarged to fit the screen, lost visibility; some drew the ball programmatically. By the way, we will be happy to hear comments from non-indifferent habrazhiteli on this topic: how would you draw an OpenGL-ball without considering the first constraint (gameplay invariance)?

A little about the code itself
Below are screenshots of some submitted tasks for Android:

image
A good implementation of Arkanoid.
The author should pay attention
on the behavior of the ball when
pushing away from the blocks
preserving angles when
collisions. Also in similar
games it is desirable to hide the toolbar.
The game has problems with rendering on
Sony Xperia Play with firmware 2.3.2.

image

Quite an interesting implementation. In this case, we control not the bat, but gravity using an accelerometer. I liked the high FPS and the absence of jerking in the animation. The gameplay was quite interesting, and at the same time within the framework of the condition. The author should pay attention to the shape of the ball on some devices and problems with the launch of the Samsung Galaxy Note with firmware 2.3.6 and Google Nexus S with firmware 4.0.4.

image
Canonical implementation of Arkanoid. Classic gameplay and strict adherence to the task conditions. The bit is controlled by an accelerometer. Of the benefits can be noted quite smooth rendering. Of the minuses - inaccuracies in handling collisions with the lower part of the bits and the possibility of the case when initially the direction of the ball is set strictly vertically - in this case, the level becomes impassable.

image
Solid work, one of the best implementations. Convenient control, nice graphics and good gameplay in general. Pleasantly pleased with the presence of animation collapsing blocks. The author should look at the behavior of the ball with a large angle of departure from the walls in cases where the player repeatedly hits the ball with the edge of the bat, increasing the angle of the trajectory, and also pay attention to the inoperability of the application on the Samsung Galaxy Note with firmware 2.3.6.

image
Another good job. Here, all elements are drawn by pixel shaders, and when passing a level, the old school's shader effect is played a la “hello from the 90s”. Of the benefits you can also note the smoothness of the gameplay and high FPS. The program worked on all checked devices. The author should raise the bat and lower the touch-zone, since the finger covers the small bat.

Since a sufficient number of options were sent, we had the opportunity to compare solutions of the same local problems.
For example, besides displaying a ball, the task of initializing a map is indicative.

Someone did it like this (iOS):

const int level [LD_HEIGHT] [LD_WIDTH] = {
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1},
{0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1},
{0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1},
{0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,1},
{0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1},
{0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1},
{0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1},
{0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1},
{0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
{0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
{0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
{0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
{0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
{0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
{0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
{0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0},
{0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0},
{0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0},
{0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0}};

Someone like this (Android):
for (int i = 0; i <MAP_W * MAP_H; ++ i)
(Blocks [i] = new block ()) -> init ((i% MAP_W - MAP_W / 2) * 0.2, (i / MAP_W) * 0.2, i% 3> 0? 1: 0, (i + 2) % 4> 0? 0.7: 0, (i + 3)% 5> 0? 0.9: 0);

And someone even like that (iOS):

// map generation

Map [0,0] = 1;
Map [0,1] = 2;
Map [0,2] = 4;
Map [0,3] = 1;
Map [0,4] = 2;
Map [0.5] = 0;
Map [0,6] = 3;
Map [0.7] = 2;
Map [1,0] = 1;
Map [1,1] = 3;
Map [1,2] = 0;
Map [1,3] = 1;
Map [1,4] = 2;
Map [1,5] = 3;
Map [1,6] = 4;
Map [1,7] = 2;
Map [2,0] = 1;
Map [2,1] = 0;
Map [2,2] = 2;
Map [2,3] = 3;
Map [2,4] = 4;
Map [2,5] = 3;
Map [2,6] = 0;
Map [2,7] = 2;
...
Map [4,7] = 1;

It is immediately clear which code was written for clarity, which one - for the purpose of speeding up the task, and which one - for the purpose of surprise someone.

Also, since we touched on this topic, we are interested in the opinion of habrazhiteli regarding this code: when it has a right to exist, and in which it is worth replacing it with a cycle (code for iOS)

[player_pic addFrame: [UIImage imageNamed: @ "0.png"]];
[player_pic addFrame: [UIImage imageNamed: @ "1.png"]];
[player_pic addFrame: [UIImage imageNamed: @ "2.png"]];
[player_pic addFrame: [UIImage imageNamed: @ "3.png"]];
[player_pic addFrame: [UIImage imageNamed: @ "4.png"]];
[player_pic addFrame: [UIImage imageNamed: @ "5.png"]];
...
[player_pic addFrame: [UIImage imageNamed: @ "12.png"]];

Comparing the iOS and Android platforms, we can say that the variability of the code under iOS is more pronounced - unreadable examples are really unreadable, the spaghetti code justifies its name, and well-executed tasks look really beautiful.

I would also like to note a less creative approach to the formulation of the task by Android programmers compared to iOS, where there were human lungs broken with bits and cigarettes (though the idea was borrowed), and a clone of Tetris, and even a project with a fantasy storyline.

In general, by code: comparing tasks for iOS and for Android, we saw something like this: the code for iOS is less documented and rather often dirty. Someone left autogenerated comments in functions that were originally stubs, and someone commented out large modules entirely.

On both platforms, the lack of KO comments seemed to please

Void initGame(); //

But comments on the merits could be more.

About inaccuracies in implementation

The task for the programmer was set as follows: “controlling the bat ... smashing a brick located in a certain place on the screen”. Many drew levels consisting of several bricks, there were even 3d variants, and there was even a variant with a real baseball bat.
The test task is not a technical task, we didn’t do literacy, because both parties understand why the test task is needed. If the programmer did something more complicated or interesting, it was only a plus. However, strict adherence to the stated assignment was also a plus, and in itself says a lot about the person. But following the direction already chosen was evaluated seriously, and it was primarily the bugs in the chosen gameplay that were evaluated.

Bugs

Bugs were almost everyone. To a lesser extent, we attached importance to errors in rendering, and we paid special attention to inaccuracies in the game engine. If errors in graphics are noticeable immediately, then errors in logic are more insidious. Through a test task, we looked for programmers who were able to issue at once good code. In this case, this implies the correct handling of collisions, the absence of memory leaks, and, of course, the fall of the game.

Typical errors in logic:

1. Determination of the direction of departure of the ball from the brick. As it turned out, this trivial task required thorough testing, since almost everyone had errors. The most common are two:
• flying the ball in opposite directions along the X and Y axes if it hits the junction angle of two bricks.
• flying the ball from the brick at an angle different from the angle of incidence.

2. Incorrect calculation of the ball's behavior at the moment when it has already flown the level of the bit, and the bit “covers” it. In this case, the bugs were very diverse, up to the ball pushing away from the lower edge of the screen, which directly contradicts the formulation of the problem.
In addition to errors in the logic in the code for Android, there were system errors, mostly - typical errors when working with memory. Describe them in detail does not make sense. Nobody had any application crashes.

Conclusion

Below is a description of the ideal task, as we see it:

1. Collisions. Ideally, a continuous collision tracking system should be made here so that there are no problems associated with low fps, etc.
2. No memory leaks. iOS 5.0 simplifies memory handling with its technology - Automatic Reference Counting.
3. Good application architecture. It would be good to show that you know what OOP is and how to use it correctly.
4. Convenient operation. In this task, it seems to us, the most convenient control is the strict adherence of the platform for the finger. Moreover, the platform should not overlap with a finger (it can be lifted from the bottom edge of the screen). Touch area must act across the screen, so that control is not lost with the vertical movement of the finger. Multitouch is absolutely useless here, so it should be turned off to avoid errors.
5. Individuality. If there is some zest in the task - this is a plus.

At the same time, we officially announce the closure of the competition for the “Arkanoid” But since our Dream Team company is growing irreversibly, we announce a new set of programmers for iOS and Android platforms (both Lead-s and ordinary, but talented) and offer a new task:

It is necessary to make a prototype of the game Pacman, in the simplest version: there is a maze in which our character is located, and a monster who is trying to catch up with him.
If we collected all the food scattered in the maze - we won, but if the monster touched us, we lost. The way you control the character is at your discretion.

Prototype requirements:
- Rendering should be implemented using OpenGL (any version);
- The game must be written in Objective-C or C ++ in the case of iOS, or using NDK (C ++) in the case of Android (the program must be entirely in C ++, there can only be code binding in Java), without any third-party libraries (like Cocos2D or GLKit);

In terms of execution time, we, on our part, do not limit in any way, because we will always need talented programmers. Efficiency will undoubtedly add competitiveness, but it is better to be satisfied with your work than just being first. Questions, suggestions and completed tasks will be waiting for job@zeptolab.com.

Our work is interesting, creative and teamwork as possible - so the schedule is flexible, but our presence in our beautiful office will be an essential element.

If suddenly you don’t have any of these skills, but the desire to join the ZeptoLab development team hasn’t diminished - you can quickly learn any of these tools (one of our (already ours) Android developers learned Android programming in a month) (well knowing C ++) and sent us one of the best tasks). Therefore, as they say, there would be a desire :)

We hope the above review will help developers with a claim to the high quality of their own work to understand what to look for when creating a masterpiece. For someone, this is another chance to try your hand among professionals and learn a lot.

In general, everything.

If you have something to share on the topic - as they say, also welcome.

We do not say goodbye.

Zeptoteam

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


All Articles