cool20141 cool20141

<a href= http://mosros.flybb.ru/viewtopic.php?f=2&t=635>Процесс получения диплома стоматолога: реально ли это сделать быстро?</a>

danilaxxl danilaxxl

CollectableItemData.cs

[CreateMenuItem(fileName = "newItem", menuName = "Data/Items/Collectable", order = 51]

GoloGames GoloGames

vadya_ivan, рад, что вам игра показалась интересной : )

P.S. Кстати уже доступна бесплатная демо-версия в Steam

vadya_ivan vadya_ivan

Визуал, задумка, музыка , механики, все в цель

GoloGames GoloGames

Ato_Ome, спасибо за позитивные эмоции, будем стараться : )

Ato_Ome Ato_Ome

Потрясающий результат, все так четенько, плавненько)
То ли саунд, то ли плавность напомнили мне игрушку World of Goo, удачи вам в разработке и сил побольше дойти до релиза!)

Cute Fox Cute Fox

Graphics are a little cool, good HD content. But this game doesn't cause nary interest me.
However the game is well done.

GMSD3D GMSD3D

Почему действие после всех условий выполняется?
[step another object]

Zemlaynin Zemlaynin

Jusper, Везде, но наугад строить смысла нет. Нужно разведать сперва территорию на наличие ресурсов.

Jusper Jusper

Zemlaynin, а карьеры можно будет везде запихать?
Или под них "особые" зоны будут?

Zemlaynin Zemlaynin

Это так скажем тестовое строительство, а так да у города будет зона влияния которую нужно будет расширять.

Jusper Jusper

А ссылка есть?

Jusper Jusper

Я не оч понял из скриншота, как вообще работает стройка. У игрока будет как бы поле строительства?

split97 split97

в игру нужно добавить время песочные часы в инвентаре, пока бегаешь наберается усталость и ты очень тормозной мобильный враг просто убевает

split97 split97

в игру нужно добавить время песочные часы в инвентаре, пока бегаешь наберается усталость и ты очень тормозной мобильный враг просто убевает

ViktorJaguar ViktorJaguar

Почему я нигде не могу найти нормальный туториал, где покажут как экипировать предмет (например, меч) в определенную (выделенную под оружие) ячейку???

Логотип проекта Unity

Паттерны. "Singleton", "Decorator". Unity

Паттерны. "Singleton", "Decorator". Unity

Здравствуйте уважаемые читатели данной статьи. Сегодня я решил поговорить о ОО-проектировании в сфере геймдева, используя движок Unity. Сразу скажу, что данная статься является объективным видением использования паттернов и в особенности, их реализация. Кто-то может говорить о том, что в моих далее приведенных примерах лучше использовать тот или иной паттерн и возможно вы будете правы, но моя задача как минимум поверхностно пройтись по этой достаточно сложной теме. Я рассчитываю сделать небольшой цикл статей про разные паттерны и их примерное использование, чтобы архитектура вашего проекта стала гибкой и расширяемой.
Также хочу отметить, что данный цикл будет требовать определенных знаний в области ОО-программирования и базового ознакомления с понятием "паттерн".
Вроде всё оговорил, можем начинать!

Паттерн "Одиночка"

Данный паттерн предназначен для реализации единственного, уникального объекта во всей программе. При разработке игры вы можете столкнутся даже не один раз, когда вам нужно будет реализовать какой-либо модуль для игры (например систему сохранения игры или систему достижений). За продолжительное время в геймдеве я столкнулся с несколькими подходами к реализации уникальных объектов, но сегодня я хочу рассказать о том, на котором остановился на данный момент.
Былое: Ранее, я думал, что все подобные модули, которые я приводил в пример, должны быть уникальными объектами и делал каждый такой модуль на базе паттерна "Одиночка", но вскоре понял, что есть и более элегантный способ.
Собственно, я пришёл к выводу, что лучше всего сделать один единственный класс-одиночку, а внутри него хранить экзмепляры классов, которые могут быть задействованы из любой точки программы. Иначе говоря, у меня есть один класс на базе "Одиночка", который даёт доступ только для чтения всех ранее проинициализированных экземпляров классов.
Вот собственно его реализация:

using UnityEngine;

namespace Game.Main
{
    public class GameStorage : MonoBehaviour
    {
        public static GameStorage Instance { get; private set; }
        public FileManager FileManager { get; private set; }
        public AchievementsManager AchievementsManager { get; private set; }

        private void Awake()
        {
            CheckInstance();
            InitManagers();      
        }

        private void CheckInstance()
        {
            if (Instance == null)
            {
                Instance = this;
                DontDestroyOnLoad(this);
            }
            else
            {
                Destroy(gameObject);
            }
        }

        private void InitManagers()
        {
            FileManager = gameObject?.GetComponent<FileManager>();
            AchievementsManager = gameObject?.GetComponent<AchivementsManager>();
        }
    }
}

Как вы можете видеть, класс-одиночка не сильно привязан к тем экземплярам, которые инициализируются за счёт оператора '??', а также инициализирует он их на том же игровом объекте, на котором находится сам. Это значит, что если вам не обязательно добавлять все модули сразу. С другой стороны, если вы забудете добавить нужный модуль (модуль в моей интерпретации это управляющий класс), то движок вам напомнить не сможет.

Примечание:
Помните, что это пример на Unity и лишь одна из интерпретаций паттерна. Дело в том, что данный вариант не будет работать корректно с несколькими потоками. Возможным решением может стать ключевое слово для статического экзмепляра одиночки "volatile". С учётом новой Job System в Unity, для меня неизвестно, как именно будет работать одиночка, стоит проверить.

Вот, собственно, и всё, данный подход можно использовать для вызова методов из разных модулей в любом классе.

