icon

Платформы

Plugin Your Games 2.0 — мультиплатформенный. Переключаются в два клика!
При переключении платформы устанавливаются соответствующие настройки проекта. Всё гибко настраивается и можно даже создавать свои опции, которые будут вносить изменения в настройки проекта. Или опции могут просто меняться в зависимости от платформы, чтобы в коде получать разные значения для разных платформ.
Если вы можете интегрировать SDK какой-либо площадки в свою игру, то можете попробовать создать свой модуль платформы для PluginYG2.
Бесплатно предоставляется сам PluginYG2 и платформа YandexGames. Остальные готовые платформы я публикую у себя на Boosty всего за 200р.

Настройки платформ

В настройках Plugin Your Games → Basic Settings есть поле Platform — это выбор платформы и ссылка на её настройки.
Настройки платформы удобнее всего открыть в отдельном окне — для этого нажмите правой кнопкой мыши по ссылке → Properties....
icon
В данном примере:
YandexGames — название платформы. Его можно получить из поля YG2.platform.
YandexGamesPlatform_yg — используется для Scripting Define Symbols.
Настройки проекта — в этом разделе содержатся опции настроек проекта, для которых есть необходимость настраивать по разному для разных платформ. При применении настроек платформы — установятся только те опции, которые активированы флажком слева. Активность опций будет одинаковая для всех платформ.

При обновлении платформы (импорте) снемите флажок с файла настроек платформы, если не хотите чтобы они слетели:
icon

Сборка игры под Android
Удалите платформу из поля Platform в разделе Basic Settings настроек плагина. В таком случае, практически никакой код плагина не попадёт в билд игры, только малая доля, которая может пригодится и для мобильных устройств. Например, локальные сохранения продолжат свою работу.
Ниже будет рассмотрено, как создать свою платформу. Таким образом, вы можете как минимум подключить к плагину монетизацию, которую вы испротзуете для мобильных устройств. Тогда можно будет менять платформу в два клика и собирать игру под Android и под WebGL без корректировок проекта.

PlatformEventsYG2 компонент

Данный компонент может выборочно выполнять различные методы в зависимости от текущей платформы. Таким образом, можно скрыть некоторые элементы для определённого списка платформ:
icon
В этом примере для Yandex Games видно все элементы, а для Crazy Games они скрываются, т.к. в CG эти модули не работают из-за отсутствия такого функционала у площадки.

Чтобы сделать также, выберите платформы для которых будут выполняться методы и привяжите какие угодно методы. В примере используется деактивация игрового объекта, такой метод привязывается по умолчанию.
Затем можно выровнять элементы интерфейса, чтобы они адаптировались под изменения — с помощью компонента Grid Layout Group.

Работа с кодом

Нечто аналогичное как с компонентом Platform Events YG2 можно делать и в коде, используя вышеупомянутые поле YG2.platform и дефайны. Например:

using UnityEngine;
using YG;

public class MyClass : MonoBehaviour
{
    public void MyMethod()
    {
        if (YG2.platform == "CrazyGames")
        {
            gameObject.SetActive(false);
        }

#if CrazyGamesPlatform_yg // Код какого то из условий не попадёт в билд
        gameObject.SetActive(false);
#else
        gameObject.SetActive(true);
#endif
    }
}

Методы опциональные

Есть методы с разной реализацией для разных платформ, что позволяет использовать один метод, который будет вести себя по разному для разных платформ.

Метод FirstInterAdvShow — например, CrazyGames требует, чтобы самый первый показ рекламы при открытии первого уровня/локации проигнорировался. Метод FirstInterAdvShow проигнорирует первый показ рекламы для CrazyGames, а для YandexGames покажет рекламу в любом случае. После того, как реклама будет показана с помощью данного метода, информация об этом сохранится и реклама будет показана в любом случае, даже при после перезагрузки страницы. Чтобы сбросить эти сохранения, в Unity Editor необходимо отчистить Player Prefs. Для тестирования в вебе откройте игру в режиме инкогнито.

Метод OtherInterAdvShow покажет рекламу на YandexGames, для CrazyGames проигнорирует. В CrazyGames запрещается показывать рекламу при переходе в главное меню игры и в некоторых других местах. Для таких моментов можно использовать метод OtherInterAdvShow, чтобы использовать разные его реализации для разных платформ.

Метод LoadInterAdv будет подгружать рекламу для платформ, в которых это необходимо. Для YandexGames и CrazyGames такого нет, по этому метод у них пустой. Такой же метод есть для рекламы за вознаграждение LoadRewardedAdv.

Все опциональные методы содержатся в классе OptionalPlatform. Пример вызова такого метода:
YG2.optionalPlatform.FirstInterAdvShow();

Опциональные методы также можно выполнять без кода через компонент EventsYG2.

