⚡⚡⚡ Полезные ссылки ⚡⚡⚡ 🔎 yakovlevgamedev.tilda.ws - ссылка с информацией по курсу (запись откроется 25 июня в 12:00) 🔎 t.me/yakovlev_gamedev - ссылка на мой telegram канал (тут проходит розыгрыш) 🔎 boosty.to/yakovlevgamedev - ссылка на бусти (тут можно поддержать канал, выход новых видео и даже получить эксклюзивные ништяки)
Это он? Да пофиг, они все одинаковые по голосу Братан, хорош, давай, давай, вперёд! Контент в кайф, можно ещё? Вообще красавчик! Можно вот этого вот почаще?
8:10 за такой совет язык надо вырывать. Тут нарушается принцип открытости/закрытости «Классы, методы или функции должны быть открыты для расширения (добавления новой функциональности) и закрыты для модификации». Добавится новая расса и код придется менять
Вообще, первым советом наверное стоило обозначить "учите матчасть" :) ибо не понимать, что метод Instantiate() возвращает, означает, что остальные советы на далекое будущее пригодятся. Спасибо автору за полезное инфо 😍
По примеру про урон в совете про инкапсуляцию. А я наоборот этой особенностью пользуюсь. Понимаю, что можно делать и по другому, но если, допустим, Нежить лечится от урона ядом, то достаточно удобно просто менять знак :D Понятное дело, что это все неправильно, особенно для крупных проектов. Но если ты делаешь что нить мелкое, которое надо успеть за день два для, условно, геймДжема - то такие методы самое оно.
@@bigbluepie8983 сериализация в первую очередь нужна для сохранения состояния объекта, а не для отображения в инспекторе. Например, если инициализировать приватное поле в OnValidate, то в билде оно окажется пустым, потому что юнити по умолчанию не сериализует приватные поля
Хм, последний совет немного поставил в тупик) Предположим у нас есть некая трасса, на ней появляются объекты препятствия которые могут наносить урон, а также есть объекты что дают очки, или какой-то эффект. Постоянно спавнить объекты не вариант, проще уже составить какое-то определенное кол-во и включать\выключать на сцене. И неужели проще движку хранить у себя в скрипте где-то список таких-то объектов, которые делают больно, или наоборот и т.д. и проходится по всем объектам в списке, нежели чем просто при пересечении получить тэг, и сразу сослаться на нужное действие без всякого прохождения по спискам?
Ты случаем не на курсах от IJunior учился? Стиль кода и мышление похоже)
Год назад
У меня такая вот проблемка, которую я решил, скорее всего - говнокодом, но для первой игры не так ужэ сильно волнуюсь. Что ж, не смотря на это, если кто-то знает вариант получше то скажите с чего начать, пожалуйста. 4 сцены есть: Главное меню Выбор персонажа и пушки Основной геймплей Босс арена (да, мне нужна отдельная сцена под босс файт) Для удобства по номерам будет дальше, 1, 2, 3, 4. В 2 сцене игрок выбирает персонажа и пушку, на основе этого на 3 сцене отображается количество его ХП в виде ячеек, они спавнятся как GameObject и layout group'ом выстраиваются слева сверху. Так же начинает тикать таймер и снизу справа очки за убийство врага. Когда надо переместиться к боссу текущий игрок переносится на другую сцену загрузкой сцены, а на нём вот такой код висит: public static CRCubeStatManager playerInstance; if (playerInstance != null) { Destroy(this.gameObject); return; } playerInstance = this; GameObject.DontDestroyOnLoad(this.gameObject); Таким образом при возврате обратно не спавнится ещё один игрок и в меню главном он аналогично уничтожается, там отдельный объект следит что бы не было дубликатов. Таймер и счётчик очком аналогично переносятся, а в сцене 1 уничтожаются. Я пытался сделать такой менеджер что бы при смерти игрока вызывался метод OnSceneUnload, но только сам себя запутал и ничего не получалось. +- такую же логику использовал. Это то что сейчас работает, этот скрипт отвечает за перенос текущего игрока между сценами using UnityEngine; using UnityEngine.SceneManagement; public class FullCharacterHandler : MonoBehaviour { [SerializeField] private string playerTag = "Player"; [SerializeField] public GameObject fullCharacterHandler; private void Awake() { SceneManager.sceneLoaded += OnSceneLoaded; SceneManager.sceneUnloaded += OnSceneUnloaded; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (scene.name == "GamePlay" || scene.name == "BossArena") { fullCharacterHandler = GameObject.FindGameObjectWithTag(playerTag); FindObjectOfType().character = fullCharacterHandler; FindObjectOfType().character = fullCharacterHandler; FindObjectOfType().playerTransform = fullCharacterHandler.transform; if (fullCharacterHandler == null) { fullCharacterHandler = Instantiate(fullCharacterHandler); fullCharacterHandler.tag = playerTag; } } } private void OnSceneUnloaded(Scene scene) { if (scene.name == "GamePlay" || scene.name == "BossArena") { if (fullCharacterHandler != null) { Destroy(fullCharacterHandler); fullCharacterHandler = null; } } } [ContextMenu("LoadBossScene")] public void LoadBossScene() { SceneManager.LoadSceneAsync("BossArena"); } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; SceneManager.sceneUnloaded -= OnSceneUnloaded; } } Логика таймера и счёта такая же, только там свои приколы на босс сцене происходят. Самая главная сложность была в том что просто юзать DontDestroyOnLoad(gameObject); нельзя, ибо в главном меню будет дубликат всегда, как и в прочем при возврате со сцены 4 на 3 и из них в главное меню, если игрок сдаётся. Надеюсь я достаточно объяснил, но если Вы заинтересовались или сталкивались с подобной задачей то буду благодарен за любые предложенные решения. Сделаю копию проекта, протестирую. В принципе я и так в будущем хотел изменить эту логику, всё же следить за дубликатами, уничтожать их или ещё как-то бороться с последствиями подобных переносов может привести к тому что при расширении логики я столкнусь со сломанной игрой. Сроки поджимают, так что пока так. Спасибо за внимание
В целом то что ты делаешь это паттерн singleton. Самый новичковский паттерн, но в больших проектах его тоже полезно знать. Он кроме того что добивается уникальности (не дает создать второго персонажа игрока), еще и сильно помогает с доступностью. Просто по имени класса можно вызвать его инстанс откуда угодно. То есть у тебя там есть строка fullCharacterHandler = GameObject.FindGameObjectWithTag(playerTag); Это не то чтобы фундаментальное зло, но все Find функции работают медленно, так как перебирают все геймобджекты в сцене. Когда их станет много это станет проблемой в плане производительности. Ее можно заменить на fullCharacterHandler = CRCubeStatManager.playerInstance; Просто сразу берет ссылку на инстанс из статик параметра, без поиска по всем объектам. FindObjectOfType даже наверно большая проблема, тоже хорошо бы придумать как от них избавиться. Я б гдето в инспекторе один раз ссылки назначил на уровне префабов или сцены. Но сложно говорить что у тебя там. Ну и самый большой подводный камень такого синглтона, он не создает новый экземпляр класса, он продолжает удерживать в памяти тот же старый при любых действиях до закрытия программы. То есть например твой персонаж игрока получил урон, изменились его hp. Ты вышел в главное меню, зашел в новую игру. Эти данные никуда не денутся, он будет с неполным hp. Что делать: проводить инициализацию когда надо. Присваивать полные hp в данном примере, но вообще надо перебрать всё что могло поменяться. Таких параметров бывает очень много, поэтому синглтон не всегда удобно использовать, часто проще убить старый объект, а новый получить при загрузке сцены.
Год назад
@@iamaim2847 fullCharacterHandler = CRCubeStatManager.playerInstance; Почему я не использую этот вариант - я не знаю какой скрипт будет на игроке, то есть у меня, допустим CR (Character) Name StatManager По поводу удержания статов до выхода из игры - я столкнулся с эой проблемой ещё когда SO начал юзать и задаю дефолтные значения. Можно было бы SO юзать только в качестве конфига, как все и рекомендуют, но тогда я об этом не знал и просто вызывал метод дефолта перед началом. То есть да, когда мой перс получит +200 урона, пока конкретно он не будет выбран в следующий забег - его урон будет так же +200, но увы, переделывать 4 месяца работы я сейчас не очень хочу, да и узнал про Zenject, DI, совсем по иному следующую игру буду строить. По поводу производительности - сильных проблем нет, все тяжёлые методы выполняются либо перед началом игры, либо тогда когда активен UI и спешить некуда. Да, я насрал, но не вонючим говном. Можно всё исправить и сделать лучше, но тут уже вопрос времени и денег, которых всегда не хватает, а задач сверху ещё больше. Спасибо за уделённое время
Год назад
Можно сделать заготовки и к ним ссылаться, но не вижу смысла сейчас, ибо персонажей на выбор (так же как и пушек, абилок и хрен знает что ещё захочу добавить) будет много, а так я могу один раз создать объект, который хранит ссылки на доступ к ТЕКУЩИМ объектам, все кто надо присвоят себе в поля всё что надо из этого объекта и будут работать с текущими пушкой, персонажем, обилкой и т.д Так как у меня рогалик и я хочу максимально большое количество стат изменять - лучше для себя в плане реализации на час времени не нашёл. Всё упирается в знания и желание улучшать скиллы, это будет, но только с временем и сроками
Ты как-то странно понимаешь инкапсуляцию. Это не "не только сокрытие через private", это вообще не сокрытие)) Если бы это было такое сокрытие, то его бы и называли скорытие Если просто, то это объединение данных и методов для работы с этими данными. Хотя ладно, немного вру) Слово "сокрытие" сюда можно прикрутить. Т.к. можно сказать, что инкапсуляция, это сокрытие РЕАЛИЗАЦИИ. Например у тебя есть какой-то супер метод где сразу куча действий производится. Мытье кружки, кипячение воды, заварка кофе, поиск чистой ложки, перенос кружки к компьютеру и т.д. Так вот ты можешь вынести логику заварки кофе в какой-нибудь CoffeeFactory или CoffeeMachine. И получится что у тебя реализация будет обернута(инкапсулирована) в сущность кофемашины и наружу у тебя будут только контракт(публичные методы, интерфейс кста для этого и нужен). Т.е. ты не будешь знать реализации и сущность для тебя будет как черный ящик
Подскажите, а Enemy наследуется от gameObject? - Не очень понятно. Instantiate - клонирует префаб, у меня он выдаёт ошибку если подать не gameObject, а класс-компонент, который на нём висит.
@@-it394 благодарю за ответ. У меня так и есть. Но он выдаёт ошибку если инстанциировать не gameobject. (Правда, я его инстанциирую на карте, а здесь нет других аргументов).
Instantiate конкретно для GameObject. Но и там можно сразу записать компонент в переменную, если сделать: MyComponent myComponent = Instantiate(prefabLink).GetComponent(); Создать компоненты на геймобджектах можно через gameObject.AddComponent(typeof(MyType)); В том числе и компоненты сделанные из своих скриптов. Самописные классы, не унследованные от монобеха, точнее их экземпляры, можно делать через new, как и всем известные Vector3.
@@iamaim2847 благодарю. С этим знаком. Я удивился как Enemy в ролике инстанциировался. Попробовал провернуть подобный трюк, и Unity пожаловался на cast, что логично, потому что при инстанцировании на сцену он ожидает префаб.
А как относитесь к синглтонам? Заметил, что часто стал их использовать, если объект в сцене точно один, то не пропихиваю его везде, а тупо завожу статик поле у класса и все кому надо - обращаются к нему. Это плохая практика?
Зависит от того как, где и для чего используются. Обычно, если через DI то норм, если просто то не очень. Синглтоны тяжело тестировать т.к. их тяжело подменять. Так же желательно чтобы они не хранили никакого состояния. Кароч главное осмысленно и без фанатизма
Вот только есть одна особенность). К юнити это не имеет никакого отношения. Это чисто языковые фичи и особенности. В юнити я полный профан, но с c# дружу давно и подтверждаю что каждый из этих советов будет полезен и далеко за пределами движка.
По поводу первого совета, рекомендую не надеяться на гет компонент с RequireComponent, это бывает опасно и не всегда практично - банально бывает, что компонент находится в иерархии как дочерний, а RequireComponent добавляет новый и ты далеко не сразу сможешь понять, что же пошло не так =))
Компоненты не бывают дочерними. Если ты про компонент в дочернем gameobject, то тут ошибка только на твоей стороне, нужно правильно проектировать иерархию.
@@DarkIllusoire осмыслить то, что в твоем случае вешается RequireComponent на обьект, который не должен содержать этого компонента, а его должен содержать дочерний обьект? В твоём случае атрибут делает всё правильно: вешает недостающий компонент, а то что компонент должен быть вообще на другом обьекте - это твоя ошибка.
@@_cyp4ik_201 да, основной консерн в том, что эта штука гарантирует компонент, но не гарантирует правильный, тем самым может вводить в заблуждение и приводить к ошибкам. Лучше использовать сериализованные поля, а трюк с получением компонента или require component, применять в случае, когда нужно изменить много объектов, которые уже существуют на сцене. И это не мой случай,а опыт за два года работы тимлидом, причем увидеть ошибку джуна в таком случае очень сложно, особенно в пулреквесте
⚡⚡⚡ Полезные ссылки ⚡⚡⚡
🔎 yakovlevgamedev.tilda.ws - ссылка с информацией по курсу (запись откроется 25 июня в 12:00)
🔎 t.me/yakovlev_gamedev - ссылка на мой telegram канал (тут проходит розыгрыш)
🔎 boosty.to/yakovlevgamedev - ссылка на бусти (тут можно поддержать канал, выход новых видео и даже получить эксклюзивные ништяки)
Закрепи свой коммент)
@@veiterio че то я провтыкал))
Братан, хорош, давай, давай, вперёд! Контент в кайф, можно ещё? Вообще красавчик! Можно вот этого вот почаще?
Это он?
Да пофиг, они все одинаковые по голосу
Братан, хорош, давай, давай, вперёд! Контент в кайф, можно ещё? Вообще красавчик! Можно вот этого вот почаще?
Начал смотреть видео и заранее поставил лайк, досмотрел видео и снова потянулся поставить лайк :)
Супер. Взял на вооружение
Какой молодой канал, и какой полезный. Круто
8:10 за такой совет язык надо вырывать. Тут нарушается принцип открытости/закрытости «Классы, методы или функции должны быть открыты для расширения (добавления новой функциональности) и закрыты для модификации». Добавится новая расса и код придется менять
Про закрепление в 1 совете это полезно, спасибо за материал
Даёшь бубнеж!!!! Аля-улю!!
Коммент для поддержки) ❤❤❤
Вообще, первым советом наверное стоило обозначить "учите матчасть" :) ибо не понимать, что метод Instantiate() возвращает, означает, что остальные советы на далекое будущее пригодятся. Спасибо автору за полезное инфо 😍
Золотая инфа, могу только пожелать удачи и кинуть +rep)
атрибуты Min и Max, тоже существуют и они полезные
просто спасибо, жду дальше Зенджект)
Жду видео про Zenject)
Давай про оптимизацию игру на телефон и тд
По примеру про урон в совете про инкапсуляцию.
А я наоборот этой особенностью пользуюсь. Понимаю, что можно делать и по другому, но если, допустим, Нежить лечится от урона ядом, то достаточно удобно просто менять знак :D
Понятное дело, что это все неправильно, особенно для крупных проектов. Но если ты делаешь что нить мелкое, которое надо успеть за день два для, условно, геймДжема - то такие методы самое оно.
Большое спасибо, по поводу ButtonExtension, я это называл интерфейсом с более высокой абстракций, когда писал на Lua, ну или просто wrap-функций.
Сделай мтни курс на ютуб, нде какую-нибудь прлстенькую игру доводишь от начала и до конца
Хотелось бы послушать что-то по архитектуры, вечно когда начинаю новый проект - не знаю с чего лучше начать работать, Entry Point, Сервисы и т.п.
С проекта начните. На самом деле все эти рюшки код не упрощают, а усложняют.. ООП на юнити - такое себе развлечение, для очень утонченных эстетов.
Hideininspector не бесполезный. Иногда бывает ситуация, когда поле нужно сериализовать, но при этом в инспекторе его видеть не хочется
Согласен
А зачем его сериализовать, если он не нужен в инспекторе?
@@bigbluepie8983 сериализация в первую очередь нужна для сохранения состояния объекта, а не для отображения в инспекторе. Например, если инициализировать приватное поле в OnValidate, то в билде оно окажется пустым, потому что юнити по умолчанию не сериализует приватные поля
для этого нужно использовать публичные свойства
@@NezertorcheaT гений 👍
Давай ещё вот такого побольше, контент в кайф!
Требуют ли ныне от джуна Zenject, ECS, JobSystem?
Обычно нет, но есть места где да)))
Не везде, может только зенджект, многие понимают что это мидл и + уровень уже
Спасибо за видос. Одно замечание: character звучит как "керектер" а не как "чаректер". Не останавливайся!
привет)
спасибо за видосы!
сильно интересует тема тестирования в юнити. если есть что рассказать - буду крайне благодарен)
Бро, сделай видео про подключение и настройку рекламы с Iron Source!
Открываешь документацию Iron Source и вперёд, лол
@@veiterio Красавчик 👍
Хм, последний совет немного поставил в тупик)
Предположим у нас есть некая трасса, на ней появляются объекты препятствия которые могут наносить урон, а также есть объекты что дают очки, или какой-то эффект. Постоянно спавнить объекты не вариант, проще уже составить какое-то определенное кол-во и включать\выключать на сцене. И неужели проще движку хранить у себя в скрипте где-то список таких-то объектов, которые делают больно, или наоборот и т.д. и проходится по всем объектам в списке, нежели чем просто при пересечении получить тэг, и сразу сослаться на нужное действие без всякого прохождения по спискам?
А есть еще что то похожее на плагин Naughty Attributes
?
Ты случаем не на курсах от IJunior учился? Стиль кода и мышление похоже)
У меня такая вот проблемка, которую я решил, скорее всего - говнокодом, но для первой игры не так ужэ сильно волнуюсь. Что ж, не смотря на это, если кто-то знает вариант получше то скажите с чего начать, пожалуйста.
4 сцены есть:
Главное меню
Выбор персонажа и пушки
Основной геймплей
Босс арена (да, мне нужна отдельная сцена под босс файт)
Для удобства по номерам будет дальше, 1, 2, 3, 4.
В 2 сцене игрок выбирает персонажа и пушку, на основе этого на 3 сцене отображается количество его ХП в виде ячеек, они спавнятся как GameObject и layout group'ом выстраиваются слева сверху.
Так же начинает тикать таймер и снизу справа очки за убийство врага.
Когда надо переместиться к боссу текущий игрок переносится на другую сцену загрузкой сцены, а на нём вот такой код висит:
public static CRCubeStatManager playerInstance;
if (playerInstance != null)
{
Destroy(this.gameObject);
return;
}
playerInstance = this;
GameObject.DontDestroyOnLoad(this.gameObject);
Таким образом при возврате обратно не спавнится ещё один игрок и в меню главном он аналогично уничтожается, там отдельный объект следит что бы не было дубликатов.
Таймер и счётчик очком аналогично переносятся, а в сцене 1 уничтожаются.
Я пытался сделать такой менеджер что бы при смерти игрока вызывался метод OnSceneUnload, но только сам себя запутал и ничего не получалось.
+- такую же логику использовал. Это то что сейчас работает, этот скрипт отвечает за перенос текущего игрока между сценами
using UnityEngine;
using UnityEngine.SceneManagement;
public class FullCharacterHandler : MonoBehaviour
{
[SerializeField] private string playerTag = "Player";
[SerializeField] public GameObject fullCharacterHandler;
private void Awake()
{
SceneManager.sceneLoaded += OnSceneLoaded;
SceneManager.sceneUnloaded += OnSceneUnloaded;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if (scene.name == "GamePlay" || scene.name == "BossArena")
{
fullCharacterHandler = GameObject.FindGameObjectWithTag(playerTag);
FindObjectOfType().character = fullCharacterHandler;
FindObjectOfType().character = fullCharacterHandler;
FindObjectOfType().playerTransform = fullCharacterHandler.transform;
if (fullCharacterHandler == null)
{
fullCharacterHandler = Instantiate(fullCharacterHandler);
fullCharacterHandler.tag = playerTag;
}
}
}
private void OnSceneUnloaded(Scene scene)
{
if (scene.name == "GamePlay" || scene.name == "BossArena")
{
if (fullCharacterHandler != null)
{
Destroy(fullCharacterHandler);
fullCharacterHandler = null;
}
}
}
[ContextMenu("LoadBossScene")]
public void LoadBossScene()
{
SceneManager.LoadSceneAsync("BossArena");
}
private void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.sceneUnloaded -= OnSceneUnloaded;
}
}
Логика таймера и счёта такая же, только там свои приколы на босс сцене происходят.
Самая главная сложность была в том что просто юзать DontDestroyOnLoad(gameObject); нельзя, ибо в главном меню будет дубликат всегда, как и в прочем при возврате со сцены 4 на 3 и из них в главное меню, если игрок сдаётся.
Надеюсь я достаточно объяснил, но если Вы заинтересовались или сталкивались с подобной задачей то буду благодарен за любые предложенные решения. Сделаю копию проекта, протестирую. В принципе я и так в будущем хотел изменить эту логику, всё же следить за дубликатами, уничтожать их или ещё как-то бороться с последствиями подобных переносов может привести к тому что при расширении логики я столкнусь со сломанной игрой.
Сроки поджимают, так что пока так. Спасибо за внимание
В целом то что ты делаешь это паттерн singleton. Самый новичковский паттерн, но в больших проектах его тоже полезно знать.
Он кроме того что добивается уникальности (не дает создать второго персонажа игрока), еще и сильно помогает с доступностью. Просто по имени класса можно вызвать его инстанс откуда угодно.
То есть у тебя там есть строка
fullCharacterHandler = GameObject.FindGameObjectWithTag(playerTag);
Это не то чтобы фундаментальное зло, но все Find функции работают медленно, так как перебирают все геймобджекты в сцене. Когда их станет много это станет проблемой в плане производительности. Ее можно заменить на
fullCharacterHandler = CRCubeStatManager.playerInstance;
Просто сразу берет ссылку на инстанс из статик параметра, без поиска по всем объектам.
FindObjectOfType даже наверно большая проблема, тоже хорошо бы придумать как от них избавиться. Я б гдето в инспекторе один раз ссылки назначил на уровне префабов или сцены. Но сложно говорить что у тебя там.
Ну и самый большой подводный камень такого синглтона, он не создает новый экземпляр класса, он продолжает удерживать в памяти тот же старый при любых действиях до закрытия программы. То есть например твой персонаж игрока получил урон, изменились его hp. Ты вышел в главное меню, зашел в новую игру. Эти данные никуда не денутся, он будет с неполным hp. Что делать: проводить инициализацию когда надо. Присваивать полные hp в данном примере, но вообще надо перебрать всё что могло поменяться. Таких параметров бывает очень много, поэтому синглтон не всегда удобно использовать, часто проще убить старый объект, а новый получить при загрузке сцены.
@@iamaim2847 fullCharacterHandler = CRCubeStatManager.playerInstance;
Почему я не использую этот вариант - я не знаю какой скрипт будет на игроке, то есть у меня, допустим CR (Character) Name StatManager
По поводу удержания статов до выхода из игры - я столкнулся с эой проблемой ещё когда SO начал юзать и задаю дефолтные значения.
Можно было бы SO юзать только в качестве конфига, как все и рекомендуют, но тогда я об этом не знал и просто вызывал метод дефолта перед началом.
То есть да, когда мой перс получит +200 урона, пока конкретно он не будет выбран в следующий забег - его урон будет так же +200, но увы, переделывать 4 месяца работы я сейчас не очень хочу, да и узнал про Zenject, DI, совсем по иному следующую игру буду строить.
По поводу производительности - сильных проблем нет, все тяжёлые методы выполняются либо перед началом игры, либо тогда когда активен UI и спешить некуда. Да, я насрал, но не вонючим говном. Можно всё исправить и сделать лучше, но тут уже вопрос времени и денег, которых всегда не хватает, а задач сверху ещё больше.
Спасибо за уделённое время
Можно сделать заготовки и к ним ссылаться, но не вижу смысла сейчас, ибо персонажей на выбор (так же как и пушек, абилок и хрен знает что ещё захочу добавить) будет много, а так я могу один раз создать объект, который хранит ссылки на доступ к ТЕКУЩИМ объектам, все кто надо присвоят себе в поля всё что надо из этого объекта и будут работать с текущими пушкой, персонажем, обилкой и т.д
Так как у меня рогалик и я хочу максимально большое количество стат изменять - лучше для себя в плане реализации на час времени не нашёл. Всё упирается в знания и желание улучшать скиллы, это будет, но только с временем и сроками
Ты как-то странно понимаешь инкапсуляцию. Это не "не только сокрытие через private", это вообще не сокрытие))
Если бы это было такое сокрытие, то его бы и называли скорытие
Если просто, то это объединение данных и методов для работы с этими данными.
Хотя ладно, немного вру) Слово "сокрытие" сюда можно прикрутить. Т.к. можно сказать, что инкапсуляция, это сокрытие РЕАЛИЗАЦИИ.
Например у тебя есть какой-то супер метод где сразу куча действий производится. Мытье кружки, кипячение воды, заварка кофе, поиск чистой ложки, перенос кружки к компьютеру и т.д. Так вот ты можешь вынести логику заварки кофе в какой-нибудь CoffeeFactory или CoffeeMachine. И получится что у тебя реализация будет обернута(инкапсулирована) в сущность кофемашины и наружу у тебя будут только контракт(публичные методы, интерфейс кста для этого и нужен). Т.е. ты не будешь знать реализации и сущность для тебя будет как черный ящик
Подскажите, а Enemy наследуется от gameObject? - Не очень понятно. Instantiate - клонирует префаб, у меня он выдаёт ошибку если подать не gameObject, а класс-компонент, который на нём висит.
От монобеха наследовать надо
@@-it394 благодарю за ответ. У меня так и есть. Но он выдаёт ошибку если инстанциировать не gameobject. (Правда, я его инстанциирую на карте, а здесь нет других аргументов).
Instantiate конкретно для GameObject. Но и там можно сразу записать компонент в переменную, если сделать:
MyComponent myComponent = Instantiate(prefabLink).GetComponent();
Создать компоненты на геймобджектах можно через gameObject.AddComponent(typeof(MyType)); В том числе и компоненты сделанные из своих скриптов.
Самописные классы, не унследованные от монобеха, точнее их экземпляры, можно делать через new, как и всем известные Vector3.
@@iamaim2847 благодарю. С этим знаком. Я удивился как Enemy в ролике инстанциировался. Попробовал провернуть подобный трюк, и Unity пожаловался на cast, что логично, потому что при инстанцировании на сцену он ожидает префаб.
Я бы про настройки hdrp послушал от автора
А как относитесь к синглтонам? Заметил, что часто стал их использовать, если объект в сцене точно один, то не пропихиваю его везде, а тупо завожу статик поле у класса и все кому надо - обращаются к нему. Это плохая практика?
Зависит от того как, где и для чего используются.
Обычно, если через DI то норм, если просто то не очень. Синглтоны тяжело тестировать т.к. их тяжело подменять. Так же желательно чтобы они не хранили никакого состояния.
Кароч главное осмысленно и без фанатизма
Ссылка на бусти не активна из-за "gamedev-" дефис лезет в ссылку)
Спасибо!
Вот только есть одна особенность). К юнити это не имеет никакого отношения. Это чисто языковые фичи и особенности.
В юнити я полный профан, но с c# дружу давно и подтверждаю что каждый из этих советов будет полезен и далеко за пределами движка.
Просто и чётко 👍
Хороший контент
По поводу первого совета, рекомендую не надеяться на гет компонент с RequireComponent, это бывает опасно и не всегда практично - банально бывает, что компонент находится в иерархии как дочерний, а RequireComponent добавляет новый и ты далеко не сразу сможешь понять, что же пошло не так =))
Компоненты не бывают дочерними. Если ты про компонент в дочернем gameobject, то тут ошибка только на твоей стороне, нужно правильно проектировать иерархию.
@@_cyp4ik_201 перечитай внимательно написанное и попробуй осмыслить, и не писать абы что
@@DarkIllusoire осмыслить то, что в твоем случае вешается RequireComponent на обьект, который не должен содержать этого компонента, а его должен содержать дочерний обьект? В твоём случае атрибут делает всё правильно: вешает недостающий компонент, а то что компонент должен быть вообще на другом обьекте - это твоя ошибка.
@@_cyp4ik_201 да, основной консерн в том, что эта штука гарантирует компонент, но не гарантирует правильный, тем самым может вводить в заблуждение и приводить к ошибкам. Лучше использовать сериализованные поля, а трюк с получением компонента или require component, применять в случае, когда нужно изменить много объектов, которые уже существуют на сцене. И это не мой случай,а опыт за два года работы тимлидом, причем увидеть ошибку джуна в таком случае очень сложно, особенно в пулреквесте
+
Жалко этих добряков кто заплатит за курс персонажу, который считает, что инкапсуляция это сокрытие, а так же советует использовать статик классы ))
какое бесячее интро
Братан, хорош, давай, давай, вперёд! Контент в кайф, можно ещё? Вообще красавчик! Можно вот этого вот почаще?