Как стать автором
Обновить

Комментарии 23

Не уверен, что Static класс это хорошее решение проблемы, почему не использовать возможности Unity (Object.DontDestroyOnLoad, Game Manager, Singleton Unity3D) для продления жизни GameObject между сценами? По крайне мере на основе паттерна Singleton я сделал, чтобы очки игрока сохранялись между сценами.

public class GameStatus : MonoBehaviour
{
    ...

    // State variables
    [SerializeField] private int _currentScore = 0;

    void Awake()
    {
        int objectsCount = FindObjectsOfType<GameStatus>().Length;

        if (objectsCount > 1)
        {
            gameObject.SetActive(false);
            Destroy(gameObject);
        }
        else
        {
            DontDestroyOnLoad(gameObject );
        }
    }

    ...

    public void ResetGame()
    {
        Destroy(gameObject);
    }    
}

Даже в ссылках которые вы прикрпели (Static Class) используется Singleton
В статье описан личный опыт в основном, на идеальность решения не претендую.
Вообще нужно посчитать, что будет затратнее по ресурсам, они дороги, так как проект ориентирован на мобильные. Меня учили, что на сцене лучше лишних объектов не держать, но буду рада если расскажете почему решение с синглтоном лучше.
Если вы не претендуете, то вот это определенно лишнее
Данная статья будет полезна начинающим разработчикам игр.
)))
Статик, мягко говоря, так себе решение. Представьте ситуацию, когда вам надо ресетнуться, полоностью перезапустить игру, а у вас в статике 100500+ полей. Будете ручками все это дефолтить? Статик для констант удобен. Хотя если аккуратно, то имеет право на жизнь, например в качестве контейнеров.

эм, но в таком случае в статик кладется объект а-ля AllStaticData и обнуляется только он.

Это ад перфекциониста )))

И почему это плохо, иметь статичный, доступный отовсюду некий GameState?

Я использовала здесь статик, потому что храню в нём ровно два поля :)
Но да, полезная ремарка, если начинающий разработчик вдруг решит туда напихать гораздо больше.
Попыталась намекнуть на это словами «простых игр» в названии, буду аккуратнее.
Вот, вот. А соблазн запихать туда всё, что можно и нельзя, появится в следущую секунду, после того, как человек узнает и поймет, что такое статик )))
Данный способ позволяет уничтожить объект в случаее необходимости, а также использовать в связке с другими игровыми объектами на экране, например с общим HUD между сценами. Касаемо статика, клас будет болтаться в памяти с момента первого к нему обращения и до закрытия приложения.
А если его и не нужно уничтожать? Что значит «использовать в связке с другими объектами»?
Как пример, что вы можете поместить в данный объект логику не только по хранению чего-то, но и взаимодествия с элементами управления на UI. Обновление счетчика жизний и брони, очков и т.д. Касаемо данного пункта это не совсем про вашу проблему, а один из способов применения данного функционала.
Спасибо, это интересно! Покопаю эту тему тоже
Не уверен, что хранить очки игрока в синглтоне — хорошая идея. При вылете или намеренном снятии активити, весь прогресс в трубу. Для этого есть плеерпрефс или сохранение в облако. Не нужно заставлять игрока чувствовать боль из-за багов вашей игры
Я не являюсь разработчиком игр, это для меня только fo fun. Я лишь привел примел где показал способ передачи состояния между сценами.
Примеры использования? И как жить с тем, что он хранится как ассет, и если в редакторе запустить игру — получим измененный ассет?

Советую посмотреть на Dependency Injection и DI / IoC фреймворки вроде ZenJect (линк).
Знаю, что для новичка это не простая концепция, но она имеет большое количество преимуществ перед синглтонами/статик классами/DontDestroyOnLoad.


Данный подход позволит сделать единую точку входа в приложение, а для хранения данных пользователя вместо singleton объекта можно использовать сервис (который потом можно заинъектить в необходимые вам скрипты):


public interface IGameDataService
{
    public int DifficultyLevel { get; set; }
}

public class EnemyInstaller : MonoInstaller
{
    public override void InstallBindings()
    {
        // IGameDataService будет автоматически инъекцировано в зависимые классы
        // включая другие сцены, если использован Scene Container Parenting
        Container.Bind<IGameDataService>().To<GameDataService>().AsSingleton();
    }
}

public class EnemyFactory : IEnemyFactory
{
    private readonly IGameDataService _gameDataService;

    // Зависимость будет добавлена в конструктор автоматически при резолвинге EnemyFactory
    // Для инъекции в MonoBehavior, можно добавить специальный компонент ZenjectBinding и аттрибут [Inject]
    public EnemyFactory(IGameDataService gameDataService)
    {
        _gameDataService = gameDataService;
    } 

    public void SpawnEnemy(string enemyName)
    {
         var level = _gameDataService.DifficultyLevel;
         ...
         var enemy = GameObject.Instantiate(...).GetComponent<IEnemy>();
         enemy.SetLevel(level);
    }
}

В идеале, GameObject'ы и MonoBehavior'ы — для объектов игрового мира. Для всего остального есть обычный C#.

О, спасибо! Нигде не встречала информацию про этот подход, а выглядит он очень круто. Можете ссылки посоветовать где почитать? Погуглить я конечно тоже погуглю
читайте ридми на гитхабе зенджекта, там все подробно расписано, в том числе с примерами
А следующим шагом можно ознакомиться с ECS (Entity-Component-System) архитектурой.
Окей, спасибо, посмотрю
Спасибо тебе, что Unity называешь не Unity3d
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории