S
logo
Soulskiller

Код в проекте

Привет. ‎Расскажу‏ ‎про ‎то, ‎как ‎устроен ‎код‏ ‎в ‎проекте,‏ ‎чего‏ ‎придерживался, ‎что ‎пришлось‏ ‎менять. ‎Тут‏ ‎есть, ‎о ‎чем ‎поговорить.‏ ‎Я‏ ‎поделюсь ‎своим‏ ‎опытом.

Разграничения

Как ‎уже‏ ‎писал ‎в ‎предыдущей ‎статье, ‎пространства‏ ‎имен‏ ‎– ‎это‏ ‎отличный ‎способ‏ ‎разграничить ‎островки ‎игровой ‎логики ‎в‏ ‎проекте‏ ‎в‏ ‎крупном ‎масштабе.‏ ‎На ‎более‏ ‎низком ‎уровне‏ ‎идет‏ ‎разбиение ‎на‏ ‎классы. ‎Помните, ‎Божественный ‎объект ‎–‏ ‎это ‎антипаттерн.‏ ‎К‏ ‎слову, ‎один ‎заказчик‏ ‎немного ‎разбирался‏ ‎в ‎программировании ‎и ‎всерьез‏ ‎хотел,‏ ‎чтобы ‎мы‏ ‎делали ‎именно‏ ‎божественные ‎объекты ‎в ‎играх.

Тогда ‎еще‏ ‎совет.‏ ‎Вы ‎–‏ ‎специалист ‎своего‏ ‎дела, ‎который ‎знает ‎технические ‎подробности‏ ‎реализации‏ ‎проекта,‏ ‎и ‎это‏ ‎ваша ‎обязанность‏ ‎– ‎настоять‏ ‎на‏ ‎правильном ‎обоснованном‏ ‎техническом ‎решении.

Альманах

Не ‎забываем ‎про ‎абстракцию.‏ ‎Если ‎того‏ ‎требует‏ ‎ситуация, ‎сначала ‎делаем‏ ‎абстрактный ‎класс‏ ‎или ‎интерфейс, ‎потом ‎более‏ ‎конкретную‏ ‎реализацию. ‎Не‏ ‎беспокойтесь, ‎никогда‏ ‎не ‎поздно ‎начать ‎извлекать ‎методы‏ ‎и‏ ‎выделять ‎классы.

Интерфейс‏ ‎или ‎абстрактный‏ ‎класс? ‎Абстрактный ‎класс ‎уместней ‎использовать‏ ‎при‏ ‎очевидной‏ ‎общности ‎наследников,‏ ‎интерфейс ‎же‏ ‎– ‎лишь‏ ‎модель‏ ‎поведения, ‎которую‏ ‎могут ‎реализовать ‎объекты, ‎не ‎имеющие‏ ‎ничего ‎общего‏ ‎между‏ ‎собой.

Совет. ‎Учи ‎рефакторинг, это‏ ‎реально ‎полезно.‏ ‎Учи ‎горячие ‎клавиши ‎в‏ ‎среде‏ ‎программирования, ‎это‏ ‎реально ‎полезно.‏ ‎На ‎новом ‎месте ‎работы ‎я‏ ‎научился‏ ‎многому ‎у‏ ‎старших ‎коллег,‏ ‎и ‎в ‎то ‎же ‎время‏ ‎мне‏ ‎тоже‏ ‎было ‎что‏ ‎рассказать ‎и‏ ‎показать ‎им.

Пример‏ ‎абстракции.‏ ‎Когда ‎главный‏ ‎герой ‎знакомится ‎с ‎новым ‎видом‏ ‎противника, ‎то‏ ‎игроку‏ ‎показывается ‎описание ‎нового‏ ‎врага ‎и‏ ‎его ‎особенности, ‎характерные ‎черты‏ ‎поведения.‏ ‎То ‎же‏ ‎самое ‎происходит‏ ‎с ‎новыми ‎подобранными ‎игроком ‎свитками.‏ ‎Логично‏ ‎сделать ‎некую‏ ‎основу, ‎в‏ ‎которой ‎будут ‎меняться ‎детали. ‎Поэтому‏ ‎данные‏ ‎о‏ ‎свитке ‎и‏ ‎данные ‎о‏ ‎новом ‎противнике‏ ‎унаследованы‏ ‎от ‎общего‏ ‎класса ‎от ‎ScriptableObject. ‎Страница ‎описания‏ ‎противника, ‎и‏ ‎страница‏ ‎описания ‎свитка ‎тоже‏ ‎имеют ‎сходство,‏ ‎но ‎в ‎описании ‎противника‏ ‎мы‏ ‎еще ‎показываем‏ ‎список ‎характерных‏ ‎черт, ‎а ‎в ‎свитках ‎есть‏ ‎только‏ ‎описание.

