
In this article I want to talk about my experience of writing a game for the Windows Phone platform. Despite the seeming simplicity, the path from the idea to the game in the Windows Phone Store took almost a year and was full of unexpected pitfalls - both from the technical and organizational sides. The article is designed for novice developers who have an idea about .NET / C #, but have not tried to make full-fledged games.
Idea
It is difficult to remember exactly how the idea came to write a game. In my school and college years I was entertained by writing toys on the designers of games like
Multimedia Fusion , but the event-action system is rather inconvenient for describing complex logic. The choice in favor of Windows Phone fell for the following reasons:
')
- At that time (a year ago) there were very few applications in the market, my game will not get lost.
- Games can be written in C #, which I know very well.
- My colleague DiverOfDark , with the help of which I later published the game, bought Windows Phone and praised it in all its colors, predicting an enchanting success to the platform.
I wrote to a friend and told him that I wanted to write a game for the phone: another remake of the
classic game mechanics thirty-five years ago , about 30 levels with several bosses. A friend agreed to do the graphics, and I sat down to study the toolkit.

Findings:- It is not necessary to write a game for a platform that you use yourself.
- People love classic games. It is not necessary to open a new genre and invent radically new unexplored game mechanics, but it is still necessary to lick it to the smallest detail.
What to write?
The current version of the platform was
WP 7.5 Mango , which allowed using both Silverlight and XNA in the same application. This turned out to be very useful, since XNA is a rather scary framework, providing only the Spartan minimum of functionality. Silverlight can be used for menus and other “cool” pages with text, buttons and input fields, and draw the game itself on a special XNA page.
Examples of games that can be downloaded from the Microsoft site and pick it up, showed poorly suitable practices for developing a normal game. All variables were declared as properties directly in the class of the scene, and if it is still excusable for a game from one backdrop and two objects, then when creating any complex scenes, the code will turn into an unsupported mess. The search for suitable game engines also did not bring the desired success: almost all engines are focused on 3D games, and our game is solely 2D. So it was decided to quench the thirst of cycling and write a small engine for internal use.
When the engine was already giving conscious signs of life, the announcement of Windows Phone 8 was a pleasant surprise for me, which, however, quickly turned into an unpleasant one: XNA is now supported only in compatibility mode, and Microsoft no longer offers the official way to write games for WinPhone in C #! However, it was absolutely impossible to start learning about new technology and rewriting everything for it, and I had to be content with the compatibility mode, which, fortunately, did not prepare any unexpected pitfalls.
Findings:- Microsoft changes its priorities so often that it puts both developers and users.
Own 2D engine
The main task of the engine was the organization of the code and the provision of an OOP framework, on which it would be possible to construct a diagram of classes of the domain. For those who want to look at the code or use the engine for their game - for health, it is available under the MIT license
on the githaba .
The base class
VisualObjectBase
provided the presence of two abstract methods
Update
and
Draw
, commonly used in XNA games, and also stored the position of the object and allowed its dimensions to be calculated (bounding box).
From
VisualObjectBase
inherited, which added objects such properties as transparency, rotation angle, scale and their derivatives, as well as linear velocity to objects. The object was given a list of animated properties and behaviors, which are described below. Next in the hierarchy was the
InteractiveObject
, which checks for collisions, the position of an object, and pressing a finger on it (tap), followed by a
GameObject
in which sprites appeared. Most of the user objects in the game are heirs to
GameObject
.
To store a previously unknown set of objects of the same type, there is an
ObjectGroup
class: it is inherited from
DynamicObject
and in essence is a wrapper over the
List<VisualObjectBase>
.
The picture shows an approximate diagram of classes in the engine. The solid arrow - "inherits", the dotted - "uses."

