Features of the development of mobile MMO RTS. Part 1
In the series of articles "Features of the development of mobile MMO RTS" we will talk about the work of a large team on a large-scale project Stormfall: Rise of Balur. This experience will be useful for independent developers and studios who have not yet decided on the choice of technology, architecture and team structure for their RTS.
Unity selection. Advantages and disadvantages
The main argument in favor of Unity was C #. But there are other advantages:
Unity has a fairly low entry threshold for developers.
Unity takes care of all issues related to the compatibility and correct operation of the application on different platforms. We just need to make sure the build is working in the Unity Editor, check it on key devices, and then monitor the application through the crash reports service and our Community Managers. We notify guys of problems from Unity, they fix it with regular patch releases, and after that we release a hot fix.
Unity provides a high level of developer support. Standard responses from agents are rare. If the question contains a detailed description of the problem, screenshots and a test project to run, you will receive a comprehensive answer with tips on how to get out of the situation.
Now about the bad:
The low entry threshold had its drawbacks. The applicants we interviewed knew Unity well, but badly - C #. We came to the conclusion that it is better to look for developers with a deep understanding of C # and a desire to explore the most popular game engine.
Unstable quality releases. Especially for patches. Unity advises you to install them only when they fix a bug affecting your project. But something can break in another place.
Strange priorities in roadmap. For example, long researches of polymorphic serialization or nested prefabs. I think that Unity is trying to catch up with its closest competitors in terms of graphics quality and does not implement features that would greatly simplify the development of large projects.
Closed platform. If you have problems, the solution of which depends on Unity, you have no other options than to wait for the desired release.
Architecture
If you want to come to the market for a long time, you need to think carefully about the architecture of the application. If you think everything over, you can quickly and easily add new features and modify old ones. There are a lot of articles on this topic on the web, but I want to draw attention to several important points: ')
Select an architecture pattern at the initial stage of development and always stick to it. For Unity projects, this is necessary in order to understand exactly how data will be exchanged between the UI and the business logic. Your task is to make the exchange of the same type, clear and transparent.
Do not attempt to describe the entire architecture before the project begins. It begins to emerge only at the development stage. To start, it is enough to follow the principles of the chosen template and gradually arrange similar mechanisms in the form of architectural solutions. But still, at the initial stage of development, the architecture should be paid more attention than the creation of new functionality.
Lay in time for refactoring to implement new architectural solutions.
Create restrictions on work in the code, just a discussion is not enough. You agree with the team that an object can only be used in a specific way, from a stream or for specific conditions. It takes a couple of weeks, and someone is surely taken to use this object not where it is needed and not in the manner agreed upon, which often leads to problems that are difficult to determine.
Adhere to the principles of SOLID, but without fanaticism. Common sense has not been canceled. Imagine that you have 2 ways. The first is to implement a well-thought-out modular technical solution that easily expands anywhere. The second is to perform business tasks in a limited time, but then all the beauty of the technical solution “on the drum”. In this case, choose the second path. Do not stoop to design for the sake of design.
Make important decisions with the team. Try to discuss to provide several options with the pros and cons of each approach.
Why MVVM
The template is well known to WPF developers, and its essence is that the “data binding” is used when separating the data model from the view. The model, like MVC, is a fundamental application data and various mechanisms for their processing. A view is a GUI object. They are subscribers to property value change events that are provided by the View Model. Representation model is an aggregation of the necessary data for representation from the model. It contains commands through which the view can influence the model.
Due to the nature of our application, we chose the architectural pattern MVVM. Unlike MVC / MVP, it provides a higher level of abstraction of UI from logic and data with which the UI works.
Model
The model in our application is the classes with data shared with the server, the mechanisms for their processing and the commands. Data is grouped by purpose in classes, which also provide methods for accessing and processing. All this is provided through the front object for access from the ViewModel.
Commands are the only mechanisms through which a view can influence a Model. They are an abstraction for performing operations that changes the local model and also encapsulates the logic of data synchronization with the server. All commands are wrappers on HttpWebRequest and are executed asynchronously (Asynchronous Programming Model). For WebGL builds, the commands are wrappers over the Unity WWW class, which runs through the cortina. To communicate with the server, the data is serialized in JSON format.
Due to the asynchronous execution of callbacks in other threads from ThreadPool, as well as from the mechanism of dynamic updating of the model, which is performed in a separate thread, data access synchronization is necessary. This logic is encapsulated in a front access object to the model that I described earlier.
Viewmodel
The ViewModel layer of our application is the most voluminous by the amount of code. In essence, all the main feature development takes place at this level. On this layer, data from disparate model objects is gathered together in order to be presented to the user in View. The ViewModel is in no way tied to the implementation of the View, but the set and data format directly depends on how they are presented in the UI. Also on this layer are implemented various mechanisms that may not have a UI, but are necessary for the functioning of the application: various managers for working with social networks and so on.
Our ViewModel operates with several basic concepts, among them Property and Context. Property is a custom generic implementation of the ObservableObject pattern. Contexts act as containers for Property and other Context. Context also encapsulates the search and search logic and the activation and deactivation logic of contexts. This is necessary as an optimization so that the contexts of objects that in the UI, for example, are blocked by something, do not catch events and are not updated once again. The search mechanism is implemented through reflection and works only at the moment when some UI element wants to bind to the Property from the ViewModel and is far from the bottleneck in performance.
View
The View layer is responsible for the UI. It is at this level that the code becomes aware that it works in Unity. Object groups at this level are represented by:
Binding mechanism.
ContextBox objects are MonoBehaviour scripts that are basic for all objects that plan to use the ViewModel, because they create and control the life cycle of contexts from the ViewModel.
Custom Unity components required for gameplay.
UI scripts, such as NGUI or Unity UI.
The binding mechanism implemented for us works like this:
A Label UI script is hung on the GameObject.
The LabelBinding script hangs on the same GameObject, it accepts a reference to the Label with the parameter, which it works with. Next, the path to the Property in the ViewModel is specified in a string form that the GameObject should contact.
With Awake, the binding through ContextBox looks in Context for the Property it needs along the way and, if it finds it, subscribes to its changes.
When the Property value in the ViewModel UI changes, it immediately reacts to these changes and displays them in the associated Label.
For now. In the second part we will talk about multithreading, working with skins, executing queries and caching them.