AlexanderDllSky

Пикабушник
Дата рождения: 07 марта 1989
поставил 5178 плюсов и 12893 минуса
отредактировал 0 постов
проголосовал за 0 редактирований
Награды:
5 лет на Пикабу
9229 рейтинг 241 подписчик 75 подписок 64 поста 11 в горячем

К чему приводят комментарии на пикабу

Всем привет!
Делюсь небольшой историей и её результатом.
Энное время назад на пикабу под постом о детских рисунках я оставил комментарий про рисунок моей четырехлетней дочери (который в обозримом будущем хочу превратить в татуировку)

К чему приводят комментарии на пикабу Лига Добра, Пикабушники, Творчество, Рукоделие без процесса, Длиннопост, Позитив, Благодарность, Истории из жизни, Мобильная фотография

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

Ну что могу сказать, шалость удалась. Вышло всё очень классно. Дочка довольна.
Спасибо тебе, добрый человек, за такие эмоции!

К чему приводят комментарии на пикабу Лига Добра, Пикабушники, Творчество, Рукоделие без процесса, Длиннопост, Позитив, Благодарность, Истории из жизни, Мобильная фотография
К чему приводят комментарии на пикабу Лига Добра, Пикабушники, Творчество, Рукоделие без процесса, Длиннопост, Позитив, Благодарность, Истории из жизни, Мобильная фотография
К чему приводят комментарии на пикабу Лига Добра, Пикабушники, Творчество, Рукоделие без процесса, Длиннопост, Позитив, Благодарность, Истории из жизни, Мобильная фотография
Показать полностью 4

Не сохраняет картинки

Блин, разработчики, приложение до сих пор на новых ОС Андроид не умеет ни сохранять картинки, ни вставлять в посты (точнее - не предусмотрено разрешение).
Доколе?

Не сохраняет картинки Приложение на Android, Приложение Пикабу, Баг на Пикабу, Длиннопост
Не сохраняет картинки Приложение на Android, Приложение Пикабу, Баг на Пикабу, Длиннопост
Показать полностью 2

Когда клеите с ребёнком поделки, не используйте токсичные материалы

...иначе эти поделки будут оживать =D

Ностальгии пост

Пост посвящается олдфагам. Добро пожаловать в детство девяностых и нулевых!
Навестил родителей. Нашёл свои старые игрушки, конструкторы, диски и зарисовки...
Вспомнилось детство. Ностальгия =)

Ностальгии пост Ностальгия, Детство 90-х, Воспоминания из детства, Длиннопост
Ностальгии пост Ностальгия, Детство 90-х, Воспоминания из детства, Длиннопост
Ностальгии пост Ностальгия, Детство 90-х, Воспоминания из детства, Длиннопост
Ностальгии пост Ностальгия, Детство 90-х, Воспоминания из детства, Длиннопост
Показать полностью 4

Моим подписчикам. Не теряйте. Работаю над продолжением обучающих постов

Всем привет! Уже неделю от меня тишина, нет обучаюших постов.
Не теряйте, я не пропал и не "сдулся".
У меня отпуск. Я отдыхаю и немного работаю над пет-проектом по которому породолжу пилить обучение.
Это будет скорее всего скроллер с енотом. Игроку предстоит в роли "Енота-борца за чистоту" уничтожать мусор. Простенько.
Посты планирую продолжить, когда будет готов проект или хотя бы половина.
До скорого! И успеха всем в программировании и геймдеве!

Моим подписчикам. Не теряйте. Работаю над продолжением обучающих постов Обучение, Подписчики, Gamedev

Как делать игры в Unity. Попытка в серию обучающих постов #3

Пост №3. Несколько способов связи разных компонентов

Дисклеймер:

Во-первых, эти посты я пишу для тех, кто хоть немного знаком с C#. Во-вторых, это далеко не все способы связи частей программы/игры. В-третьих, не стоит забывать, что приведенные ниже код написан в просветительских целях, ориентирован на низкий порог вхождения, поэтому "делать еще более правильнее и профессиональнее, используя больше абстракций, а не конкретные классы" я не стану. И еще - можно бесконечно долго спорить о паттернах и анти-паттернах =)

Всем привет!
Сегодня расскажу и покажу три способа связи разных компонентов.

Как делать игры в Unity. Попытка в серию обучающих постов #3 Unity, Csharp, Gamedev, Обучение, Длиннопост

Сферическая задача в вакууме будет такой:

Есть некий объект-счетчик и есть интерфейс с текстовым полем и кнопкой. Счетчик существует сам по себе, интерфейс - сам по себе. Объект не должен знать о существовании каких-либо частей UI и уж тем более не должен от них зависеть - это поможет в дальнейшем избежать массу проблем (самая очевидная - сложности в модификации при подобных не совсем уместных зависимостях). Но этот объект может (и должен) обладать неким инструментом, что бы можно было реагировать на его изменения в процессе игры.

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