The most significant problems solved by the engine, we consider in more detail.
Collision check
Even such an important thing as collision checking was not in XNA by default. I had to look for a compromise between speed and accuracy, which is reflected in the following code (somewhat simplified for the article):
public override bool IsOverlappedWith(InteractableObject obj) { var box1 = GetBoundingBox(true); var box2 = obj.GetBoundingBox(true); var isect = Rectangle.Intersect(box1, box2); if (isect.IsEmpty) return false; var gameObject = obj as GameObject; // Check whether both objects are GameObjects and are neither rotated nor scaled if (gameObject == null || !Scale.IsAlmost(1) || !obj.Scale.IsAlmost(1) || !Angle.IsAlmostNull() || !gameObject.Angle.IsAlmostNull() ) return true; // Convert it from screen coordinates to texture coordinates Rectangle textureRect1 = isect, textureRect2 = isect; textureRect1.X -= box1.X; textureRect1.Y -= box1.Y; textureRect2.X -= box2.X; textureRect2.Y -= box2.Y; var colorData1 = GetCurrentAnimation().GetTextureRegion(textureRect1); var colorData2 = gameObject.GetCurrentAnimation().GetTextureRegion(textureRect2); // check every 2nd pixel for the sake of speed for (var idx = 0; idx < colorData1.Length; idx += 2) if (colorData1[idx].A != 0 && colorData2[idx].A != 0) return true; return false; }
The essence of the example is quite simple: first, the intersection of the rectangles bounding the objects is checked. If they do not intersect, objects obviously cannot collide; otherwise, a pixel-by-pixel comparison of the portion of textures located at the intersection of the rectangles is performed. After the owner of
HTC Mozart complained about noticeable lags when checking collisions for many objects, I had to sacrifice the accuracy of the mechanism and check only every second pixel.
Animated properties
In the real world, uniform motions practically do not exist: when an object begins to move, it gradually accelerates, and also slows down before stopping. To make the movement of objects in the game look more natural and attractive,
Robert Penner’s slightly reworked
easing formulas were used. The universal mechanism allows you to apply an uneven gradual change to any
float
property of an object, and through it indirectly to values ​​of type
Vector2
or
Color
.
Behavior
In essence, this
is the “Strategy” design pattern : each object of type
DynamicObject
has a list of objects of type
IBehaviour
, each of which has a link to the parent object and having the ability to control its properties by executing arbitrary code.
This approach allows us to greatly simplify the description of game logic, reducing it to combining several ready-made "recipes". For example, all enemies can be hanged in one fell swoop with “behavior”, which makes them flicker after a player’s bullets hit them, crumble into a sheaf of sparks after death, rattle, bounce off walls and move through complex tractors.
Touchscreen interaction
To obtain information about clicks on the screen, the
TouchPanel
class and its
GetState
method are
GetState
. Nothing was written in the
documentation for this method and
usage examples , but the status of the
TouchCollection
updated with every call. Thus, if several of them call
GetState
in the object tree, only the first of them will see clicks with the
Pressed
and
Released
states! For other objects,
Pressed
will turn into
Moved
, and
Released
will be excluded from the collection altogether. The engine wrapped this roughness by caching the one-time-received
TouchCollection
, which is available to all objects in the tree.
Deferred actions
Imagine a typical game situation: if an object flew off the screen, it must be destroyed. This can be represented as the following pseudocode:
foreach(var bullet in Bullets) if(bullet.LeavesPlayfield()) Bullets.Remove(bullet);
However, such a code will throw an exception, since changing the collection during its crawling in the
foreach
prohibited. What to do? The most elegant solution to the problem was to create a global list of
continuations , and the code began to work something like this:
var cont = new List<Action>(); foreach(var bullet in Bullets) if(bullet.LeavesPlayfield()) cont.Add(() => Bullets.Remove(bullet)); foreach(var act in cont) cont();
Findings:- Cycling is not always bad, especially if it comes down to writing helper methods.
- Preliminary creation of a list of all the required functionality in the form of tasks on some task tracker very well helps to deal with the growth of requirements .
Search artists and musicians
By the end of May, the project was more than half ready, and suddenly the unexpected happened: my friend, who was drawing graphics for the game, was promoted at work, and therefore he did not have free time for our project. The project has stalled for the whole summer, and although during this time I wrote some code, there was clearly not enough motivation for working alone.
Closer to August, I thought the game had stalled and it doesn't make sense to finish it. Then came magic magic kicks from colleagues; I reduced the requirements for the game (I refused bosses and story mode) and went in search of freelance artists.
The most effective place to find pixel artists was the
Job Offerings forum
on PixelJoint : over ten people wrote to me overnight, offering their help and giving links to the portfolio. I agreed with one of them and the work began to boil again.
The price range was quite substantial. Americans and Europeans asked for their services almost fourfold cost compared to their colleagues from the CIS countries, although there was practically no difference in quality. There are some very strange personalities: one American who boasted of participating in “projects released under the Game Boy Advance” still writes from time to time to Skype and asks him to lend him $ 100 on account of his work on future projects with me.
One of the forum visitors, having learned that I had already found an artist, offered his help as a musician. I didn’t really like the melodies he originally wrote, but after some constructive criticism I managed to convince him to rewrite the music so that it would fit the game more.
Findings:- Even for small, but fixed money, artists are and work much more actively than for an idea or a percentage of profits. If you really want to finish and release the project - you should consider the initial investment.
- It is better to release some part of the game and refine it afterwards, rather than try to do everything at once and take the risk of not releasing anything.
Testing and sending to the Windows Phone Store
On the nose was a Catholic Christmas. I wanted to release the game as soon as possible, as a result of which I was having a lot of testing time, and it was in vain. Having fixed a few errors found, I decided that the game was ready, and sent it to the Store. The initial certification took a week, and literally several hours before the game was accepted, a friend wrote to me and said that he had found a significant new bug, because of which the game hangs tight. I had to build a new version and wait another 5 days for it to be checked.
When making an application in the Windows Phone Store, no one checks its actual value. Microsoft in this matter is guided by the idea that obviously useless applications are themselves filtered by low marks. In practice, the
indescribable shit in the market very much .
To increase the chance that the game will be certified the first time, you should pay particular attention to the following things:
- The application does not have the right to arbitrarily run its music, if the user is already playing . It is best to show a message with the request “turn on the soundtrack or not?”, But you can just leave the user with the music that is playing on his player. This case is checked in 100% of cases and the violation of this rule guarantees a refusal .
- The application must be stable . If it falls during some basic actions, most likely it will not pass certification.
Findings:- The time originally allocated for testing should be multiplied by two. Twice.
Useful services and services
To facilitate the work with the fall of the application there is a convenient
BugSense service. Exceptions are automatically classified by callstack and are sent to you by mail. It is a good idea to create a special page, which is accessed when an unhandled exception occurs: you can write something on it like, “
Something broke, but don't worry, dear user, the glass path is halfway through, and we are working on the problem! ” . Trifle, but nice ©.
Flurry is great for collecting statistics. The number of different statistical sections is impressive:
- Number of new, unique, regular users
- Number and average session duration
- Geography and system locale
- Phone model
- Gender, user age
- A lot of other indicators
Both services can be used for free (although BugSense with some restrictions). However, the connection statistics has an unexpected negative property: the list of application requirements in the market is replenished immediately with four rather scary-sounding items:
- Phone Identity - required to collect information about phone models.
- Owner's ID - required to collect information about the number of unique users and sessions.
- Location Services — required to collect geographic information.
- Data services — required to send statistics and crash reports.
In addition, if your game plays music through
MediaPlayer.Play()
, the item "
photo, music and video libraries " will also appear in the list of requirements.
Findings:- In the comments some paranoid may start, but you should not give him too much attention - statistics is more important.
Advertising
How to attract users to your game or application? There are several ways:
- Buy ads on some thematic site or in applications.
- If you \ your friends have other popular applications, place advertisements in them.
- Take advantage of the AdDuplex service: you are advertising other applications, and they are yours.
- Post information on thematic forums, groups in social networks, reddit and squeal in a tweet.
In my case, the last one turned out to be the most effective way: having posted a small message on the
WPCentral forum with screenshots, a video on youtube and a link, the next morning I found a review on the main page that grew five times the download statistics and was mentioned in the official
Nokia USA account.
Findings:Summarizing
It is difficult to say how commercially successful the game has turned out, but the fact that bringing a product from an idea to readiness gives a lot of useful life experience is indisputable. I hope someone my notes and thoughts out loud save a couple of stuffed cones on his forehead.
PS I do not deliberately give direct links to my game, but a curious user who has carefully read the article can easily find it.