Создание опций

Можно создать новые опции для двух разделов:

  1. Такие же опции как мы рассматривали ранее. Их можно сделать с флагами активности и без. Это опции, которые содержат разные значения для разных платформ.
  2. Общие настройки, которые размещаются в отдельном разделе. У них будет одинаковое для всех платформ.
    icon

И в первом и во втором случае нужно создать скрипт, файл которого можно назвать как угодно и таких файлов сделать можно сколько угодно и к ним применимы атрибуты: [ApplySettings], [SelectPlatform], [DeletePlatform].

Создание опций
Пример без флага активности.
Создание поля с разными значениями для разных платформ:
namespace YG.Insides
{
    public partial class ProjectSettings
    {
        public string myOption; // Добавление опции
    }
}
Обращение к созданному полю:
YG2.infoYG.platformOptions.myOption

Также создаётся поле общих настроек, только класс другой:

namespace YG.Insides
{
    public partial class CommonOptions
    {
        public string myCommonOption; // Добавление опции
    }
}
Обращение к созданному полю:
YG2.infoYG.common.myCommonOption

Следующий пример — с добавлением флага активности:

namespace YG.Insides
{
    public partial class ProjectSettings // Или CommonOptions
    {
        public string myOption; // Добавление опции

        [ApplySettings]
        public void MyApplySettings()
        {
            // Сработает при применении настроек платформы. Пример:

            // Получаем ссылку на флаги опций
            PlatformToggles toggles = YG2.infoYG.platformToggles;

            // Если флаг активный - применяем опцию
            if (toggles.myOption == true)
                myOption = "apply";
        }

        [SelectPlatform]
        public void MySelectPlatform()
        {
            // Сработает при выборе платформы
        }

        [DeletePlatform]
        public void MyDeletePlatform()
        {
            // Сработает перед удаление платформы из проекта
        }
    }

    // Добавьте флаг активности
    public partial class PlatformToggles
    {
        public bool myOption; // Флаг должен называться также как опция
    }
}

Создание платформы

Для примера возьмём платформу Crazy Games.

  1. Создайте папку с именем платформы в PluginYourGames/Platforms. Название нужно подобрать тщательно, оно много где будет использоваться.
  2. Создайте текстовый документ Version.txt, в нём запишите версию модуля в таком формате: v1.0.
  3. Создайте файл настроек платформы: ЛКМ → Create → YG2 → New Platform. Настройте по желанию.
  4. Создайте папку SDK — она будет игнорироваться для компилятора, если платформа не активна. В данную папку поместите SDK площадки, если таковой имеется. И все скрипты платформы содержите в папке SDK.

icon

Если вы создаёте WebGL платформу, то шаблон нужно назвать также как назвали платформу. Шаблон — это index.html и другие файлы для WebGL билда. Шаблон должен находиться в папке WebGLTemplates. Сделайте по аналогии с YandexGames.

В настройках PluginYG2 переключитесь на созданную платформу.
В SDK можно создать папку ScriptsYG, чтобы обозначить скрипты для PluginYG. В этой папке создайте базовый скрипт, в котором будет логика инициализации. Я назову скрипт CG_BasicAPI. Вставьте в него шаблон:

#if CrazyGamesPlatform_yg
namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
        public void InitAwake() { }
        public void InitStart() { }
        public void InitComplete() { }
        public void GameplayStart() { }
        public void GameplayStop() { }
        public void HappyTime() { }
    }
}
#endif
Измените дефайн
CrazyGamesPlatform_yg — это дефайн (директива препроцессора). Его можно встретить в следующих местах:
drawing
Измените его название на то, что указано в настройках платформы. Когда название верное, код внутри #if код #endif не серый. Серый он становится тогда, когда дефайна нет в списке Scripting Define Symbols. Это ещё от IDE (редактор кода) зависит, конечно. Если в списке он есть и название верное, но код серый — перезагрузите IDE.
О интерфейсе и методах
Скрипт выше реализует интерфейс IPlatformsYG2.
Представленные методы переопредиляют стандартную реализацию. Для всех методов в интерфейсе IPlatformsYG2 есть стандартная реализация. У представленных методов реализация пустая (кроме InitAwake, его пока не трогать). По этому их можно удалить или оставить так, ничего не изменится. В примере предоставлены самые важные методы, которые есть в PluginYG без отдельных модулей.

По простому, это работает так:
Например, нам нужно выполнить метод SDK платформы GameplayStart. В одноименном представленном методе внутри фигурных скобок прописываем реализацию:

public void GameplayStart()
{
	CrazySDK.Game.GameplayStart();
}
Можно сократить и прописать так:
public void GameplayStart() => CrazySDK.Game.GameplayStart();
Инициализация
Чаще всего SDK предоставляет асинхронный метод инициализации. После того, как игра загрузилась — SDK ещё не готов и нельзя пользоваться его функциями, надо подождать пока SDK инициализируется.
Давайте рассмотрим два варианта:

1. Когда SDK при запуске игры сразу готов (как у платформы YandexGames на PluginYG. Она адаптирована под два варианта). В этом случае нужно только удалить метод InitAwake.
2. Второй случай, когда необходимо дождаться инициализации.

Для второго варианта необходимо включить опцию Sync Init SDK в Basic Settings и настроить вытикающие параметры. Почитайте всплывающие подсказки.

Затем, в реализации InitAwake выполните метод SDK для инициализации. По завершению инициализации выполните метод YG2.SyncInitialization(), чтобы сигнализировать PluginYG о том, что SDK готов. Пример:

public void InitAwake()
{
    if (CrazySDK.IsAvailable) // Требования CrazyGames
    {
        CrazySDK.Init(() =>
        {
            YG2.SyncInitialization();
        });
    }
}
Реализация отдельных модулей
Для удобства скрипты под отдельные модули можно поместить в папку Modules.

Например мы делаем реализацию для модуля некого MyModule. Создадим скрипт с названием файла CG_MyModule. И вставим в скрипт тот же код, что был для инициализации удалив все методы.
Но вот что нам ещё нужно сделать для скипта использующего методы модуля — прописать дефайн:

#if CrazyGamesPlatform_yg && MyMethod_yg // + && MyMethod_yg
namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
        public void MyMethod()
        {
            // Реализация
        }
    }
}
#endif

Мы добавили дефайн модуля. Дефайн состоит из названия модуля и приписки _yg. Это нужно делать, потому что модуль может отсутствовать в проекте и тогда пойдут ошибки.
Инициализация модулей
Многие модули имеют методы для инициализации. Они выполняются после рассмотренного выше метода InitAwake, когда SDK уже готов. Например, у модуля EnvirData есть метод InitEnvirData — в нём данные вроде device, language из SDK записываются в поля плагина. И для новой платформы тоже нужно передавать таким образом данные. Вот как выглядит готовый скипт CG_EnvirData:
#if CrazyGamesPlatform_yg && EnvirData_yg
using CrazyGames;

namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
        public void InitEnirData()
        {
            if (CrazySDK.User.IsUserAccountAvailable) // Требование платформы
            {
                YG2.envir.language = CrazySDK.User.SystemInfo.countryCode.ToLower();
                YG2.envir.browser = CrazySDK.User.SystemInfo.browser.name;
                YG2.envir.platform = CrazySDK.User.SystemInfo.os.name;

                string device = CrazySDK.User.SystemInfo.device.type;
                YG2.envir.deviceType = device;

                switch (device)
                {
                    case "desktop":
                        YG2.envir.isDesktop = true;
                        break;
                    case "tablet":
                        YG2.envir.isTablet = true;
                        break;
                    case "mobile":
                        YG2.envir.isMobile = true;
                        break;
                }
            }
        }

        public void GetEnvirData()
        {
            InitEnirData();
            YG2.GetDataInvoke();
        }
    }
}
#endif

Метод GetEnvirData — обновляет данные в процессе игры. И в конце он выполняет метод YG2.GetDataInvoke, который вызовет событие onGetSDKData если PluginYG уже полностью инициализирован. Данное событие может вызвать некоторые обновления данных плагина на сцене.
Асинхронная инициализация модулей
Бывает такое, что асинхронные методы есть не только для инициализации. Например, для Crazy Games нужно асинхронно инициализировать ещё данные игрока. Все асинхронные инициализации необходимо выполнить в методе InitAwake. По этому в скрипте с базовыми реализациями мы инициализируем и данные игрока, но зададим условие — если импортирован модуль авторизации. Вот так выглядит итоговый скрипт CG_BasicAPI:
#if CrazyGamesPlatform_yg
using CrazyGames;

namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
#if Authorization_yg
        public PortalUser User;
#endif
        public void InitAwake()
        {
            if (CrazySDK.IsAvailable)
            {
                CrazySDK.Init(() =>
                {
#if Authorization_yg
                    if (CrazySDK.User.IsUserAccountAvailable)
                    {
                        CrazySDK.User.GetUser(user =>
                        {
                            User = user;
                            YG2.SyncInitialization();
                        });
                    }
                    else
                    {
                        YG2.SyncInitialization();
                    }
#else
                    YG2.SyncInitialization();
#endif
                });
            }
        }
    }
}
#endif

Сохраняем данные в поле User. Используем его для записи данных в методе инициализации модуля. Готовый скрипт CG_Authorization:
#if CrazyGamesPlatform_yg && Authorization_yg
using UnityEngine;
using CrazyGames;

namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
        public void InitAuth()
        {
            if (CrazySDK.User.IsUserAccountAvailable)
            {
                YG2.player.auth = true;
                YG2.player.name = User.username;
                YG2.player.photo = User.profilePictureUrl;
            }
        }

        public void GetAuth()
        {
            if (CrazySDK.User.IsUserAccountAvailable)
            {
                CrazySDK.User.GetUser(user =>
                {
                    User = user;
                    YG2.GetDataInvoke();
                });
            }
        }

        public void OpenAuthDialog()
        {
            CrazySDK.User.ShowAuthPrompt((error, user) =>
            {
                if (error != null)
                {
                    Debug.LogError("Show auth prompt error: " + error);
                    return;
                }

                User = user;
                InitAuth();
                YG2.GetDataInvoke();
            });
        }
    }
}
#endif
Подытожим:

  1. Все реализации происходят в одном классе PlatformYG2.
  2. Для реализации нужно переопределить существующий метод.
  3. Сначала выполняется метод InitAwake, потом методы инициализации модулей. Потом метод InitStart, за ним InitComplete.
  4. Если требуется, в методе InitAwake производим асинхронные инициализации. Если нужно, сохраняем некоторые данные для модулей.
  5. Переопредиляем реализации для модулей.

Реализация рекламы

Все методы в интерфейсе для модуля можно найти в папке модуля → Scripts. Скрипты интерфейсы помечены подпиью interface. Там же можно посмотреть и стандартную реализацию.
Вместе со всеми модулями идёт реализация для стандартной платформы YandexGames. Содержится в скриптах с подписью yandexPlatform.
В скриптах с подписью yg содержится логика самого модуля. В info опции из настроек PluginYG.
icon

Рассмотрим реализацию для Interstitial Adv:

#if CrazyGamesPlatform_yg && InterstitialAdv_yg
using CrazyGames;
using YG.Insides;

namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
        public void InterstitialAdvShow()
        {
            CrazySDK.Ad.RequestAd(CrazyAdType.Midgame, () =>
            {
                YGInsides.OpenInterAdv();
            }, (error) =>
            {
                YGInsides.ErrorInterAdv();
                YGInsides.CloseInterAdv();
            }, () =>
            {
                YGInsides.CloseInterAdv();
            });
        }

        public void FirstInterAdvShow()
        {
            OptionalPlatform.FirstInterAdvShow_RealizationSkip();
        }

        public void OtherInterAdvShow() { }
    }
}
#endif
Здесь мы переопредиляем реализацию для метода InterstitialAdvShow. CrazyGames предоставляет коллбеки открытия, закрыти и т.д. рекламы.

В соответствующих коллбеках выполняются методы из внутреннего класса YGInsides, в нём содержится всё скрытое. Так мы выполняем, например, метод закрытия рекламы: YGInsides.CloseInterAdv();

А в OptionalPlatform содержатся готовые реализации для опциональных методов. О них сказано выше.

Реализация локализации

Создайте метод GetLanguage, который должен вернуть язык. Пример:

#if CrazyGamesPlatform_yg && Localization_yg
using CrazyGames;

namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
        public string GetLanguage()
        {
            if (CrazySDK.User.IsUserAccountAvailable)
            {
                return CrazySDK.User.SystemInfo.countryCode.ToLower();
            }
            return "en";
        }
    }
}
#endif

Реализация облачных сохранений

Метод LoadCloud должен загружать сохранения. Для этого нужно передавать их в json строке методу YGInsides.SetLoadSaves. Стандартное значение указываем Null. Если передаваемое значение будет нулевым или это будет пустая строка, то сохранения сбросятся.
Метод SaveCloud должен сохранять. Сохраняем поле YG2.saves. Пример:

#if CrazyGamesPlatform_yg && Storage_yg
using UnityEngine;
using YG.Insides;
#if NJSON_STORAGE_YG2
using Newtonsoft.Json;
#endif
using CrazyGames;

namespace YG
{
    public partial class PlatformYG2 : IPlatformsYG2
    {
        private const string KEY_SAVE = "CG_SavesYG";

        public void LoadCloud()
        {
            string jsonSaves = CrazySDK.Data.GetString(KEY_SAVE, null);
            YGInsides.SetLoadSaves(jsonSaves);
        }

        public void SaveCloud()
        {
#if NJSON_STORAGE_YG2
            CrazySDK.Data.SetString(KEY_SAVE, JsonConvert.SerializeObject(YG2.saves));
#else
            CrazySDK.Data.SetString(KEY_SAVE, JsonUtility.ToJson(YG2.saves));
#endif
        }
    }
}
#endif
Локальные сохранения и сохранения для смуляции в Unity Editor уже реализованы в логике самого модуля.

Создали модуль? Напишите мне 😀 mbornysov@mail.ru