January 10, 2025
  • Home
  • Default
  • Unity in Action: Segment One of Our Collective Journey
A Solidarity mission for all platforms: Segment 1

Unity in Action: Segment One of Our Collective Journey

By on November 27, 2024 0 25 Views

Today, I would like to present one of the template projects, the configurations and modules of which I utilize from project to project. With its assistance, I will illustrate one of the options for developing a Unity game that can operate on various platforms, including Steam, Android devices (Google Play), and web platforms (supported by Playgama (Instant) Bridge, for example, CrazyGames, Game Distribution, Playgama, Yandex Games, and many others). This template project encompasses the following topics:

– Working with common project classes

– Saving game data

– Importing textures, handling sprites, and Sprite Atlas

– Transitioning between scenes

– Establishing build settings

– Creating a .gitignore file

– Video playback

– Playing music and sound effects

– Input System

– Working with metrics

– Classes for monetization through advertising

– Localization

In this article, we will explore the initial few topics; the remaining will be outlined in future articles.

The template project is available for download at the following link.

A brief disclaimer: using this template does not guarantee successful moderation on specific platforms; each game has its own intricacies that, in one way or another, affect the successful navigation of moderation hurdles.

In this project, I aimed to encapsulate the most commonly used mechanisms that are essential in nearly every game.

So, let’s get started…

Working with common project classes

First, a few words regarding the project structure. If everything is fairly clear with most of the folders (and we will examine all of them in their respective chapters), then the Scripts folder deserves particular attention. This folder contains all the scripts that inherit from the MonoBehaviour class, which can also be attached to game objects as components.

The Services folder includes classes for managing localization, metrics, sound, and advertising.

The Settings folder comprises everything necessary for effectively organizing and loading game data.

The Utilities folder contains several constant classes, as well as a collection of static utility classes with auxiliary functions.

In this chapter, we will focus on two primary classes from the Scripts folder, specifically SingletonServices and GameServices.

Let’s start with the first and most commonly used. SingletonServices, as its name implies, operates on the concept of the singleton pattern; thus, when initializing project objects, only one instance of the SingletonServices class will be created. This class provides access to all available auxiliary services of the game that may be needed in any scene. I emphasize the term “any” because if, for instance, we compare this class with GameServices, its usage is limited to game scenes only, excluding the initialization scene. However, we will discuss it a bit later.

The SingletonServices“`html
The class retail outlets links to services and products for managing localization, audio, advertising, and metrics. Here, you can also gather strategies for loading and storing game configurations, as well as a method for retrieving sprites by their identifier. For example, saving game configurations utilizing this class will appear as follows:

_singletonServices.SaveSettings();

where the _singletonServices variable was initially set up like this:

SingletonServices _singletonServices = SingletonServices.Instance;

To function correctly, SingletonServices should be included in the game object during the initialization scene (InitScene).

The second significant class – GameServices is also a singleton and is utilized to integrate classes and methods related to game objects. For instance, it manages the game menu and displays the game interface, while also allowing language switching, among other functionalities. With the considerable expansion of the project, I still recommend isolating, such as dedicating tasks associated with the game UI to a separate script and utilizing GameServices solely as an intermediary class for accessing the UI controller. This is not particularly necessary in our template project. To operate correctly, GameServices should be incorporated into the game object on the scene immediately following the initialization scene (in our case, this is MainScene). Additionally, since GameServices utilizes SingletonServices methods internally, it should be initialized after the latter. To achieve this, navigate to the project settings and adjust the script execution order as follows:

Saving game data

As previously mentioned, all scripts related to saving game data can be found in the Scripts/Settings folder.

GameSettings serves as the primary object for game data. I have indeed included several fields for storage within it, such as the selected language and the number of button clicks.

The file directly involved in loading and saving GameSettings is referred to as FileSettingsAdapter. It implements the ISettingsAdapter interface, which contains only two methods: loading and saving.

Saving data is generally straightforward, but it’s worth mentioning a few details regarding the signature of the loading method. It currently looks like this:

void LoadSettings(Action callAfterLoad);

The method doesn’t return any value but solely accepts a delegate as a parameter, which is a reference to the method that should be invoked after the data loading is completed. In standard scenarios (for example, on PC and Android builds), this structure is not necessarily required. This approach is implemented to enhance the web version, which we can discuss in detail in one of the upcoming articles.

The entire process of loading game settings can be reviewed in the SingletonServices.Beginning method, while the saving procedure can be observed in the GameServices.IncreaseCounter.

Importing textures, managing sprites and Sprite Atlas

Let’s now concentrate on the components of the Sprites folder and begin with a small, optional TextureImporter file. For some unknown reason, Unity decided to modify the default behavior of the sprite importer and began to set the Sprite Mode to Multiple by default (previously it was Single), which means that the added image can contain multiple sprites, for instance, it may be a sprite sheet for character animation. Thus, if your project has significantly fewer sprite sheets than typical single sprites, you can create a TextureImporter and configure sprite settings for it, which will be applied to all imported textures by default. To do this, within the importer settings, it is necessary to click the preset selection button and create a new one with the desired import parameters.

We adjust all essential parameters of the created preset (in the context of this specific template project, the Sprite Mode was changed to Single, and compression was disabled) and add the preset to the default options.

Now, when adding new sprites, their settings will adhere to the configurations of the newly created TextureImporter
“`
.

