📜 ⬆️ ⬇️

GUI in the game World of Tanks. Part Two: GUI Structure Overview and Future Plans

image

Today we continue the story begun a week ago about the interface of the game World of Tanks.

Current project status

Let's refresh the information from the first part of the article.
')
Now for the GUI rendering in the project, the Autodesk Scaleform technology is used, which allows using Flash as a development environment.

Anyone familiar with Flash knows that the programming language in this environment is ActionScript. This language has several versions, but the most widely used are ActionScript2 (AS2) and ActionScript3 (AS3).
Our project currently uses both versions. This is due to the fact that the development started on AS2, since Scaleform did not support AS3 at that time. Over time, when AS3 support in Scaleform appeared and its implementation became quite reliable, the transfer of service (non-combat) interfaces to AS3 began.

Why did the transition to AS3 begin with the migration of service interfaces to it? Everything is very simple. Cheerful tank rubilovo is our everything. Any interference, lags or bugs in the combat interface can spoil the user's perception during the game. We could not take such a risk and started the migration from a less demanding in terms of resources and not so critical parts for the gameplay. This approach is fully justified. We stumbled upon problems with performance and memory consumption. Most of them we decided before the release of the updated hangar, some were caught and corrected already in production, relying on the bug reports from the players. There were no serious punctures, which is good.

In the previous article I gave a list of problems with which we had to live in AS2. I will refresh this list:


These problems made a significant contribution to labor input when adding new functionality to the project, and this is another reason why the transition to AS3 began with service interfaces. From the point of view of the GUI, the hangar is a part of the project with the greatest concentration of new functionality on release, and, accordingly, the most costly in human resources. In turn, the combat interface is already working on AS2, it is updated less often and does not cause any major complaints. Why break something that already works?

Overview of the architecture and development process

But the WoT GUI-developer does not live as a Flash. The project uses Python as the scripting language. All the beauty that we have done in Flash, you need to connect in the game, fill with data, process and translate user input into real actions in the game. All this is done in Python.

Here is a simplified diagram of the main GUI elements in the client:

image

Let's take a closer look at what is behind these multi-colored rectangles.

AS2 and its interaction with Python

When you enter the battle begins loading battle.swf. This file contains almost all the main elements of the combat interface (HUD): command lists, chat, tank status panel, mini-map, consumables panel, etc.

Virtually every element present in battle.swf is responsible for one of the classes in Battle.py. When the download is complete, the contents of the file are stretched to the entire viewport of the game client and drawn over the 3D scene. In addition to battle.swf, SWF files are also loaded to display markers and sights. They are placed under battle.swf so that the markers and sights do not overlap with the elements of the HUD, but hide under them.

Also for systems with multiple monitors, SWF files with scopes and markers are stretched to all monitors, and battle.swf is drawn only on the main monitor (so that the HUD does not scatter around the different corners of these monitors and you can adequately read the combat information).

The status of the markers and sights monitors Python. It handles game events and data, creates and destroys markers and sights. Each type of sight has its own Python class. VehicleMarkersManager is tracking markers. The location of the markers and sights on the screen is the client C ++ code.

For communication between Flash and Python in combat, two approaches are used:

1) The most frequent is the transfer of data by an array of scalar data through the API provided in Scaleform. In the previous article I described this method and explained its shortcomings (it is inconvenient to read the code, refactor and maintain).

2) The second approach is the Direct Access API (DAAPI). I just mentioned it, and now I will tell you more.

This approach has two main advantages: simplicity and speed.

The simplicity is that you can transfer complex objects in both directions without thinking about serialization / deserialization - everything happens automatically in C ++. The speed of work is achieved due to the fact that calls of methods in both directions occur "directly". That is, having a link to a Flash object in Python, you can call its method and pass arguments to it as if it were a Python object. Without using DAAPI, calling the methods occurs by specifying the path to the Flash object in the tree of visual components and searching for this component in the hierarchy, which is expensive.

In addition to these obvious advantages, there is one more, but very important - you can assign a Python object as a handler for the Flash object.

I will draw and explain what is happening, in steps.

image


This feature lies at the heart of the new architecture, which is used in the AS3 part of the project.

How is the AS3 part of the project

First of all, you need to say that the project is built using Apache Maven and Apache Ant. Logically, the project is divided into several layers:

The entry point to the AS3 application is application.swf, which contains the class net.wg.app.impl.Application. This file is always loaded when the client starts. It solves three main tasks:


The Application class from AS3 has a second half in Python - the AppEntry class. Tasks of this class:


In the process of building Common and GUI libraries, we use YAML to generate code. Here is a list of tasks that we solve using YAML:


Any class in AS3 (be it a class responsible for the work of a view, or a manager without a visual presentation) that needs to communicate with Python should be created using the description in YAML. Let's take a look at the example of the post-combat statistics window:

BattleResultsMeta.yaml

