Будь ласка, використовуйте цей ідентифікатор, щоб цитувати або посилатися на цей матеріал:
https://er.chdtu.edu.ua/handle/ChSTU/9077| Назва: | Розробка рольової гри Lost Space |
| Автори: | Метелап, Володимир Володимирович Завгородній, Владислав Ігорович |
| Дата публікації: | 13-чер-2022 |
| URI (Уніфікований ідентифікатор ресурсу): | https://er.chdtu.edu.ua/handle/ChSTU/9077 |
| Розташовується у зібраннях: | 121 Інженерія програмного забезпечення (Інженерія програмного забезпечення) |
Файли цього матеріалу:
| Файл | Опис | Розмір | Формат | |
|---|---|---|---|---|
| Кваліфікаційна робота бакалавра Завгородній Владислав Ігорович.pdf Restricted Access | 1.37 MB | Adobe PDF | Переглянути/Відкрити Запит копії |
Усі матеріали в архіві електронних ресурсів захищено авторським правом, усі права збережено.
Extracted text
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
ЧЕРКАСЬКИЙ ДЕРЖАВНИЙ ТЕХНОЛОГІЧНИЙ УНІВЕРСИТЕТ
Факультет інформаційних технологій і систем
Кафедра програмного забезпечення автоматизованих систем
Пояснювальна записка
до кваліфікаційної роботи бакалавра
на тему: «Розробка рольової гри Lost Space»
з напряму підготовки 121 «Інженерія програмного забезпечення»
(освітньо-кваліфікаційний рівень)
Виконав: студент ПЗС-1944
Напряму підготовки
121 «Інженерія програмного забезпечення»
(шифр і назва напряму підготовки)
Студент ________Завгородній В.І.________
(прізвище та ініціали)
Керівник _______Метелап В.В.__________
(прізвище та ініціали)
Рецензент_____________________________
(прізвище та ініціали)
Черкаси 2022 рік
ЗМІСТ
ПЕРЕЛІК СКОРОЧЕНЬ ТА ПЕРЕЛІК УМОВНИХ ПОЗНАЧЕНЬ .......... 4
ВСТУП ...................................................................................................................... 5
1. ПОСТАНОВКА ЗАДАЧІ ................................................................................. 7
1.1. Актуальність та аналіз предметної області .............................................. 7
1.2. Обґрунтування вибору технологій............................................................ 8
1.3. Моделювання предметної області ............................................................ 9
1.4. Формування ТЗ ........................................................................................... 9
1.5. Комп’ютерні ігри ...................................................................................... 10
2. ПРОЕКТУВАННЯ СИСТЕМИ ...................................................................... 15
2.1. План реалізації проекту ........................................................................... 15
2.2. Проектування програмних модулів ........................................................ 17
2.3. Проектування дій користувача ................................................................ 17
2.4. Проектування інтерфейсу користувача .................................................. 18
3. РОЗРОБКА ТА ТЕСТУВАННЯ СИСТЕМИ ................................................ 23
3.1. Розробка ядра ............................................................................................ 23
3.2. Розробка персонажу ................................................................................. 24
3.3. Розробка ворогів ....................................................................................... 27
3.4. Розробка ігрових механік ......................................................................... 28
3.5. Тестування ігрових механік ..................................................................... 41
ВИСНОВКИ ........................................................................................................... 43
СПИСОК ЛІТЕРАТУРИ ....................................................................................... 44
Додаток А ............................................................................................................... 45
Додаток Б................................................................................................................ 48
Додаток В ............................................................................................................... 61
Додаток Г ............................................................................................................... 63
ЧДТУ. 211962-005ПЗ
Зм. Лист № документа Підпис Дата
Розроб. Завгородній В.І «Розробка рольової гри Lost Space» Літ. Лист Листів
Керівник Метелап В.В Пояснювальна записка Н 3
Д
ФІТІС, кафедра ПЗА С,
Н.контр. Півень О.Б.
Затв. .Первунінський С.М. ПЗС-1944
ЧДТУ 211962.005ПЗ
ПЕРЕЛІК СКОРОЧЕНЬ ТА ПЕРЕЛІК УМОВНИХ ПОЗНАЧЕНЬ
ТЗ – технічне завдання;
Паттерн – набір правил та ресурсів для структуризації розробки;
RPG – Role Play Game;
Ігровий рушій – програмний рушій, центральна програмна частина
будь-якої відеогри;
UML – Unified Modeling Language;
ПК – персональний комп’ютер;
«Залізо» – апаратні системи комп’ютера;
Фреймворк – інфраструктура програмних рішень, що полегшує
розробку складних систем;
Тайл – у комп’ютерні графіці – зображення, яке використовується для
створення текстур шляхом укладання копій цього зображення на зразок
«черепиці».
Туторіал – пояснення ігрових механік та управління персонажем
користувачеві
4
ЧДТУ 211962.005ПЗ
ВСТУП
За останні декілька десятиліть у світі виник та оформився новий
напрям розробки – це комп’ютерні ігри.
На сьогоднішній день ринок комп’ютерних ігор є одним з
найприбутковіших. З моменту початку інформаційно-технічної революції
світ стрімко рухається в майбутнє, створюючи все більш досконалі
комп'ютерні системи, щоб полегшити життя людини, а так само зайняти його
дозвілля.
З появою персональних комп'ютерів, з кожним роком, їх роль в житті
людей постійно зростає. Комп'ютер став незамінним помічником не тільки в
сфері економічних розрахунків, а й є потужним центром розваг. Сфери
впливу кіно і літератури відчувають потужний тиск з боку інтерактивних
розваг, пристроїв доповненої реальності і інших, впроваджуваних завдяки
розвитку комп'ютерних технологій. Сучасна людина іноді навіть не
замислюється, що і його смартфон є аналогічним мобільним персональним
комп'ютером. З ростом ролі комп'ютерів в житті людини, комп'ютерна
техніка суттєво впливає і на модель поведінки людини. За останніми
дослідження середній вік гравця комп'ютерних ігор становить 30 років і вище.
Комп'ютерні розваги роблять життя людини багатшим, більш
насиченим і як наслідок ‒ це потужна економічна сфера приносить величезні
доходи.
Тому не випадково, що особлива роль у житті сучасної людини
відводиться комп'ютерним іграм, перші з яких існували на самій зорі
комп'ютерної техніки.
Можна сказати, що ігри ‒ це це певний вид мистецтва, схожий з
іншими видовищними жанрами. Ігри можуть нести не тільки розважальний
характер, але і змушувати задуматися, переживати, піднімати серйозні
глобальні або психологічні питання. Іншими словами ‒ це ігри ‒ це це
5
ЧДТУ 211962.005ПЗ
сучасний вид мистецтва. Комп'ютерні ігри часом дарують емоцій не менше,
ніж перегляд кінофільму або театральної постановки.
В даній курсовій роботі створюється ігровий код на основі якого
будується ігрова програма.
Метою даної роботи є розробка невеликої комп’ютерної рольової гри
на Unity яка, може залучити потенціальних покупців в стрімко
розширюваному ринку комп’ютерних ігор.
6
ЧДТУ 211962.005ПЗ
1. ПОСТАНОВКА ЗАДАЧІ
1.1. Актуальність та аналіз предметної області
Провівши поверхневий аналіз ринку комп’ютерних ігор було виявлено
3 основних потенційних конкурентів: Hollow Knight[1], Ori and the Blind[2]
Forest і Salt and Sanctuary[3].
Hollow Knight – це мультиплатформна відеогра в жанрі метроїдванія з
елементами RPG, випущена інді-студією Team Cherry у 2017 році для ПК.
Гра розповідає про пригоди та відкриття безіменного жука, якого усі
називають просто Лицарем, у давно покинутому королівстві комах
Святогнізді (Hallownest). Деякі критики назвали гру однією з найбільш
атмосферних і якісних метроїдваній, а також класикою жанру.
Ori and the Blind Forest – Гра є двовимірним платформером з деякими
тривимірними елементами. Гравець управляє персонажем на ім'я Орі —
казковою істотою білого кольору, котра нагадує щось середнє між лисицею,
білкою і дикою кішкою.
Сюжет описує пригоди лісового духа Орі в подобі звірятка. Коли ліс
занепадає, Орі вирушає відновити баланс стихій і знайти джерело лиха,
розкриваючи заразом таємницю власного походження.
Salt and Sanctuary – комп'ютерна рольова гра в жанрі Action/RPG з
елементами платформера, розроблена та випущена студією Ska Studios для
PlayStation 4 у 2016 році. Надалі гра була портована на Microsoft Windows,
macOS, Linux, PlayStation Vita, Xbox One та Nintendo Switch.
У ході гри керований гравцем персонаж обстежує таємничий острів,
куди його закинуло аварію корабля; гру відрізняє двомірна графіка,
намальована від руки у характерному стилі.
7
ЧДТУ 211962.005ПЗ
1.2. Обґрунтування вибору технологій
Оцінивши методи розробки комп’ютерних ігор, було обрано розробку
гри за допомогою ігрового рушія Unity та мови програмування C#.
Unity[4] — багатоплатформовий інструмент для розробки відеоігор і
застосунків, і рушій, на якому вони працюють. Створені за допомогою Unity
програми працюють на настільних комп'ютерних системах, мобільних
пристроях та гральних консолях у дво- та тривимірній графіці, та на
пристроях віртуальної чи доповненої реальності. Застосунки, створені за
допомогою Unity, підтримують DirectX та OpenGL.
Розглянемо цей двигун у порівнянні з UnrealEngine4. Переваги Unity:
‒ це IDE: поєднання редактора сцен (в комплексі загального редактора)
редактором ігрових об'єктів та редакторів скриптів. Додатково додаються
генератори дерев та террейнів. Покращені можливості скриптингу, а саме на
відміну від вищевказаного движка, в Unity доступні три мови: JavaScript, C# і
різновид Python's Boo;
‒ це кроссплатформеність ‒ це як уже згадувалося вище,
підтримуються Windows, MacOS, Wii, iPhone, iPod, iPad, Android, PS3 та
XBox), на смартфонах та планшетах (iOS, Android, Windows Phone), на 360,
не всі з яких, звичайно, доступні у безкоштовній ліцензії. Ну і веб- плагін,
звичайно, забувати не варто.
Сучасний рівень графіки, здатний конкурувати з іншими двигунами.
Unity, безумовно, програє UnrealEngine за кількістю реалізованих
можливостей. Однак Unity має такі можливості, як deferred освітлення,
стандартний набір постпроцессінгових ефектів, SSAO, прискорено
опрацювання лайтмапів.
Гідним чином оброблений фізичний двигун. Масштабованість і
продуктивність. Більшу частину простих процесів двигун обробляє на
чудовому рівні.
8
ЧДТУ 211962.005ПЗ
Запуск будь-якої програми на Unity у веб-плагін.
Невисока ціна за повну ліцензійну версію великого веб-розробника.
Недоліки Unity:
‒ це закритість коду. Неможливість отримання вихідних кодів движка
навіть за ліцензією.
‒ це неможливість доповнення фізики движка сторонніми
можливостями. Ви не можете додати в двигун сторонню фізику, або
SpeedTree.
Реальні мінуси важко визначити з першого погляду. Двигун
продуктивний, стабільний та легкий у застосуванні.
1.3. Моделювання предметної області
Проаналізувавши конкуруючі продукти на ринку, було вирішено, що
проект перш за все повинен складатись з відокремлених рівнів (сцен) для
кращої оптимізації гри та розбиття одної основної задачі з розробки на менші,
легші в реалізації задачі.
Алгоритм користувача має бути наступним: користувач запускає файл
гри, натискає кнопку «Старт» та починає грати.
Інтерфейс користувача та управління персонажем повинно бути
інтуїтивним, на початку гри повинен бути туторіал для меншого порогу
входження до гри.
1.4. Формування ТЗ
Технічне завдання - це інструмент, який дозволяє привести бажання
клієнта у відповідність із можливостями розробника і здатний врегулювати
всі можливі конфлікти та заощадити час. Безумовно, технічне завдання
визначає коло завдань, які слід виконати під час створення цього проекту.
9
ЧДТУ 211962.005ПЗ
Необхідно надати розробникові структуру проекту якомога детальніше
і пояснити, як повинна виглядати остаточна версія. Таким чином, технічне
завдання на розробку комп’ютерної гри повинно містити таке:
− технічні характеристики;
− маркетингові вимоги;
− особливості дизайну.
В ідеальному випадку всі деталі роботи та зовнішнього вигляду
повинні бути зазначені в технічному завданні, таким чином невідповідності
будуть мінімізовані, а результат відповідатиме вимогам та очікуванням
замовника.[5]
Так як явного замовника не має, то усі вимоги будуть відповідати тим,
що були розроблені командою розробників системи. Таким чином до
технічних вимог відносяться: вибір, обґрунтування та опис
апаратних(hardware) та системних(software) засобів, архітектурні вимоги,
опис системи, опис задіяних технологій та їх опис, вимоги до реалізації та
подальших оновлень, Огляд продукту з точки зору різних типів користувачів.
Маркетингові вимоги охоплюють дослідження цільової аудиторії, аналіз
ринку, локалізація, ресурси для реалізації, потоки прибутків, потоки витрат,
канали збуту, ризики, бізнес план та обумовлення існування продукту.
Особливості дизайну ґрунтуються на описаних вище вимогах і дослідженнях.
Оскільки, система на момент написання роботи не є комерційним продуктом,
то не має потреби описувати бізнес план і все, що стосується Lost Space як
продукту на ринку.
1.5. Комп’ютерні ігри
Розглянемо комп'ютерні ігри, розділивши їх на етапи мистецтва. Роль
автора виконує розробник гри, а все решта ролі ділять між собою готова
комп'ютерна програма (відеогра) і сам гравець. Виходить так, що гравець: 1) і
безпосередньо грає, 2) і сам дивиться шоу зі своєю участю, 3) і за рахунок
інтерактивності має стільки свободи, що може вважатися співавтором того
10
ЧДТУ 211962.005ПЗ
уявлення, що відбувається на екрані. Дует «відеогра + гравець» містять в собі
відразу всі три рівня мистецтва: творчість, гра, видовище.
Таким чином, вираз «Комп'ютерні ігри ‒ це мистецтво» ‒ це це не
просто заява про те, що ігри ‒ це це ще один черговий вид мистецтва. Це
практично знак рівності «Комп'ютерні ігри = мистецтво». Все те, що ми
раніше називали видами мистецтва, входить до складу комп'ютерних ігор
(архітектура ‒ це це левелдізайн, скульптура ‒ це моделювання, мистецтво ‒
це текстури та спрайт, танець ‒ це анімація моделей, музика ‒ це звуковий
супровід, театр ‒ це скріптові сценки, кіно ‒ це відеовставки) ; всі рівні
мистецтва (творчість, гра, видовище) присутні в будь-який найпростішої
комп'ютерній грі. Відеоігри ‒ це це особливе метамистецтво, що об'єднало в
собі всі напрацювання минулих видів мистецтв.
Відеоігри не можуть замінити собою все життя, але добре вміють
вгамувати людську спрагу в нових відчуттях, видовищах, думках, знаннях ‒
це все те, що дає нам область мистецтва.
Комп'ютерні ігри зародилися в 50-х роках минулого століття (понад 60
років тому), а ігрові жанри з'явилися лише 20 років тому. На початковому
етапі розвитку ігрової індустрії кожна гра була унікальна і неповторна. Але з
часом ігор ставало все більше і більше. Для того, щоб орієнтуватися у всьому
різноманітті ігор, люди стали розділяти гри на різні категорії.
Критерії поділу на категорії були найрізноманітніші: кількість гравців,
вид ігрової камери, сюжет (докладніше про всіх видах класифікації ігор в
статті «Класифікація комп'ютерних ігор»). Але більшу популярність отримав
спосіб поділу на ігрові жанри.
Жанри ігор формувалися безструктурно і інтуїтивно протягом
тривалого часу. Розробники ігор проводили сміливі експерименти,
створюючи нові ігрові механіки. Невдалі експерименти забувалися, а вдалі
ігри ставали прикладом для інших розробників. Розробники копіювали
популярну ігрову механіку, додаючи трохи ідей від себе, таким чином
11
ЧДТУ 211962.005ПЗ
навколо найбільш популярних ігор утворювалися цілі класи схожих між
собою ігор, ці класи і стали називати ігровими жанрами. Схема ігрових
жанрів рис. 1.1:
Рисунок 1.1 Таблиця жанрів
З початкових даних у нас тільки історично сформувалися жанри.
Диспонуємо їх назви на одній площині, і намагаємося визначити по готовим
екземплярів, в якій системі координат вони знаходяться.
За основний критерій поділу жанрів беремо дії, найбільш часто
здійснюються в іграх цього жанру, і нічого більше (положення камери: вид з
очей, вид ззаду, вид зверху, вид з кабіни; рух часу: реальний час або
покроковий режим; кількість гравців НЕ ‒ це є критеріями для жанрів, вони
лише визначають спосіб подачі геймплея).
Почнемо препарування кожного жанру, в надії розкласти його на більш
дрібні складові частини. Необхідно мати великий ігровий досвід у
відповідних жанрах, щоб зрозуміти, з чого вони вони складаються.
Угруповання, система координат
Всі знайдені елементарні частинки жанрів диспонуємо на лінії, і
використовуємо їх як систему координат.
Методом підбору групуємо всі частинки на три підгрупи: рольові,
стрілянина, стратегії. Всі ігри всередині групи дуже схожі між собою, але
12
ЧДТУ 211962.005ПЗ
одночасно з цим є гри з різними відхиленнями. Іноді відхилення невеликі, а
іноді дуже суттєві. Такі, далеко відійшли від еталонних (для групи) ігор,
стають зовсім не схожі на своїх ідейних предків, але при цьому вони все одно
знаходяться всередині групи. Значить самі групи ігор набагато ширше ніж їх
еталонні представники. Еталони знаходяться на золотій середині, а гри з все
великими відхиленнями ‒ це все далі від центру.
У кожній групі були знайдені крайні кордону. А коли знайдені кордону,
групі простіше дати правильну назву, простіше розділити на окремі складові
частини. У підсумку всі жанри успішно розкваліфікувались на три початкові
великі групи, кожна велика група розпалася на п'ять рівних елементів, що
лежать в одній площині. Вийшла красива, ідеально вибудувана таблиця, що
складається з п'ятнадцяти елементарних жанрів. І що дивно, з цієї таблиці
легко можна класифікувати взагалі будь-яку гру, а не тільки комп'ютерну.
Класифікуються і настільні, і дворові, і телевізійні, і навчальні ігри.
Трьох великих груп ігор були дані наступні назви:
− Ігри спілкування. Основні дії: отримання інформації, спілкування,
вивчення світу;
− Ігри дій. Основні дії: переміщення в просторі, використання зброї
та техніки;
− Ігри контролю. Основні дії: командування, управління, розподіл
матеріальних засобів.
Висновок до першого розділу
Виявлено головних конкурентів: Hollow Knight, Ori and the Blind Forest
і Salt and Sanctuary. Це досить хороші комп’ютерні ігри які отримали багато
нагород за їх сюжет, графічну складову та механіки які в них реалізовані. З
мінусів можна відмітити досить великий поріг входження в деяких з цих ігор.
Дослідивши технології, на яких реалізовані конкуренти, глибокому
аналізі ринку та власних можливостей, було виявлено, що при написанні
проектного коду необхідно використати розбиття основних задач на
13
ЧДТУ 211962.005ПЗ
підзадачі, а також створення псевдо відкритого ігрового світу шляхом
обмеження його коридорними сценами, що досить добре відобразилося на
оптимізації проекту та полегшенні його тестування.
Також було вирішено додати елементи головоломки до основної теми
гри для збільшення інтересу при дослідженні ігрового світу.
14
ЧДТУ 211962.005ПЗ
2. ПРОЕКТУВАННЯ СИСТЕМИ
Проектування складається із послідовних дій: опису головних
сутностей, формування на їх основі головних та вторинних програмних
модулів, опис взаємодії різних типів користувачів із системою, проектування
користувацького інтерфейсу. Усе це включає у себе план реалізації проекту.
2.1. План реалізації проекту
Перед тим як почати процес проектування системи, було складено план
реалізації, який включає у себе дані про дні на виконання, даних початку та
завершення задач з переліком ресурсів, необхідних у процесі, відповідно до
можливостей реалізаторів. Так як є частини, які не можливо реалізувати,
якщо не має вже готового функціоналу, то вони були побудовані із
включенням цієї залежності.
Таблиця 2.1
Перелік необхідних робіт до виконання
Днів
Дата Зад
на Дата
Назва задачі завершен ачі Ресурси
викон початку
ня до
ання
Ініціалізація
Оренда офісу[1],
Вс Вс
Пошук аналогів 1 днів Трудові
01/21/22 01/21/22
ресурси,Харчування
Встановлення
Чт Сб Трудові ресурси,
вимог до 3 днів 3
01/24/22 01/26/22 Електроенергія[1]
пректування
Проектування
15
ЧДТУ 211962.005ПЗ
Електроенергія[1],
11 Сб Вт
Напитання ТЗ Трудові
днів 02/5/22 02/15/22
ресурси,Харчування
Електроенергія[1.5],
Реалізація 15 Ср Ср Оренда офісу[1.5],
17
дизайну гри днів 02/09/22 2/23/22
Харчування,Трудові
ресурси
Реалізація
10 Пт Вс
Меню
днів 02/18/22 02/27/22
Пт Ср
Сцена 1 5 днів
02/18/22 02/23/22
Ср Вс
Сцена 2 5 днів
02/23/22 02/27/22
Вс Чт
Сцена 3 5 днів
02/27/22 03/03/22
Чт Пн
Сцена 4 5 днів
03/03/22 03/07/22
12 Пн Сб
Сцена 5
днів 03/07/22 03/18/22
Тестування
15 Пт Пт
управління
днів 03/25/22 04/08/22
персонажем
Тестування 7 днів Пт Чт
16
ЧДТУ 211962.005ПЗ
взаємодій 04/08/22 04/14/22
Тестування Чт Пт
9 днів
тригерів 04/14/22 04/22/22
Тестування Пт Пт
9 днів
бойової системи 04/22/22 04/30/22
Для простішого сприйняття що за чим має реалізовуватися, було
розроблено схему планування задач із розподілом з приблизною кількістю
годин на виконання. Час на виконання було прив’язано до дат, для
прогнозування приблизного часу на реалізацію проекту.(див. таблицю 2.1)
2.2. Проектування програмних модулів
Опис продукту включає у себе перелік очікуваних до реалізації модулів,
архітектурні вимоги, вказівку пріорітетів розробки, опис технологій, які
знадобляться при розробці, а також огляд продукту з різних точок зору. Всі
пункти можуть включати у себе діаграми та схеми, для ліпшого розуміння та
уявлення як система має працювати.
Lost Space складається із програмних модулів. Програмний модуль
включає у себе набір функціональних, графічних і архітектурних вимог, які
спрямовані на спільний результат.
Основними програмними модулями є:
1. Головне меню: включає в себе кнопки для взаємодії з додатком;
2. Налаштування: включає в себе налаштування звуку та управління;
3. Сцени: є основним елементом програми, включають в себе всі
основні механіки гри.
2.3. Проектування дій користувача
Основним типом користувачів є гість, тому проектувати додаток
потрібно так, щоб у користувача було якомога більше можливостей.
17
ЧДТУ 211962.005ПЗ
Рисунок 2.1. UML діагама алгоритму дій користувача
Як видно з рисунку 2.1, користувач має можливість для створення
нової гри або завантаження збереженої, також після закінчення гри
користувач може зберегти прогрес.
2.4. Проектування інтерфейсу користувача
Оскільки проект розроблявся самотужки, інтерфейс має дуже
спрощений вигляд.
Головне меню спроектовано таким чином, щоб користувачу було
інтуїтивно зрозуміло які кнопки для чого використовуються. Через кнопки на
головному меню можна запустити гру, зайти в меню налаштувань або ж
вимкнути гру.
18
ЧДТУ 211962.005ПЗ
Рисунок 2.2 Головне меню гри
Рисунок 2.3 Меню налаштувань
Інтерфейс розроблений для екранів з роздільною здатністю 1920 х 1080
пікселів, але він також адаптується до екранів з іншою роздільною здатністю.
Наступними по алгоритму розробки є сцени, кожна сцена відображає
свою частину ігрового світу і має зони переходу між собою.
19
ЧДТУ 211962.005ПЗ
Рисунок 2.4. Сцена 1
Рисунок 2.5. Сцена 2
20
ЧДТУ 211962.005ПЗ
Рисунок 2.6. Сцена 3
Рисунок 2.7. Сцена 4
Рисунок 2.8. Сцена 5
На кожній сцені розміщені свої елементи ігрового процесу, гравцю
потрібно поступово переміщуватися по ігровому світові, знайти зброю та
захищатися від ворогів.
Висновок до другого розділу
Щоб реалізувати систему був розроблений і описаний план роботи. Він
включає у себе таблицю задач із розписаними по датам початку та
завершення дій у залежності від пріорітетності та залежностей
функціональних одиниць.
21
ЧДТУ 211962.005ПЗ
Було спроектовано програмні модулі, які дозволяють керувати
додатком, а також був спроектований користувацький інтерфейс.
Також були спроектовані 5 тестових сцен, які використовуються як
туторіал для гравця, що зменшує поріг входження для нових гравців та
людей, які ніколи не грали в комп’ютерні ігри.
22
ЧДТУ 211962.005ПЗ
3. РОЗРОБКА ТА ТЕСТУВАННЯ СИСТЕМИ
3.1. Розробка ядра
Ядро системи розробки було завантажене з Unity Assets store, завдяки
ядру було полегшено розробку сцен.
За допомогою ядра було розроблено взаємодію з ігровими предметами,
виглядає це наступним чином:
Взаємодія з кнопкою:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace Gamekit2D
{
public class InteractOnButton : InteractOnTrigger
{
public string buttonName = "X";
public UnityEvent OnButtonPress;
bool m_CanExecuteButtons = false;
protected override void ExecuteOnEnter(Collider other)
{
m_CanExecuteButtons = true;
}
protected override void ExecuteOnExit(Collider other)
{
m_CanExecuteButtons = false;
}
23
ЧДТУ 211962.005ПЗ
void Update()
{
if (m_CanExecuteButtons &&
Input.GetButtonDown(buttonName))
{
OnButtonPress.Invoke();
}
}
}
}
3.2. Розробка персонажу
В процесі розробки був створений ігровий персонаж Еллен.
Розробка дизайну персонажу проводилась за допомогою Adobe
Photoshop.
Рисунок 3.1 Ігровий персонаж
24
ЧДТУ 211962.005ПЗ
Для персонажу було розроблено декілька видів спрайтів, які
використовуються для анімації персонажу та переключаються між собою в
процесі гри.
Також для персонажу було розроблено два види зброї: зброя для
ближнього бою та зброя для дальнього бою.
Рисунок 3.2 Зброя дальнього бою
25
ЧДТУ 211962.005ПЗ
Рисунок 3.2 Зброя ближнього бою
26
ЧДТУ 211962.005ПЗ
3.3. Розробка ворогів
Для ускладнення ігрового процесу було створено декілька видів
ворогів один, з яких є головним ворогом.
Рисунок 3.3 Chomper
Рисунок 3.4 Spitter
27
ЧДТУ 211962.005ПЗ
Рисунок 3.5 Gunner
У кожного із ворогів є свій тип атаки, а у головного ворога їх 3.
3.4. Розробка ігрових механік
В проекті було розроблено такі ігрові механіки як переміщення
ігрового персонажу та ворогів, що є базовою механікою, також було
реалізовано ближній та дальній бій для головного героя та ворогів.
По ігровому світу були розставлені головоломки та предмети для
персонажу.
Наприклад режими атаки головного ворога:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using BTAI;
28
ЧДТУ 211962.005ПЗ
using UnityEngine.Events;
using System;
using Gamekit2D;
public class MissileGolem : MonoBehaviour
#if UNITY_EDITOR
, BTAI.IBTDebugable
#endif
{
[System.Serializable]
public class BossRound
{
public float platformSpeed = 1;
public MovingPlatform[] platforms;
public GameObject[] enableOnProgress;
public int bossHP = 10;
public int shieldHP = 10;
}
public Transform target;
public int laserStrikeCount = 2;
public float laserTrackingSpeed = 30.0f;
public float delay = 2;
public float beamDelay, grenadeDelay, lightningDelay,
cleanupDelay, deathDelay;
public GameObject shield, beamLaser;
public GunnerProjectile projectile;
public Grenade grenade;
public GameObject lightning;
public Damageable damageable;
29
ЧДТУ 211962.005ПЗ
public float lightningTime = 1;
public Transform grenadeSpawnPoint;
public Vector2 grenadeLaunchVelocity;
[Space]
public BossRound[] rounds;
[Space]
public GameObject[] disableOnDeath;
public UnityEvent onDefeated;
[Header("Audio")]
public AudioClip bossDeathClip;
public AudioClip playerDeathClip;
public AudioClip postBossClip;
public AudioClip bossMusic;
[Space]
public RandomAudioPlayer stepAudioPlayer;
public RandomAudioPlayer laserFireAudioPlayer;
public RandomAudioPlayer grenadeThrowAudioPlayer;
public RandomAudioPlayer lightingAttackAudioPlayer;
public RandomAudioPlayer takingDamage;
public RandomAudioPlayer shieldUpAudioPlayer;
public RandomAudioPlayer shieldDownAudioPlayer;
[Space]
public AudioSource roundDeathSource;
public AudioClip startRound2Clip;
public AudioClip startRound3Clip;
public AudioClip deathClip;
[Header("UI")]
public Slider healthSlider;
public Slider shieldSlider;
30
ЧДТУ 211962.005ПЗ
bool onFloor = false;
int round = 0;
private int m_TotalHealth = 0;
private int m_CurrentHealth = 0;
//used to track target movement, to correct for it.
private Vector2 m_PreviousTargetPosition;
public void SetEllenFloor(bool onFloor)
{
this.onFloor = onFloor;
}
Animator animator;
Root ai;
Vector3 originShieldScale;
void OnEnable()
{
if (PlayerCharacter.PlayerInstance != null)
{
PlayerCharacter.PlayerInstance.damageable.OnDie.AddListener(Play
erDied);
}
originShieldScale = shield.transform.localScale;
animator = GetComponent<Animator>();
round = 0;
31
ЧДТУ 211962.005ПЗ
ai = BT.Root();
ai.OpenBranch(
//First Round
BT.SetActive(beamLaser, false),
BT.Repeat(rounds.Length).OpenBranch(
BT.Call(NextRound),
//grenade enabled is true only on 2 and 3 round,
so allow to just test if it's the 1st round or not here
BT.If(GrenadeEnabled).OpenBranch(
BT.Trigger(animator, "Enabled")
),
BT.Wait(delay),
BT.Call(ActivateShield),
BT.Wait(delay),
BT.While(ShieldIsUp).OpenBranch(
BT.RandomSequence(new int[] { 1, 6, 4,
4 }).OpenBranch(
BT.Root().OpenBranch(
BT.Trigger(animator, "Walk"),
BT.Wait(0.2f),
BT.WaitForAnimatorState(animator,
"Idle")
),
BT.Repeat(laserStrikeCount).OpenBranch(
BT.SetActive(beamLaser, true),
BT.Trigger(animator, "Beam"),
BT.Wait(beamDelay),
BT.Call(FireLaser),
BT.WaitForAnimatorState(animator,
"Idle"),
BT.SetActive(beamLaser, false),
BT.Wait(delay)
32
ЧДТУ 211962.005ПЗ
),
BT.If(EllenOnFloor).OpenBranch(
BT.Trigger(animator, "Lightning"),
BT.Wait(lightningDelay),
BT.Call(ActivateLightning),
BT.Wait(lightningTime),
BT.Call(DeactivateLighting),
BT.Wait(delay)
),
BT.If(GrenadeEnabled).OpenBranch(
BT.Trigger(animator, "Grenade"),
BT.Wait(grenadeDelay),
BT.Call(ThrowGrenade),
BT.WaitForAnimatorState(animator,
"Idle")
)
)
),
BT.SetActive(beamLaser, false),
BT.Trigger(animator, "Grenade", false),
BT.Trigger(animator, "Beam", false),
BT.Trigger(animator, "Lightning", false),
BT.Trigger(animator, "Disabled"),
BT.While(IsAlive).OpenBranch(BT.Wait(0))
),
BT.Trigger(animator, "Death"),
BT.SetActive(damageable.gameObject, false),
BT.Wait(cleanupDelay),
BT.Call(Cleanup),
BT.Wait(deathDelay),
BT.Call(Die),
BT.Terminate()
33
ЧДТУ 211962.005ПЗ
);
BackgroundMusicPlayer.Instance.ChangeMusic(bossMusic);
BackgroundMusicPlayer.Instance.Play();
BackgroundMusicPlayer.Instance.Unmute(2.0f);
//we aggregate the total health to set the slider to the
proper value
//(as the boss is actually "killed" every round and
regenerated, we can't use directly its current health)
for(int i = 0; i < rounds.Length; ++i)
{
m_TotalHealth += rounds[i].bossHP;
}
m_CurrentHealth = m_TotalHealth;
healthSlider.maxValue = m_TotalHealth;
healthSlider.value = m_TotalHealth;
if (target != null)
m_PreviousTargetPosition =
target.transform.position;
}
private void OnDisable()
{
if (PlayerCharacter.PlayerInstance != null)
{
PlayerCharacter.PlayerInstance.damageable.OnDie.RemoveListener(P
layerDied);
}
}
34
ЧДТУ 211962.005ПЗ
void PlayerDied(Damager d, Damageable da)
{
BackgroundMusicPlayer.Instance.PushClip(playerDeathClip);
}
void ActivateShield()
{
shieldUpAudioPlayer.PlayRandomSound();
shield.SetActive(true);
shield.transform.localScale = Vector3.one * 0.01f;
shieldSlider.GetComponent<Animator>().Play("BossShieldActivate")
;
Damageable shieldDamageable =
shield.GetComponent<Damageable>();
//need to be set after enabled happen, otherwise enable
reset health. That why we use round - 1, round was already
advance at that point
shieldDamageable.SetHealth(rounds[round - 1].shieldHP);
shieldSlider.maxValue = rounds[round - 1].shieldHP;
shieldSlider.value = shieldSlider.maxValue;
}
void FireLaser()
{
laserFireAudioPlayer.PlayRandomSound();
var p = Instantiate(projectile);
35
ЧДТУ 211962.005ПЗ
var dir = -beamLaser.transform.right;
p.transform.position = beamLaser.transform.position;
p.initialForce = new Vector3(dir.x, dir.y) * 1000;
}
void ThrowGrenade()
{
grenadeThrowAudioPlayer.PlayRandomSound();
var p = Instantiate(grenade);
p.transform.position = grenadeSpawnPoint.position;
p.initialForce = grenadeLaunchVelocity;
}
bool GrenadeEnabled()
{
return round > 1;
}
void ActivateLightning()
{
lightingAttackAudioPlayer.PlayRandomSound();
var p = Instantiate(lightning) as GameObject;
p.transform.position = transform.position;
Destroy(p, lightningTime);
}
void DeactivateLighting()
{
lightingAttackAudioPlayer.Stop();
}
36
ЧДТУ 211962.005ПЗ
private void FixedUpdate()
{
if (target != null)
{
m_PreviousTargetPosition = target.position;
}
}
void Update()
{
ai.Tick();
if (beamLaser != null && target != null)
{
Vector2 targetMovement = (Vector2)target.position -
m_PreviousTargetPosition;
targetMovement.Normalize();
Vector3 targetPos = target.position + Vector3.up *
(1.0f + targetMovement.y * 0.5f);
beamLaser.transform.rotation =
Quaternion.RotateTowards(beamLaser.transform.rotation,
Quaternion.Euler(0, 0, Vector3.SignedAngle(Vector3.left,
targetPos - beamLaser.transform.position, Vector3.forward)),
laserTrackingSpeed * Time.deltaTime);
}
shield.transform.localScale =
Vector3.Lerp(shield.transform.localScale, originShieldScale,
Time.deltaTime);
}
void Cleanup()
{
37
ЧДТУ 211962.005ПЗ
shieldSlider.GetComponent<Animator>().Play("BossShieldDefeat");
healthSlider.GetComponent<Animator>().Play("BossHealthDefeat");
BackgroundMusicPlayer.Instance.ChangeMusic(postBossClip);
BackgroundMusicPlayer.Instance.PushClip(bossDeathClip);
roundDeathSource.clip = deathClip;
roundDeathSource.loop = false;
roundDeathSource.Play();
foreach (var g in disableOnDeath)
g.SetActive(false);
shield.SetActive(false);
beamLaser.SetActive(false);
}
void Die()
{
onDefeated.Invoke();
}
bool EllenOnPlatform()
{
return !onFloor;
}
bool EllenOnFloor()
{
return onFloor;
}
38
ЧДТУ 211962.005ПЗ
bool IsAlive()
{
var alive = damageable.CurrentHealth > 0;
return alive;
}
bool IsNotAlmostDead()
{
var alive = damageable.CurrentHealth > 1;
return alive;
}
bool ShieldIsUp()
{
return shield.GetComponent<Damageable>().CurrentHealth >
0;
}
void NextRound()
{
damageable.SetHealth(rounds[round].bossHP);
damageable.EnableInvulnerability(true);
foreach (var p in rounds[round].platforms)
{
p.gameObject.SetActive(true);
p.speed = rounds[round].platformSpeed;
}
foreach (var g in rounds[round].enableOnProgress)
{
g.SetActive(true);
}
39
ЧДТУ 211962.005ПЗ
round++;
if (round == 2)
{
roundDeathSource.clip = startRound2Clip;
roundDeathSource.loop = true;
roundDeathSource.Play();
}
else if (round == 3)
{
roundDeathSource.clip = startRound3Clip;
roundDeathSource.loop = true;
roundDeathSource.Play();
}
}
void Disabled()
{
}
void Enabled()
{
}
public void Damaged(Damager damager, Damageable damageable)
{
takingDamage.PlayRandomSound();
m_CurrentHealth -= damager.damage;
healthSlider.value = m_CurrentHealth;
40
ЧДТУ 211962.005ПЗ
}
public void ShieldDown()
{
shieldDownAudioPlayer.PlayRandomSound();
damageable.DisableInvulnerability();
}
public void ShieldHit()
{
shieldSlider.value =
shield.GetComponent<Damageable>().CurrentHealth;
}
public void PlayStep()
{
stepAudioPlayer.PlayRandomSound();
}
#if UNITY_EDITOR
public BTAI.Root GetAIRoot()
{
return ai;
}
#endif
}
3.5. Тестування ігрових механік
В процесі розробки проводилося тестування механік які додавалися до
гри, наприклад: стрибок.
41
ЧДТУ 211962.005ПЗ
В процесі тестування було виявлено декілька багів таких, як
застрягання в текстурах або зависання у повітрі після стрибка, в ході
розробки ці баги були виправлені.
Результати тестування можна переглянути у додатку Г.
Висновок до третього розділу
Таким чином було розроблено основний інтерфейс додатку, розроблені
спроектовані раніше сцени, а також додано декілька ігрових механік, які не
планувалося робити.
Було розроблено ігрового персонажа, а також ворогів, створено
анімації для них, а також damage model.
Протестовано систему на наявність помилок, знайдені помилки було
виправлено.
42
ЧДТУ 211962.005ПЗ
ВИСНОВКИ
В процесі розробки даного проекту було створено гру, в якій потрібно
грати за головного героя, що переміщується між планетами в пошуках
підходящої для існування людей.
Використано сучасні технології розробки ігор, за допомогою
допоміжних систем було спрощено розробку сцен.
Всі сцени було створено за допомогою тайлів, це прискорило та
спростило розробку, а також дозволило оптимізувати систему.
На даний момент була реалізована лише одна із локацій, але в
майбутньому можна буде легко розширити ігровий світ методом створення
заготовлених схем для сцен.
Під час виконання курсової роботи було вдосконалено навички роботи
в Unity та з мовою програмування C#.
43
ЧДТУ 211962.005ПЗ
СПИСОК ЛІТЕРАТУРИ
1. Hollow Knight [Електронний ресурс]. – Режим доступу:
https://uk.wikipedia.org/wiki/Hollow_Knight
2. Ori and the Blind Forest [Електронний ресурс]. –
https://uk.wikipedia.org/wiki/Ori_and_the_Blind_Forest
3. Salt and Sanctuary [Електронний ресурс]. –
https://ru.wikipedia.org/wiki/Salt_and_Sanctuary
4. Unity [Електронний ресурс]. –
https://uk.wikipedia.org/wiki/Unity_(рушій_гри)
5. How to write technical task - Encomage [Електронний ресурс]. - Режим
доступу: https://encomage.com/2020/04/27/how-to-write-technical-task/
6. Jesper Juul half-real video games between real rules and fictional
worlds [Електронний ресурс]. – https://mitpress.mit.edu/books/half-
real#:~:text=A%20video%20game%20is%20half,and%20fiction%20in%20
video%20games.
7. Creating Tiles [Електронний ресурс]. –
https://docs.unity3d.com/Manual/Tilemap-CreatingTiles.html
8. Unity Sprites [Електронний ресурс]. –
https://docs.unity3d.com/Manual/Sprites.html
9. Unity Animation [Електронний ресурс]. –
https://docs.unity3d.com/ScriptReference/Animation.html#:~:text=You%20
can%20assign%20animation%20clips,over%20all%20aspects%20of%20pla
yback.
10. Unity Damage System [Електронний ресурс]. –
https://forum.unity.com/threads/hit-and-damage-system-with-
interfaces.328456/
11. Unity rigidbody2d [Електронний ресурс]. –
https://docs.unity3d.com/ru/2019.4/ScriptReference/Rigidbody2D.html
44
ЧДТУ 211962.005ПЗ
Додаток А
Розробка рольової гри «Lost Space»
Специфікація
Листів 2
Розробник: ________________________ Завгородній В.І.
Керівник: ________________________ Метелап В.В.
Черкаси 2022
45
ЧДТУ 211962.005ПЗ
Позначення Найменування Примітки
Додаток Б. Код програми
Додаток В. Інструкція
користувачеві
Додаток Г. Презентація
46
ЧДТУ 211962.005ПЗ
47
ЧДТУ 211962.005ПЗ
Додаток Б
Розробка рольової гри «Lost Space»
Код програми
Листів 13
Розробник: ________________________ Завгородній В.І.
Керівник: ________________________ Метелап В.В.
Черкаси 2022
48
ЧДТУ 211962.005ПЗ
CharacterStateSetterEditor
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
namespace Gamekit2D
{
[CustomEditor(typeof(CharacterStateSetter))]
public class CharacterStateSetterEditor : Editor
{
SerializedProperty m_AnimatorProp;
SerializedProperty m_SetCharacterVelocityProp;
SerializedProperty m_PlayerCharacterProp;
SerializedProperty m_CharacterVelocityProp;
SerializedProperty m_SetCharacterFacingProp;
SerializedProperty m_FaceLeftProp;
SerializedProperty m_SetStateProp;
SerializedProperty m_AnimatorStateNameProp;
SerializedProperty m_SetParametersProp;
SerializedProperty m_ParameterSettersProp;
GUIContent m_AnimatorContent;
GUIContent m_SetCharacterVelocityContent;
GUIContent m_PlayerCharacterContent;
GUIContent m_CharacterVelocityContent;
GUIContent m_SetCharacterFacingContent;
GUIContent m_FaceLeftContent;
GUIContent m_SetStateContent;
GUIContent m_AnimatorStateNameContent;
GUIContent m_SetParametersContent;
GUIContent m_ParameterSettersContent;
GUIContent m_ParameterSetterNameContent;
GUIContent m_ParameterSetterValueContent;
string[] m_AnimatorStateNames;
int m_StateNamesIndex;
string[] m_ParameterNames;
CharacterStateSetter.ParameterSetter.ParameterType[]
m_ParameterTypes;
49
ЧДТУ 211962.005ПЗ
int m_ParameterNameIndex;
void OnEnable ()
{
m_AnimatorProp =
serializedObject.FindProperty("animator");
m_SetCharacterVelocityProp =
serializedObject.FindProperty ("setCharacterVelocity");
m_PlayerCharacterProp =
serializedObject.FindProperty("playerCharacter");
m_CharacterVelocityProp =
serializedObject.FindProperty ("characterVelocity");
m_SetCharacterFacingProp =
serializedObject.FindProperty ("setCharacterFacing");
m_FaceLeftProp = serializedObject.FindProperty
("faceLeft");
m_SetStateProp = serializedObject.FindProperty
("setState");
m_AnimatorStateNameProp =
serializedObject.FindProperty ("animatorStateName");
m_SetParametersProp =
serializedObject.FindProperty ("setParameters");
m_ParameterSettersProp =
serializedObject.FindProperty ("parameterSetters");
m_AnimatorContent = new GUIContent("Animator");
m_SetCharacterVelocityContent = new
GUIContent("Set Character Velocity");
m_PlayerCharacterContent = new
GUIContent("Player Character");
m_CharacterVelocityContent = new
GUIContent("Character Velocity");
m_SetCharacterFacingContent = new
GUIContent("Set Character Facing Content");
m_FaceLeftContent = new GUIContent("Face
Left");
m_SetStateContent = new GUIContent("Set
State");
m_AnimatorStateNameContent = new
GUIContent("Animator State Name");
m_SetParametersContent = new GUIContent("Set
Parameters");
m_ParameterSettersContent = new
GUIContent("Parameter Settings");
50
ЧДТУ 211962.005ПЗ
m_ParameterSetterNameContent = new
GUIContent("Name");
m_ParameterSetterValueContent = new
GUIContent("Value");
SetAnimatorStateNames ();
if (m_AnimatorStateNames != null)
{
for (int i = 0; i <
m_AnimatorStateNames.Length; i++)
{
if (m_AnimatorStateNames[i] ==
m_AnimatorStateNameProp.stringValue)
{
m_StateNamesIndex = i;
}
}
}
}
public override void OnInspectorGUI ()
{
serializedObject.Update ();
EditorGUILayout.PropertyField(m_SetCharacterVelocityProp,
m_SetCharacterVelocityContent);
if (m_SetCharacterVelocityProp.boolValue)
{
EditorGUILayout.PropertyField(m_PlayerCharacterProp,
m_PlayerCharacterContent);
EditorGUILayout.PropertyField(m_CharacterVelocityProp,
m_CharacterVelocityContent);
}
EditorGUILayout.PropertyField
(m_SetCharacterFacingProp, m_SetCharacterFacingContent);
if (m_SetCharacterFacingProp.boolValue)
{
EditorGUILayout.PropertyField(m_PlayerCharacterProp,
m_PlayerCharacterContent);
EditorGUILayout.PropertyField(m_FaceLeftProp,
m_FaceLeftContent);
}
EditorGUILayout.PropertyField(m_SetStateProp,
m_SetStateContent);
51
ЧДТУ 211962.005ПЗ
if (m_SetStateProp.boolValue)
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_AnimatorProp,
m_AnimatorContent);
if (EditorGUI.EndChangeCheck())
{
SetAnimatorStateNames();
}
if (m_AnimatorProp.objectReferenceValue ==
null ||
((Animator)m_AnimatorProp.objectReferenceValue).runtimeAnim
atorController == null)
{
EditorGUILayout.HelpBox("An animator
controller has not been found and so state names cannot be
chosen.", MessageType.Warning);
m_AnimatorStateNameProp.stringValue =
"";
}
else
{
EditorGUI.BeginChangeCheck();
m_StateNamesIndex =
EditorGUILayout.Popup(m_AnimatorStateNameContent.text,
m_StateNamesIndex, m_AnimatorStateNames);
if (EditorGUI.EndChangeCheck())
{
m_AnimatorStateNameProp.stringValue
= m_AnimatorStateNames[m_StateNamesIndex];
}
}
}
EditorGUILayout.PropertyField
(m_SetParametersProp, m_SetParametersContent);
if (m_SetParametersProp.boolValue)
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_AnimatorProp,
m_AnimatorContent);
if (EditorGUI.EndChangeCheck())
{
SetAnimatorStateNames();
}
if (m_AnimatorProp.objectReferenceValue ==
null ||
52
ЧДТУ 211962.005ПЗ
((Animator)m_AnimatorProp.objectReferenceValue).runtimeAnim
atorController == null)
{
EditorGUILayout.HelpBox("An animator
controller has not been found and so state names cannot be
chosen.", MessageType.Warning);
m_ParameterSettersProp.arraySize = 0;
}
else
{
m_ParameterSettersProp.arraySize =
EditorGUILayout.IntField(m_ParameterSettersContent,
m_ParameterSettersProp.arraySize);
EditorGUI.indentLevel++;
for (int i = 0; i <
m_ParameterSettersProp.arraySize; i++)
{
SerializedProperty elementProp =
m_ParameterSettersProp.GetArrayElementAtIndex(i);
ParameterSetterGUI(elementProp);
}
EditorGUI.indentLevel--;
}
}
serializedObject.ApplyModifiedProperties ();
}
void SetAnimatorStateNames ()
{
if (m_AnimatorProp.objectReferenceValue ==
null)
{
m_AnimatorStateNames = null;
m_ParameterNames = null;
m_ParameterTypes = null;
return;
}
Animator animator =
m_AnimatorProp.objectReferenceValue as Animator;
if (animator.runtimeAnimatorController == null)
{
m_AnimatorStateNames = null;
m_ParameterNames = null;
m_ParameterTypes = null;
return;
}
AnimatorController animatorController =
animator.runtimeAnimatorController as AnimatorController;
53
ЧДТУ 211962.005ПЗ
AnimatorControllerParameter[] parameters =
animatorController.parameters;
m_ParameterNames = new
string[parameters.Length];
m_ParameterTypes = new
CharacterStateSetter.ParameterSetter.ParameterType[paramete
rs.Length];
for (int i = 0; i < m_ParameterNames.Length;
i++)
{
m_ParameterNames[i] = parameters[i].name;
switch (parameters[i].type)
{
case
AnimatorControllerParameterType.Float:
m_ParameterTypes[i] =
CharacterStateSetter.ParameterSetter.ParameterType.Float;
break;
case
AnimatorControllerParameterType.Int:
m_ParameterTypes[i] =
CharacterStateSetter.ParameterSetter.ParameterType.Int;
break;
case
AnimatorControllerParameterType.Bool:
m_ParameterTypes[i] =
CharacterStateSetter.ParameterSetter.ParameterType.Bool;
break;
case
AnimatorControllerParameterType.Trigger:
m_ParameterTypes[i] =
CharacterStateSetter.ParameterSetter.ParameterType.Trigger;
break;
default:
throw new
ArgumentOutOfRangeException();
}
}
List<string> stateNamesList = new List<string>
();
for (int i = 0; i <
animatorController.layers.Length; i++)
{
for (int j = 0; j <
animatorController.layers[i].stateMachine.states.Length;
j++)
54
ЧДТУ 211962.005ПЗ
{
stateNamesList.Add(animatorController.layers[i].stateMachin
e.states[j].state.name);
}
GetStateMachinesFromStateMachineAndAddNames(stateNamesList,
animatorController.layers[i].stateMachine);
}
m_AnimatorStateNames = stateNamesList.ToArray
();
}
static void
GetStateMachinesFromStateMachineAndAddNames (List<string>
stateNamesList, AnimatorStateMachine stateMachine)
{
AnimatorStateMachine[] stateMachines = new
AnimatorStateMachine[stateMachine.stateMachines.Length];
for (int i = 0; i < stateMachines.Length; i++)
{
stateMachines[i] =
stateMachine.stateMachines[i].stateMachine;
for (int j = 0; j <
stateMachines[i].states.Length; j++)
{
stateNamesList.Add(stateMachines[i].states[j].state.name);
}
GetStateMachinesFromStateMachineAndAddNames(stateNamesList,
stateMachines[i]);
}
}
void ParameterSetterGUI (SerializedProperty
parameterSetterProp)
{
SerializedProperty parameterNameProp =
parameterSetterProp.FindPropertyRelative("parameterName");
SerializedProperty parameterTypeProp =
parameterSetterProp.FindPropertyRelative("parameterType");
SerializedProperty boolValueProp =
parameterSetterProp.FindPropertyRelative("boolValue");
SerializedProperty floatValueProp =
parameterSetterProp.FindPropertyRelative("floatValue");
55
ЧДТУ 211962.005ПЗ
SerializedProperty intValueProp =
parameterSetterProp.FindPropertyRelative("intValue");
for (int i = 0; i < m_ParameterNames.Length;
i++)
{
if (m_ParameterNames[i] ==
parameterNameProp.stringValue)
{
m_ParameterNameIndex = i;
parameterTypeProp.enumValueIndex =
(int)m_ParameterTypes[i];
}
}
Rect position = EditorGUILayout.GetControlRect
(false, EditorGUIUtility.singleLineHeight);
Rect nameLabelRect = new Rect(position.x,
position.y, position.width * 0.2f,
EditorGUIUtility.singleLineHeight);
Rect nameControlRect = new Rect(nameLabelRect.x
+ nameLabelRect.width, position.y, position.width * 0.3f,
position.height);
Rect valueLabelRect = new
Rect(nameControlRect.x + nameControlRect.width, position.y,
position.width * 0.2f, position.height);
Rect valueControlRect = new
Rect(valueLabelRect.x + valueLabelRect.width, position.y,
position.width * 0.3f, position.height);
EditorGUI.LabelField(nameLabelRect,
m_ParameterSetterNameContent);
m_ParameterNameIndex =
EditorGUI.Popup(nameControlRect, GUIContent.none.text,
m_ParameterNameIndex, m_ParameterNames);
parameterNameProp.stringValue =
m_ParameterNames[m_ParameterNameIndex];
parameterTypeProp.enumValueIndex =
(int)m_ParameterTypes[m_ParameterNameIndex];
switch
((CharacterStateSetter.ParameterSetter.ParameterType)parame
terTypeProp.enumValueIndex)
{
case
CharacterStateSetter.ParameterSetter.ParameterType.Bool:
EditorGUI.LabelField(valueLabelRect,
m_ParameterSetterValueContent);
EditorGUI.PropertyField(valueControlRect, boolValueProp,
GUIContent.none);
break;
56
ЧДТУ 211962.005ПЗ
case
CharacterStateSetter.ParameterSetter.ParameterType.Float:
EditorGUI.LabelField(valueLabelRect,
m_ParameterSetterValueContent);
EditorGUI.PropertyField(valueControlRect, floatValueProp,
GUIContent.none);
break;
case
CharacterStateSetter.ParameterSetter.ParameterType.Int:
EditorGUI.LabelField(valueLabelRect,
m_ParameterSetterValueContent);
EditorGUI.PropertyField(valueControlRect, intValueProp,
GUIContent.none);
break;
}
}
}
}
Checkpoint
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Gamekit2D
{
[RequireComponent(typeof(BoxCollider2D))]
public class Checkpoint : MonoBehaviour
{
public bool respawnFacingLeft;
private void Reset()
{
GetComponent<BoxCollider2D>().isTrigger = true;
}
private void OnTriggerEnter2D(Collider2D collision)
{
PlayerCharacter c =
collision.GetComponent<PlayerCharacter>();
if(c != null)
{
c.SetChekpoint(this);
}
}
}
}
SavedData
using System.Collections.Generic;
using UnityEngine;
57
ЧДТУ 211962.005ПЗ
namespace Gamekit2D
{
public class SavedData : MonoBehaviour
{
public static SavedData Instance
{
get
{
if (instance != null)
return instance;
instance = FindObjectOfType<SavedData>();
if (instance != null)
return instance;
GameObject spawnManagerGameObject = new
GameObject("SpawnManager");
instance =
spawnManagerGameObject.AddComponent<SavedData>();
return instance;
}
}
protected static SavedData instance;
protected Dictionary<string, string>
m_StringSavedData;
protected Dictionary<string, bool> m_BoolSavedData;
protected Dictionary<string, int> m_IntSavedData;
protected Dictionary<string, float>
m_FloatSavedData;
protected Dictionary<string, Vector2>
m_Vector2SavedData;
void Start()
{
if (Instance != null)
{
Destroy(gameObject);
}
else
{
DontDestroyOnLoad(gameObject);
}
}
public static string Get (string key, out string
value)
{
58
ЧДТУ 211962.005ПЗ
if (Instance.m_StringSavedData.TryGetValue(key,
out value))
return value;
throw new UnityException("No string data was
found with the key - " + key);
}
public static bool Get (string key, out bool value)
{
if (Instance.m_BoolSavedData.TryGetValue (key,
out value))
return value;
throw new UnityException("No bool data was
found with the key - " + key);
}
public static int Get(string key, out int value)
{
if (Instance.m_IntSavedData.TryGetValue(key,
out value))
return value;
throw new UnityException("No int data was found
with the key - " + key);
}
public static float Get(string key, out float
value)
{
if (Instance.m_FloatSavedData.TryGetValue(key,
out value))
return value;
throw new UnityException("No float data was
found with the key - " + key);
}
public static Vector2 Get(string key, out Vector2
value)
{
if (Instance.m_Vector2SavedData.TryGetValue(key,
out value))
return value;
throw new UnityException("No Vector2 data was
found with the key - " + key);
}
public static void Set (string key, string value)
{
if
(Instance.m_StringSavedData.ContainsKey(key))
Instance.m_StringSavedData[key] = value;
else
Instance.m_StringSavedData.Add(key, value);
59
ЧДТУ 211962.005ПЗ
}
public static void Set(string key, bool value)
{
if (Instance.m_BoolSavedData.ContainsKey(key))
Instance.m_BoolSavedData[key] = value;
else
Instance.m_BoolSavedData.Add(key, value);
}
public static void Set(string key, int value)
{
if (Instance.m_IntSavedData.ContainsKey(key))
Instance.m_IntSavedData[key] = value;
else
Instance.m_IntSavedData.Add(key, value);
}
public static void Set(string key, float value)
{
if (Instance.m_FloatSavedData.ContainsKey(key))
Instance.m_FloatSavedData[key] = value;
else
Instance.m_FloatSavedData.Add(key, value);
}
public static void Set(string key, Vector2 value)
{
if
(Instance.m_Vector2SavedData.ContainsKey(key))
Instance.m_Vector2SavedData[key] = value;
else
Instance.m_Vector2SavedData.Add(key,
value);
}
}
}
60
ЧДТУ 211962.005ПЗ
Додаток В
Розробка рольової гри «Lost Space»
Інструкція користувачеві
Листів 2
Розробник: ________________________ Завгородній В.І.
Керівник: ________________________ Метелап В.В.
Черкаси 2022
61
ЧДТУ 211962.005ПЗ
Для того щоб почати гру потрібно запустити додаток через
виконуваний файл .exe, після чого дочекатися завантаження гри.
Після завантаження можна обрати один із пунктів: Старт,
Налаштування, Вихід.
Обравши пункт вихід гра закриється.
Обравши пункт налаштування можна подивитися управління
персонажем, або налаштувати гучність звуку.
Обравши пункти старт розпочинається завантаження гри, після
завантаження гри можна управляти персонажем.
Для переміщення використовуються кнопки A, S, D, SPACE.
Для атаки використовуються кнопки K, O.
62
ЧДТУ 211962.005ПЗ
Додаток Г
Розробка рольової гри «Lost Space»
Графічні матеріали
Листів 3
Розробник: ________________________ Завгородній В.І.
Керівник: ________________________ Метелап В.В.
Черкаси 2022
63
ЧДТУ 211962.005ПЗ
Рисунок Г.1 Слайд «Сфери використання»
Рисунок Г.2 Слайд «Аналоги програмного забезпечення»
64
ЧДТУ 211962.005ПЗ
Рисунок Г.3 Слайд «Аналоги програмного забезпечення»
Рисунок Г.4 Слайд «Аналоги програмного забезпечення»
65
ЧДТУ 211962.005ПЗ
Рисунок Г.5 Слайд «Структура програмного забезпечення»
Рисунок Г.6 Слайд «Постановка задачі»
66
ЧДТУ 211962.005ПЗ
Рисунок Г.7 Слайд «Вибір програмних засобів»
Рисунок Г.8 Слайд «Огляд системи, Головне меню»
67
ЧДТУ 211962.005ПЗ
Рисунок Г.9 Слайд «Огляд системи, Налаштування»
Рисунок Г.10 Слайд «Огляд системи, Сама гра»
68