Проект урока можно посмотреть в гите .

1. Паттерн Singleton

Данный паттерн (хотя в ряде случаев из-за недостатоков считается анти-паттерном) в "полной реализации" гарантирует наличие единственного экземпляра класса и предоставляет единую точку доступа к этому экземпляру.

В обучающем примере будет упрощенная реализация с наследованием от MonoBehaviour. Это нужно для того, что бы в примере просто разместить этот компонент в каком-нибудь объекте (для наглядности лучше в отдельный GameObject на "видном месте") на сцене и после запуска игры иметь простой доступ к этому компоненту. Директива #region использована исключительно для наглядности разделения блоков, т.к. в следующем пункте будем  дорабатывать этот класс.

Из-за такой условности, что упрощенная реализацию плюс  наследование от MonoBehaviour, у моего примера есть существенный недостаток - инициализация происходит в методе Awake. Следовательно, если на сцене изначально (при запуске игры) будут находиться объекты, которым потребуется доступ к этому классу, то делать это придется после Awake() - т.е. не раньше чем в Enable() или Start().

Как делать игры в Unity. Попытка в серию обучающих постов #3 Unity, Csharp, Gamedev, Обучение, Длиннопост

2. Паттерн ServiceLocator

Этот паттерн позволяет в едином месте хранить ссылки на "сервисы". И как правило - каждый "сервис" - это отдельный класс. В реалиях игры этими "сервисами" могут быть контроллер интерфейса (который, допустим, создает все окна и элементы UI), контроллер игрового режима (который, н-р, знает все правила текущей игры), какой-нибудь контроллер ботов (содержащий список всех ботов на сцене) и т.д.

На основе предыдущего пункта создадим такой Локатор. В моем примере он (локатор) наследуется от MonoBehaviour для наглядного размещения на сцене. Однако это вовсе не обязательно. Класс-локатор может быть статичным, а может быть и Singleton (но без наследования MonoBehaviour и без размещения на сцене его пришлось бы создавать в каком-нибудь месте игры, н-р, при инициализации).

Как делать игры в Unity. Попытка в серию обучающих постов #3 Unity, Csharp, Gamedev, Обучение, Длиннопост

"Локатор" готов. Но сам по себе он бесполезен. Теперь создадим основную сущность этого урока - Счетчик. Он должен будет регистрироваться в существующем локаторе и давать возможность корректно изменять свое состояние (помните про совет с минимумом общедоступных членов класса?) и выдавать по запросу свое актуальное состояние (значение счетчика).

Как делать игры в Unity. Попытка в серию обучающих постов #3 Unity, Csharp, Gamedev, Обучение, Длиннопост

Но как же Счетчик будет сообщать об изменении своего состояния? Чтобы другие объекты в игре могли отслеживать изменения Счетчика без необходимости его регулярной проверки, будем использовать...

3. События

События сообщают объектам-подписчикам о каком-то изменении. В данном примере Счетчик должен будет сообщать, что изменилось его значение. И что бы избежать лишней последовательности "Сработало событие -> Запрашиваем актуальное состояние -> Выводим результат" при вызове события сразу будет передаваться актуальное состояние счетчика.

События объявляются ключевым словом event с указанием типа делегата, которым будет представлено событие. Для примера подойдет "встроенный" в C# делегат Action<int> - он принимает параметр типа int - с его помощью будем передавать значение счетчика.

В написанный выше класс Счетчика внесем несколько изменений.

Подключим пространство имен и объявим событие

Как делать игры в Unity. Попытка в серию обучающих постов #3 Unity, Csharp, Gamedev, Обучение, Длиннопост
Как делать игры в Unity. Попытка в серию обучающих постов #3 Unity, Csharp, Gamedev, Обучение, Длиннопост

И в методе изменения счетчика добавим вызов события

Как делать игры в Unity. Попытка в серию обучающих постов #3 Unity, Csharp, Gamedev, Обучение, Длиннопост

Теперь быстренько создадим класс для работы кнопки и класс для текстового поля для "отлова" события изменения счетчика.

Кнопка должна будет через Локатор получить Счетчик и вызвать метод изменения счетчика.

Как делать игры в Unity. Попытка в серию обучающих постов #3 Unity, Csharp, Gamedev, Обучение, Длиннопост

Компонент для текста должен будет при старте игры отобразить состояние счетчика, а в последствии обновлять информацию только по необходимости (т.е. при срабатывании события OnChange). Для этого создаваемый компонент должен будет подписаться на это событие.

[ВАЖНО] если вы подписываетесь на какое-то событие, не забывайте от него отписываться. Иначе это может привести не только к неожиданному поведению Вашей игры, но и критическим ошибкам.