!net.wg.WoT.models.DAAPIModel type: window #     Flash  python: #  Python ,     Flash - BattleResultsMetaPy: [ eventBus : net.wg.py.app.EventBusPy ] #  constructor: eventBus - saveSorting: [ iconType : String , sortDirection : String , bonusType : int ] #     - showEventsWindow: [ questID : String ] #      flash: #  Flash ,     Python - BattleResultsMeta: [ ] #  constructor: - as_setData: [data : Object] #        Flash 

After processing this YAML file during project assembly, the following set of classes and interfaces will be generated:

BattleResultsMeta is a basic Python class. It declares a set of all methods from the python-section of YAML for their subsequent overload in the class-successor and a set of methods from the flash-section, to be able to access them from Python by the signature declared in YAML.

 class BattleResultsMeta(DAAPIModule): def saveSorting(self, iconType, sortDirection, bonusType): self._printOverrideError('saveSorting') def showEventsWindow(self, questID): self._printOverrideError('showEventsWindow') def as_setDataS(self, data): if self._isDAAPIInited(): return self.flashObject.as_setData(data) 

BattleResultsMeta - base AS3 class. It declares a set of all methods from the python section of YAML, to be able to access them from Flash by the signature declared in YAML. It is these methods that are declared as fields with the type Function, and they will be replaced by the Python methods from the previous paragraph, after setting up the DAAPI connection.

 public class BattleResultsMeta extends AbstractWindowView { public var saveSorting : Function = null; public var showEventsWindow : Function = null; public function saveSortingS(iconType : String, sortDirection : String, bonusType : int) : void { App.utils.asserter.assertNotNull(saveSorting); saveSorting(iconType, sortDirection, bonusType); } public function showEventsWindowS(questID : String) : void { App.utils.asserter.assertNotNull(showEventsWindow); showEventsWindow(questID); } } 

IBattleResultsMeta - AS3 interface. It declares a set of all methods from the YAML python and flash sections. The class that implements the functionality of the post-combat statistics window must implement this interface.

 public interface IBattleResultsMeta extends IEventDispatcher { function saveSortingS(iconType : String, sortDirection : String, bonusType : int) : void; function showEventsWindowS(questID : String) : void; function as_setData(data : Object) : void; } 

Now, to integrate the new window into the client, you need to perform several steps


Some of these steps can also be automated as part of the YamlTask ​​run. I chose the simplest approach in order not to complicate the story.

Dances with a tambourine are finished. To show a new window in the client, it is enough for the Python-part of our Application to call the loadView method, to which the unique identifier of the new component is passed.

What happens after we cause our window to load

Here is a simplified algorithm for working on the module loading and initialization (the steps in Python are highlighted in blue, the steps are pink in Flash):

image

All these steps are performed by various parts of our infrastructure layer, which isolates the developer of functionality from the need to do these steps with his hands. This layer solves the following tasks:


Future plans

The most voluminous task for the foreseeable future is the translation of HUD to AS3. We are currently conducting research and are preparing a project for such a transition. The main thing we want to achieve in this transition is to unify the mechanisms for adding and developing new functionality and getting rid of the variety of approaches that we have now.

We also want to at least not degrade the performance and memory consumption of the new HUD, and in the best case, achieve performance gains and a decrease in the amount of memory required for the HUD to work.

In addition, we have a number of activities aimed at simplifying and improving the process of interaction with related departments during the development and development of new functionality.

The bottleneck is interaction with the User Experience (UX) department. Now, when developing new game concepts or new functionality, it is often necessary to create a prototype on the basis of which it is possible (before transferring the task to development) to evaluate the convenience or ease of understanding the basic mechanics by simple players.

Creating such prototypes outside the client is expensive and may not always give the desired effect. Not having the context or environment that we have in the client, we can not achieve the desired level of immersion in the game. It remains to create prototypes within the game client. This is also very expensive, because for this, developers have to distract from their main occupation and redirect their efforts to perform work that may be completely forgotten and not claimed after the test.

Even if the test was successful, it is likely that everything will have to be redone. In pursuit of reduced costs and due to the tight deadlines for the execution of the prototype, we often have to resort to the use of crutches, coarse-grained files and patches.

To solve this problem, we plan:

• create a set of standard components (buttons, indicators, lists, etc.);

This step is due to the fact that until recently almost every major new task introduces, in addition to the newest functionality, a set of new components. They have to be done on the basis of old ones, changing their appearance and making changes in the logic of their work, or re-implementing these components. The UX department is engaged in creating a list of standard components and forming requirements for them.

• create rapid prototyping tools.

Relying on the library of standard components, we plan to create a separate tool or mode in the client, in which UX specialists will be able to create new interfaces without the intervention of programmers and set up simple rules for their interaction with each other. Such prototypes will be built only from standard components. They can be saved and loaded for execution at the client and tested at minimal cost.

That's all I wanted and could tell you about the GUI in World of Tanks. Ask questions in the comments. Thanks for attention.

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


All Articles