Только ‎спустя‏ ‎пару ‎лет‏ ‎практики ‎программирования ‎начинаешь ‎понимать ‎принципы‏ ‎SOLID‏ ‎и‏ ‎ООП ‎по-настоящему.‏ ‎Не ‎просто‏ ‎так ‎в‏ ‎каждом‏ ‎ролике, ‎в‏ ‎каждой ‎статье ‎или ‎интервью ‎с‏ ‎разработчиками ‎повторяется‏ ‎как‏ ‎мантра: ‎каждая ‎механика‏ ‎– ‎это‏ ‎отдельный ‎островок, ‎который ‎работает‏ ‎независимо‏ ‎от ‎других;‏ ‎удаляя ‎один‏ ‎компонент, ‎другой ‎не ‎должен ‎сломаться…‏ ‎Старайтесь‏ ‎придерживаться ‎принципов‏ ‎программирования, ‎это‏ ‎в ‎любом ‎случае ‎дешевле ‎обойдется,‏ ‎чем‏ ‎потом‏ ‎переделывать ‎все,‏ ‎поправляя ‎одно,‏ ‎ломая ‎тем‏ ‎самым‏ ‎другое. ‎

Совет.‏ ‎Не ‎переставайте ‎менять ‎именование ‎полей,‏ ‎методов ‎и‏ ‎классов‏ ‎до ‎тех ‎пор,‏ ‎пока ‎не‏ ‎станет ‎максимально ‎удовлетворять ‎вас.‏ ‎Именование‏ ‎должно ‎лаконично‏ ‎передавать ‎суть‏ ‎и ‎все. ‎Классы ‎именуются ‎как‏ ‎имя‏ ‎существительное, ‎методы‏ ‎как ‎глагол.‏ ‎События ‎привычно ‎писать ‎со ‎слова‏ ‎On‏ ‎(OnHit,‏ ‎OnLoaded, ‎OnError),‏ ‎но ‎методы,‏ ‎которые ‎на‏ ‎них‏ ‎подписываются, ‎должны‏ ‎передавать ‎свою ‎суть ‎(GetDamage, ‎Unfade,‏ ‎SetDefaultValues). ‎Помните,‏ ‎большую‏ ‎часть ‎времени ‎вы‏ ‎прежде ‎всего‏ ‎читаете ‎код, ‎нежели ‎непосредственно‏ ‎пишите‏ ‎его. ‎Решиться‏ ‎на ‎изменения‏ ‎в ‎коде ‎гораздо ‎легче, ‎если‏ ‎хорошо‏ ‎владеть ‎IDE‏ ‎(например, ‎переименование‏ ‎и ‎извлечение ‎метода).

Совет. ‎Используйте ‎ключевое‏ ‎слово‏ ‎field‏ ‎в ‎атрибутах,‏ ‎оно ‎позволяет‏ ‎воспринимать ‎свойства‏ ‎как‏ ‎поля, ‎отображая‏ ‎их ‎в ‎инспекторе, ‎но ‎все‏ ‎еще ‎инкапсулировать‏ ‎данные.‏ ‎Не ‎пренебрегайте ‎ограничением‏ ‎доступа ‎к‏ ‎данным. ‎Этот ‎трюк ‎сокращает‏ ‎количество‏ ‎строчек ‎в‏ ‎2 ‎раза,‏ ‎Карл! ‎Этот ‎десяток ‎строк ‎мог‏ ‎выглядеть‏ ‎как ‎20‏ ‎строк.

Спаун ‎противников

Тут‏ ‎вроде ‎все ‎просто. ‎Враги ‎появляются‏ ‎по‏ ‎волнам.‏ ‎Волны, ‎количество‏ ‎противников ‎и‏ ‎период ‎их‏ ‎создания‏ ‎во ‎время‏ ‎волны ‎определяется ‎в ‎SpawnerData. ‎Они‏ ‎могут ‎появляться‏ ‎на‏ ‎протяжении ‎всей ‎волны,‏ ‎могут ‎в‏ ‎начале ‎волны ‎или ‎только‏ ‎в‏ ‎конце; ‎по‏ ‎одному ‎в‏ ‎секунду ‎или ‎сразу ‎скопом.