Now let’s examine the SpriteAtlas file, which not only indicates that you can reduce the number of draw calls, but also offers a convenient way to retrieve sprites by their name in the code. You can create a sprite atlas in the following manner:

Now concerning the atlas configuration.

It’s essential to be extremely mindful with the Enable Rotation and Tight Packing options. These options are activated by default, but they can sometimes lead to various distortions, flips, and artifacts if you change sprite components dynamically in your code.

And of course, do not forget to include folders that can be nested within the created sprite atlas. In our case, this is one folder named Atlas. Within the Sprites directory, there is also a NonAtlas folder, which, as you might guess from the name, we do not include in the sprite atlas. For example, you can store icons, a cursor, and more here.

An example of retrieving sprites from a sprite atlas by name can be found in the SoundsButtonController.Beginning method.

Transitions between scenes

An example of transitioning from the initialization scene to the main scene can be observed in the InitSceneLoader class. I should mention that this script needs to be added as a component to the game object in the InitScene scene.

In the LoadingCheck function of this script, we wait for the initialization of all primary services, which are crucial for our game to function, and if everything goes well, in this case the intro video is played, followed by the transition to a new scene utilizing the SceneManager.LoadScene method. Playing the video is not strictly necessary and serves only as an illustration. However, you could easily start any animation or directly switch to the main scene without any additional steps.

Build settings for the project

The main branch of the project is currently set up for the Android build, so in this section I will outline the key settings for this platform, while I will provide additional settings in future articles.

Thus, when creating an Android project, I first navigate to the Build Settings -> Player -> Publishing settings section and check the following files: Custom Main Gradle Template, Custom Gradle Properties Template and Custom Gradle Settings Template.

Believe me, this will save you from a considerable headache when it comes to importing and using third-party packages, such as the EDM kit, also known as external dependency manager, which is essential for Firebase, Appodeal, and other libraries.

Next, I navigate to the Other Settings configuration, set the package name, and adjust the Target API Level.

By default, the Target API Level is set to Automatic (highest installed), meaning that when building an Android project, Unity will rely on the Android SDK and NDK already installed on your computer. For example, if version 33 is installed, then after building the project you will not be able to upload it to the Google Play Console, since currently the minimum required Target API Level must be 34. However, I wouldn’t recommend rushing to set the highest version either, or at least have the option to test your application on multiple devices. Otherwise, you might encounter something like this:

In short, do not ignore this, because if you set the Target API Level to 34, the game crashes when launched on devices with API level 34 (it functions perfectly on others). The remedy here is, unfortunately, not straightforward, as you need to upgrade Unity to a later version that includes the fix, which isn’t always easy nor painless.

Build .gitignore file

I would like to conclude today’s segment of the article with a brief mention of the .gitignore file. There is nothing particularly special here; it currently includes all the files and directories that should not be added to the repository. I will simply add that it excludes the folders web_build and PCBuild. I often include these folders myself, and they are, interestingly enough, used exclusively for builds of the respective platforms.

That’s all for today; we will continue to explore this template project in future articles. However, you can download and analyze it yourself right now by following the link.

I’m compiling wishlists here and here.

Thank you for your attention!

Visit my website

Learn More

  Default
Leave a comment

Your email address will not be published. Required fields are marked *