Как делать игры в Unity. Попытка в серию обучающих постов #3 Unity, Csharp, Gamedev, Обучение, Длиннопост

Из текста я опущу то, что эти компоненты нужно разместить на сцене, в случае кнопки - еще необходимо задать обработчик нажатия в компоненте Button в инспекторе, а в случае компонента для текста - через инспектор задать значение текстового поля.


В результате получается следующее:

Запускается игра, сингтон-локатор инициализируется. Затем Счетчик регистрируется в локаторе. Следом (по порядку вызова Unity-методов MonoBehaviour) текстовое поле подписывается на событие изменения счетчика и первый раз выводит текущее состояние этого счетчика. А при нажатие на кнопку происходит увеличение счетчика. В результате чего вызывается событие изменения, на которое реагирует текстовый компонент.


На этом пост подходит к концу.

Еще раз напомню, что код и сцену можно посмотреть в репозитории.

Надеюсь, кому-нибудь пост окажется полезным. И буду рад, если встретив для себя какой-то незнакомый термин Вы почитаете об этом подробнее.

Успехов в геймдеве!

Показать полностью 9

Как делать игры в Unity. Попытка в серию обучающих постов #2

Пост №2. Азы программирования. Некоторые правила написания кода.


Всем привет! Продолжу серию обучающих постов.

Этот пост будет посвящен плохим и хорошим привычкам написания кода (в ключе "новичок"). Существует много книг и практик по написанию "понятного/чистого" кода, который легко поддерживать (н-р, советую "классику" - "Чистый код" Р.Мартин), знать и использовать их все не обязательно, особенно новичкам.

Но я считаю, что даже на начальных порах следует придерживаться некоторых правил написания кода, что бы приучать себя "качественно делать свою работу". К тому же при работе в команде необходимо писать в более-менее едином стиле, поэтому приучая себя придерживаться хотя бы минимума правил в начале своего пути в дальнейшем будет проще адаптироваться к правилам кодстайла команды/компании.


Дисклеймер:

Некоторые вещи могут показаться слишком очевидными, но их следует упомянуть в любом случае. А так же следует помнить, что написанное ниже имеет отношение к C# и Unity, а в разных языках программирования могут быть разные принятые стандарты (например, в C# методы должны называться с заглавной буквы, а в Java - с маленькой)

1. Имена классов

Называйте классы с заглавной буквы и используйте CamalCase. Никто не запрещает называть классы с маленькой буквы и/или использовать в названии "подчеркивание" _ , однако это является дурным тоном.

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

Как делать игры в Unity. Попытка в серию  обучающих постов #2 Unity, Csharp, Gamedev, Обучение, Длиннопост

2. Имена свойств и полей классов и переменных в методах

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

Как делать игры в Unity. Попытка в серию  обучающих постов #2 Unity, Csharp, Gamedev, Обучение, Длиннопост

Имена свойств/полей/переменных также должны выдаваться осмысленно. Переменные всегда называются с маленькой буквы. С полями и свойствами не так все однозначно - в разных командах могут быть разные стандарты. Но как правило это: свойства называются с заглавной буквы, а поля с маленькой, причем имена приватных полей могут начинаться с подчеркивания _.

3. Имена методов

Естественно, называть методы "от балды" нельзя. Как и в предыдущих пунктах, имя/название метода должно отражать его роль/функцию/работу. Но хочется особо отметить методы с ключевыми словами Set/Get/Check.

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

Как делать игры в Unity. Попытка в серию  обучающих постов #2 Unity, Csharp, Gamedev, Обучение, Длиннопост

3.2 Get-методы

Методы с "Get" в названии должны что-то возвращать. Нельзя в таких методах производить какие-либо присваивания и вычисления, которые что-нибудь меняют в классе. Нельзя менять состояние объектов через "гет-методы".

Как делать игры в Unity. Попытка в серию  обучающих постов #2 Unity, Csharp, Gamedev, Обучение, Длиннопост

3.3 Check-методы

Как предполагает название, такие методы должны что-то проверять, возвращая результат проверки (как правило bool). И в таких методах так же не стоит менять состояния объектов.

Как делать игры в Unity. Попытка в серию  обучающих постов #2 Unity, Csharp, Gamedev, Обучение, Длиннопост

4. Модификаторы доступа

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

Открытые (public) поля и методы нужны, что бы ими можно было пользоваться извне, в каком-нибудь другом классе. Поэтому старайтесь минимизировать число открытых членов класса.

По умолчанию используется модификатор private. Однако это не означает, что не стоит его указывать явно. Хорошей практикой программирования является явное указание модификатора доступа, даже если это private.