С ‎самого‏ ‎начала‏ ‎я ‎не‏ ‎до ‎конца‏ ‎продумал ‎как ‎именно ‎будут ‎появляться‏ ‎противники‏ ‎на‏ ‎арене, ‎а‏ ‎я ‎очень‏ ‎хотел ‎внести‏ ‎какую-то‏ ‎оригинальность ‎в‏ ‎моей ‎игре. ‎Поэтому ‎мне ‎пришлось‏ ‎переопределить ‎архитектуру‏ ‎этой‏ ‎части ‎кода. ‎Теперь‏ ‎точка ‎появления‏ ‎и ‎логика ‎этого ‎события‏ ‎делегируются‏ ‎в ‎отдельный‏ ‎класс ‎SpawnDealer.‏ ‎Он ‎стал ‎отвечать ‎за ‎то,‏ ‎как‏ ‎именно ‎и‏ ‎где ‎появится‏ ‎противник. ‎Например, ‎арахниды ‎появляются ‎с‏ ‎помощью‏ ‎червя‏ ‎Нидуса, ‎если‏ ‎такого ‎нет‏ ‎на ‎сцене,‏ ‎сначала‏ ‎появится ‎червь,‏ ‎проиграется ‎анимация, ‎а ‎уж ‎потом‏ ‎появится ‎противник‏ ‎из‏ ‎него. ‎Духи ‎появляются‏ ‎только ‎в‏ ‎темных ‎участках ‎арены, ‎а‏ ‎демоны‏ ‎в ‎точках,‏ ‎где ‎есть‏ ‎огонь ‎(факел, ‎костер, ‎пожар). ‎Некоторые‏ ‎противники‏ ‎появляются ‎с‏ ‎помощью ‎молний,‏ ‎только ‎на ‎участках ‎арены ‎под‏ ‎открытым‏ ‎небом.

Красными‏ ‎точками ‎отмечены‏ ‎темные ‎места‏ ‎для ‎появления‏ ‎Духов,‏ ‎а ‎белыми‏ ‎точки ‎под ‎открытым ‎небом ‎для‏ ‎создания ‎молнии‏ ‎и‏ ‎спауна ‎противников ‎из‏ ‎них.

Урон ‎и‏ ‎здоровье

Эту ‎часть ‎игры ‎тоже‏ ‎пришлось‏ ‎переписывать ‎после‏ ‎первых ‎попыток.‏ ‎Итогом ‎стали ‎абстрактный ‎класс ‎Health‏ ‎и‏ ‎его ‎наследники‏ ‎HealthPart ‎и‏ ‎HealthParent. ‎Предполагалось, ‎что ‎попадание ‎в‏ ‎разные‏ ‎части‏ ‎тела ‎(HealthPart)‏ ‎дает ‎множитель‏ ‎на ‎получаемый‏ ‎урон,‏ ‎передавая ‎значения‏ ‎на ‎HealthParent, ‎который ‎у ‎противника‏ ‎есть ‎в‏ ‎единственном‏ ‎экземпляре. ‎Это ‎решение‏ ‎из ‎общей‏ ‎папки ‎с ‎кодовой ‎базой,‏ ‎на‏ ‎самом ‎деле‏ ‎в ‎проекте‏ ‎используется ‎только ‎HealthParent.

Так ‎как ‎в‏ ‎игре‏ ‎есть ‎стихийный‏ ‎урон ‎и‏ ‎различные ‎мета-данные ‎нанесения ‎урона ‎(с‏ ‎какой‏ ‎стороны‏ ‎прилетел ‎удар,‏ ‎точка ‎удара,‏ ‎физическая ‎сила‏ ‎удара,‏ ‎префабы ‎попадания),‏ ‎я ‎сделал ‎структуру ‎HitData, ‎а‏ ‎также ‎DamageDealer‏ ‎для‏ ‎удобства ‎заполнения ‎этих‏ ‎данных.

Совет. ‎Старайтесь‏ ‎подписываться ‎на ‎события ‎(если‏ ‎это‏ ‎не ‎дочерние‏ ‎компоненты), ‎нежели‏ ‎напрямую ‎завязывать ‎внешние ‎объекты ‎между‏ ‎собой.‏ ‎Это ‎уменьшит‏ ‎связность ‎проекта,‏ ‎позволит ‎убирать ‎или ‎добавлять ‎что-либо‏ ‎на‏ ‎сцену,‏ ‎не ‎ломаю‏ ‎остальное.

Завершение

Понимаешь ‎диаграммы‏ ‎классов? ‎Что-то‏ ‎стоит‏ ‎поправить? ‎Что‏ ‎думаешь? ‎Есть ‎польза ‎от ‎написанного?‏ ‎Критикуй, ‎пиши,‏ ‎прочтем.‏ ‎Я ‎очень ‎надеюсь,‏ ‎что ‎делаю‏ ‎какое-то ‎полезное ‎дело, ‎в‏ ‎надежде‏ ‎повысить ‎свою‏ ‎и ‎вашу‏ ‎грамотность ‎в ‎написании ‎кода.

Разработчик | Проект | YouTube | e-mail | Поддержка

Предыдущий

Все посты проекта
0 комментариев

Подарить подписку

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

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

Будет создан код, который позволит адресату получить сумму на баланс.

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

Добавить карту
0/2048