📜 ⬆️ ⬇️

Developing a game for Windows Phone



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:
')

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:


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:


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:


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:


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:



Findings:


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:


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:


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:


Advertising


How to attract users to your game or application? There are several ways:

  1. Buy ads on some thematic site or in applications.
  2. If you \ your friends have other popular applications, place advertisements in them.
  3. Take advantage of the AdDuplex service: you are advertising other applications, and they are yours.
  4. 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.

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


All Articles