Если в вашем классе-компоненте необходимо в Unity через инспектор задавать какие-то ссылки (указывать другие объекты, части интерфейса и пр.) - то используйте закрытые (private) поля, но с аттрибутом [SerializeField]. Это сохранит целостность инкапсуляции (другие классы не смогут получить доступ к полю и "испортить" его), однако в инспекторе Unity Вы сможете видеть эти поля и задавать им значения.

Как делать игры в Unity. Попытка в серию  обучающих постов #2 Unity, Csharp, Gamedev, Обучение, Длиннопост

Наверное это основные правила, которые я бы рекомендовал использовать каждому новичку.

Пост подходит к концу, а всем вам желаю успеха в геймдеве!

Показать полностью 6

Как делать игры в Unity. Попытка в серию  обучающих постов #1

Пост №1. Азы программирования.


Всем привет! Попытаюсь поработать над серией обучающих постов по Unity.

Сегодня хочу поговорить об азах правильной работы с языком C# в Unity. Об азах программирования, но не о том, как выучить C#. И о частых ошибках.


Подразумевается, что вы, читатели, уже имеете некое представление о синтаксисе ЯП (языка программирования) и можете написать "Hello, World".

Если нет - то настоятельно рекомендую сначала ознакомиться с C# и только потом уже приступать к работе в Unity. По роду своей работы и по тому, что происходит в ру-сегменте StackOverflow по тегу "Unity3D", очевидно, что большинство проблем/вопросов у новичков возникает по причине незнания ЯП.

Как делать игры в Unity. Попытка в серию  обучающих постов #1 Unity, Csharp, Gamedev, Обучение, Длиннопост

Программирование в Unity на C# немного отличается от "классического" использования C#. Самое главное отличие - в классах-компонентах (наследниках от MonoBehaviour) не принято использовать конструкторы и деструкторы.  И с этим связана одна из частых "ошибок новичков" - попытка создания компонентов ч/з оператор new. Так делать нельзя!

Как делать игры в Unity. Попытка в серию  обучающих постов #1 Unity, Csharp, Gamedev, Обучение, Длиннопост

Классы-компоненты не могут существовать без "носителя"-GameObject'а. Поэтому если вам необходимо добавить новый компонент из кода, необходимо использовать метод AddComponent().

Как делать игры в Unity. Попытка в серию  обучающих постов #1 Unity, Csharp, Gamedev, Обучение, Длиннопост

Если же необходимо создать экземпляр "обычного класса", то в этом случае, разумеется, используется оператор new и конструктор класса.

Еще очень важное отличие - в одном .cs-файле в Unity может быть только один класс-компонент (но это не значит, что в этом же файле нельзя будет определять структуры, другие "обычные классы", перечисления и т.д.)
И файл должен называться точно так же, как класс-компонент (наследник от MonoBehaviour)!

Как делать игры в Unity. Попытка в серию  обучающих постов #1 Unity, Csharp, Gamedev, Обучение, Длиннопост

В классах-компонентах могут быть использованы "предусмотренные движком" методы (Awake(), Start(), Update() и т.д.) Эти методы должны быть определены в классе и должны быть названы точно так же (с учетом регистра), как указано в документации. Иначе они не будут вызываться движком в предусмотренное время в предусмотренном порядке. Это связано с тем, что Unity работает с такими методами через механизм рефлексии.
И самая, на мой взгляд, распространенная "ошибка новичка" при работе с "предусмотренными методами" - работа с Update(), FixedUpdate(), LateUpdate().


Update() - вызывается раз за кадр. И часто новички в этот метод вставляют много бессмысленного кода (а временами и "вредного", негативно сказывающегося на производительности). Не стоит каждый кадр искать компоненты и объекты (н-р, GameObject.FindObjectOfType()) и не стоит каждый кадр обновлять UI (н-р, каждый раз присваивать тексту здоровья текущее значение HP игрока - это стоит делать только при изменении значения). Так же не забывайте использовать Time.deltaTime - время, прошедшее с прошлого вызова Update() (не путать с Time.fixedDeltaTime) если необходимо что-то делать равномерно каждый кадр (н-р, перемещая объект каждый кадр - можно указанную скорость умножать на величину Time.deltaTime).


FixedUpdate() - вызывается фиксированное кол-во раз в секунду. Настраивается в Unity. Как правило этот метод используют для работы с физикой. И тут для "равномерности" необходимо использовать Time.fixedDeltaTime (не Time.deltaTime).


LateUpdate() - вызывается раз за кадр после Update(). Поэтому в момент вызова LateUpdate() уже известны все изменения из Update(). Как правило в этом методе работают с перемещением камеры. Для "равномерности" следует использовать Time.deltaTime.

На этом буду заканчивать с первым постом. Очень надеюсь, что продолжу серию.
А вам всем желаю успеха в геймдеве!

Показать полностью 4
Отличная работа, все прочитано!