TheDarkestRed TheDarkestRed

Новое окружение ⛰ 🌲 🌳 🎮

Rummy_Games Rummy_Games

Доброго субботнего вечера! Сегодня мы ходим поделиться наработками нашего 3D-моделлера в рамках #saturdayscreenshot. А также кратко делимся ЛОРом игры.

...
TheDarkestRed TheDarkestRed

Карта мира The Darkest Red 🎮 🐺 🤺 🌍 🗺 ⛰

TheDarkestRed TheDarkestRed

Обновили поведение камеры и механики боя 🎮 🤺 🧟 🎥

Rummy_Games Rummy_Games

Доброго субботнего вечера! Сегодня мы поделимся с вами видео процесса разработки одного из противников (“Роя”) в нашей игре, в рамках #saturdayscreenshot, а также кратко делимся ЛОРом игры.

...
mushroom_queen mushroom_queen

Jusper, спасибо за комментарий! старалась писать нескучно))

Jusper Jusper

Моя любимая фаза разработки любой игры!
Отлично написано, посмеялся местами от души. Спасибо!

Jusper Jusper

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

Не вижу пока, как в такое управление впихнуть боевку.

Jusper Jusper

PallSwarrow
Что ж я поиграл. Пока это не игра про пиратов, а игра про навигацию парусами. Это скорее пока в плюс, потому что управление мне понравилось, но боюсь, что весь игровой фокус сейчас только в этом...

...
id44474404 id44474404

В Княжествах Онлайн снова появились анимации, они синхронизируются с сервером и работают реалистично, т.е. нанесение урона или получение ресурсов происходит в тот момент, когда это соответствует анимации...

...
TheDarkestRed TheDarkestRed

Экспериментируем с рэгдолами 🎮🧟🤺🐺

lehha95 lehha95

Открыли страницу в Steam! Добавляйте в список желаемого!

https://store.steampowered.com/app/1355780/

romandviski romandviski

Спасибо, добрый человек.

Rummy_Games Rummy_Games

Доброго субботнего вечера! Сегодня мы поделимся с вами видео процесса разработки одного из противников (“Роя”) в нашей игре, в рамках #saturdayscreenshot, а также кратко делимся ЛОРом игры.

...
id44474404 id44474404

Всем привет!
Функционал авторитарного сервера продолжает восстанавливаться до уровня, который был на фотон клауде. На этой неделе стало возможным убийство мобов, и получение с них опыта, и прокачка персонажа...

...
Jusper Jusper

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

Kazirath Kazirath

Насколько я понял проще установть последнюю версию перед 2.3 и продолжить работать под ней. Новинка не стоит свеч после переделки скриптов

Kazirath Kazirath

Это совсем не радостная новость. Меня вполне устраивал функционал старой работы скриптов и я даже выработал некоторую систему, которая позволяла через скрипты настраивать работу объектов и прочего. Принудительная же переделка в функции у меня не сработает из за структур некоторых скриптов...

...
alexprey alexprey

Учитывая то, что написано в данной статье обратно включить это не получится и придется действительно обернуть код скриптов в функции.

Кратко из документации:

  • Раньше скрипты были индивидуальными и изолированными
  • ...
  • ...
  • ...
  • ...
...
PallSwarrow PallSwarrow

Спасибо за комменты, оч приятно)
Про ссылку тупанул - пока разбираюсь с сайтом)

Логотип проекта 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 не имел сразу доступа ко всем одиночкам и классам внутри него, а брал только те данные, которые ему нужны..

Справка