Более подробнее ознакомится с паттерном можно будет здесь

Паттерн "Декоратор"

Лично я вижу сложность в том, чтобы придумать серьезную практическую задачу для данного паттерна. Его суть в том, что он создаёт некоторые дополнения для одного объекта. Это если говорить двумя словами, но на деле всё может показаться чуть сложнее.
Предположим, что у нас есть класс "Weapon". Мы хотим, чтобы наше оружие могло иметь разные модификации (глушитель, прицел, например), это и будут называться "дополнения" для одного объекта "Weapon". Сам процесс добавления таких дополнений реализован посредством "оборачивания" объекта "Weapon".
В нашем случае, рассмотрим простой пример с пистолетом и глушителем и выведем конечное описание оружия.
Создадим для начала абстрактный класс Weapon:

using UnityEngine;

namespace Patterns.Decorator
{

    public abstract class Weapon : MonoBehaviour
    {
        [SerializeField]
        private string nameWeapon;       

        public abstract string GetDescription();
        public string GetWeaponName() => nameWeapon;
    }
}

Далее, чтобы добавлять разные модные штучки на нашу мощную пушку, сделаем класс-обертку, которая будет являться классом-наследником для класса "Weapon" и назовём этот класс "WeaponWrapper". Вот как он выглядит:

using UnityEngine;

namespace Patterns.Decorator
{

    public abstract class WeaponWrapper : Weapon
    {
        protected Weapon weapon;

        public void SetWeapon(Weapon weapon) => this.weapon = weapon;

        public override string GetDescription() => weapon.GetDescription();

    }
}

Но не будем спешить и сделаем класс, который будет нашей пушкой (конкретной реализацией). Пусть это будет пистолет. Собственно его реализация:

using UnityEngine;

namespace Patterns.Decorator
{

    public class WeaponPistol : Weapon
    {
        private WeaponWrapper muffler = new Muffler();

        public override string GetDescription()
        {
            return GetWeaponName();
        }

        private void Start()
        {
            Debug.Log(GetDescription());
            muffler.SetWeapon(this);
            Debug.Log(muffler.GetDescription());
        }
    }

}

Что такое "Muffler"? Сейчас покажу, но скажу пока кое-что на счёт данного класса. В данном примере я хочу выводить описание нашего оружия. Как видите, здесь я вывожу описание сначала пистолета (просто название оружия), а потом описание объекта "Muffler". Перейдём теперь к классу "Muffler".

Сделаем класс, который будет одним из модификаций для нашей пушки, пусть это будет глушитель. Класс будет называться "Muffler" и выглядеть так:

using UnityEngine;

namespace Patterns.Decorator
{

    public class Muffler : WeaponWrapper
    {

        public override string GetDescription()
        {
            return weapon.GetWeaponName() + " с глушителем";
        }
    }
}

Теперь, если вернуться обратно к пистолету, то теперь можно понять, что выводится описание, казалось бы, глушителя, но это не совсем так. Точнее так, но в описании глушителя я вывожу и название оружия, к которому он прикреплён. Тогда результат будет следующим:

Паттерны. "Singleton", "Decorator". Unity — Unity — DevTribe: инди-игры, разработка, сообщество (GameDev, patterns, Unity)

Как видите, в данном случае, не оружие хранит модификации, а модификации хранят оружие. В этом специфика данного паттерна. Возможно, с точки зрения логики, было бы правильнее хранить модификации оружия внутри класса оружия, однако, как я говорил ранее, придумать пример на базе такого паттерна в сфере разработки игр для меня оказалось достаточно интересной задачей. Может быть ваш пример будет гораздо лучше? Если так, то предлагайте, будет интересно посмотреть!
В конце хочется отметить, что данный паттерн хорошо используете в комбинации с паттерном "абстрактная фабрика", но сегодня мы рассмотрели чистый паттерн "декоратор" суть которого дополнять объект новыми свойствами без изменения классов самих оружий.

Более подробно ознакомится с паттерном можно здесь

Спасибо за внимание!

Смотрите также:


Комментарии



Весьма интересный подход к реализации синглтона в Unity. Надо взять на заметку, а то я сейчас просто через FindObject пытаюсь найти инстанс к таким важным вещам. Единственное, как быть если все такие компоненты разбросаны в разных частях сцены? Например, InventoryController, UnitSelectionController и т.д.?

alexprey, В таком случае, вы можете самостоятельно инициализировать экземпляры этих классов через инспектор. Например:
[SerializedField]
private InventoryController inventoryController;
А далее просто сделать общедоступный Get-метод для доступа к этому объекту, как вариант :)
Однако минус такого подхода в том, что при переходе между сценами, будут проблемы. В таком случае, нужно заранее продумать все детали.

RedHelium, да действительно, все чуть проще чем я себе накрутил...

alexprey, В таком случае, вы можете самостоятельно инициализировать экземпляры этих классов через инспектор. Например:
[SerializedField]
private InventoryController inventoryController;
А далее просто сделать общедоступный Get-метод для доступа к этому объекту, как вариант :)
Однако минус такого подхода в том, что при переходе между сценами, будут проблемы. В таком случае, нужно заранее продумать все детали.
alexprey, Немного порассуждав над вопросом, я для себя понял следующее. Если у вас много таких классов, к которым можно обратится из любого класса, то вероятно, лучший способ - подумать над архитектурой т.к. рационально ли хранить, скажем на 10-20 игровых объектах разные важные глобальные данные? И второе. Если объектов таких несколько, в таком случае, может будет резонно сделать несколько классов-одиночек, причём тогда бы я разграничил всё по пространствам имён, чтобы класс N не имел сразу доступа ко всем одиночкам и классам внутри него, а брал только те данные, которые ему нужны..

Справка