You are on page 1of 74

ЗАТВЕРДЖЕНО

Наказ Міністерства освіти і науки, молоді


та спорту України
29.03.2012 N 384

Форма N Н-6.01

Міністерство освіти і науки України


Вінницький національний технічний університет
Кафедра програмного забезпечення

КУРСОВА РОБОТА
з дисципліни ” Об’єктно-орієнтоване програмування ”
на тему: РОЗРОБКА ПРОГРАМНОЇ СИСТЕМИ ДЛЯ МОДЕЛЮВАННЯ
ОБ’ЄКТІВ ” Світ гри The Crusader Stronghold; Перша фортеця, Друга фортеця;
списоносець, лучник, лицар-тамплієр ”
З ВИКОРИСТАННЯМ UML ТА МОВИ ПРОГРАМУВАННЯ JAVA

Студента (ки) __1___ курсу _ групи 2ПІ-20б


спеціальності 121 Інженерія програмного
забезпечення” Захарчука М.

Керівник: доцент кафедри ПЗ, к.т.н., Д.І. Катєльніков


Національна шкала _____________________________
Кількість балів: ________ Оцінка: ECTS ________
Члени комісії ______________
(підпис) (прізвище та ініціали)
______________ ___________________________
(підпис) (прізвище та ініціали)

м. Вінниця - 2021 рік


Міністерство освіти і науки України
Вінницький національний технічний університет
Факультет інформаційних технологій та комп’ютерної інженерії

ЗАТВЕРДЖУЮ
Зав. кафедри ПЗ, проф., д.т.н.

______________ О.Н. Романюк


(підпис)

Затверджено на засіданні каф. ПЗ протокол №_14 від ”29” січня 2021 р.

ІНДИВІДУАЛЬНЕ ЗАВДАННЯ
на курсову роботу з дисципліни ”Об'єктно-орієнтоване програмування”
студенту групи 2ПІ-20б Захарчуку М.
РОЗРОБКА ПРОГРАМНОЇ СИСТЕМИ ДЛЯ МОДЕЛЮВАННЯ ОБ’ЄКТІВ ” Світ гри The Crusader
Stronghold; Перша фортеця, Друга фортеця; списоносець, лучник, лицар-тамплієр ” З ВИКОРИСТАННЯМ UML
ТА МОВИ ПРОГРАМУВАННЯ JAVA
Вихідні дані:
- Середовища розробки NetBeans IDE, IntelliJ IDEA або Eclipse, платформа JavaFX.

Вимоги до курсової роботи:


В програмі повинно бути реалізовано: додаток Windows з графічним інтерфейсом. Клас мікрооб’єкта повинен містити не менше 4 елементів змінних і не менше 4 методів (окрім геттерів та сеттерів). Як мінімум одна
змінна повинна бути типу int, одна – типу double і як мінімум одна – рядок. Змінні-елементи класу мають бути приватними, для них повинні бути створені відповідні аксесори та мутатори (іншими словами – геттери та сетери. В класі
мікрооб’єкта повинен бути присутній конструктор без аргументів. Повинно бути використано делегування конструкторів. Повинно бути продемонстровано як мінімум один статичний блок ініціалізації і один нестатичний. Реалізація
функцій boolean equals(Object o) та String toString(). Додати до класу мікрооб’єкта в якості елемента посилальний тип, щоб зробити необхідним глибинне копіювання. Реалізовано глибинне копіювання шляхом реалізації інтерфейсу
Cloneable. Повинне бути продемонстроване використання глибинного копіювання. Продемонструвати використання як мінімум двох функцій-статичних елементів класу java.util.Arrays (можливо для цього потрібно буде створити
тимчасовий об’єкт-масив з колекції, яка використовується). Продемонструвати використання інтерфейсу Сomparable або Comparer. Повинні бути продемонстровано використання віртуальних функцій. Повинні бути
продемонстровано типу доступу protected. Повинно бути продемонстровано використання динамічного поліморфізму. Повинно бути продемонстровано використання статичного поліморфізму. Продемонстровано використання
ключового слова instanceof. Мікрооб'єкт: мінімум три графічних примітива (один з яких - текст) (навіть в неактивованому стані!). Білий (=невидимий) графічний примітив НЕ рахується! Універсальний об'єкт: мінімум три графічних
примітива (один з яких - текст). Білий (=невидимий) графічний примітив НЕ рахується! Макрооб'єкт: мінімум три графічних примітива(один з яких - текст). Білий (=невидимий) графічний примітив НЕ рахується! При натискуванні
лівої кнопки миші на мікрооб’єкті він повинен ставати активним/неактивним. В програмі повинна бути реалізована активація декількох об’єктів одночасно. Зображення активного мікрооб’єкта повинно відрізнятись від зображення
неактивного хоча б одним графічним примітивом. Інтерфейс програми повинен сигналізувати про те, який саме мікрооб’єкт активував користувач. По вибору студента інформація про активований мікрооб’єкт/мікрооб’єкти може
виводитись у рядку статуса або робочій області програми. Якщо користувач активував декілька мікрооб’єктів, то інформація про це також має якимось чином відображатися. При натискувань клавіш-стрілок активні об’єкти/об’єкт
повинні рухатись у вікні програми. При натискувань клавіши Delete активні об’єкти повинні знищуватись. Якщо активного об’єкта нема – клавіша Delete ігнорується. Реалізувати в проекті: Клавіша Esc повинна відміняти активацію
обєкта. Повина бути побудована ієрархія класів мікрооб'єктів, яка містить як мінімум три рівня наслідування, які можуть інстанціонуватись і зображатись на екрані. Зображення кожного рівня має відрізнятись від всіх інших хоча б
одним графічним примітивом. В побудованій ієрархії класів повинні бути продемонстровані: - виклик конструктора базового класу; - виклик метода базового класу. При натискуванні клавіши Insert повинно з’являтись діалогове
вікно, яке повинно визначати параметри створюваного мікрооб’єкта. В нього повинна бути присутня можливість обирати до якого з класів нащадків у ієрархії наслідування він належить. Крім керуючого елемента Button у діалоговому
вікні також повинні бути використані як мінімум три з наступного списку: TextField, CheckBox, {ComboBox|ListView|ChoiceBox}, RadioButton. Додати у проект клас/класи універсального об’єкта. Універсальний об’єкт призначений
містити всі мікрооб’єкти та всі макрооб’єкти. У вікні програми відображається лише певна частина універсального об’єкта, яка не повинна перевищувати 25% його загального розміру. Мінімальний розмір універсального об’єкта
1600 позицій для мікрооб’єкта (тобто на екрані одночасно можна побачити не більше квадрата 20*20 позицій для мікрооб’єкта). Реалізувати можливість змінювати частину універсального об’єкта, яку спостерігає користувач (будь
яким способом). Додати у проект клас/класи макрооб’єкта. Макрооб’єкт повинен мати можливість містити більше одного мікрооб’єкта. Не обов’язково мати можливості додавати/видаляти макрооб’єкти в програму. Цілком достатньо,
якщо програма буде мати деяку кількість макрооб’єктів (БІЛЬШЕ ОДНОГО!) згенеровану при запуску програми і яка буде незмінною протягом роботи програми. Макрооб’єкти повинні мати певні позиції в універсальному об’єкті і
повинні відображатись на екраині. Позиції макрооб’єктів в середині універсального об’єкта можуть залишатись незмінними протягом роботи програми. Мікрооб’єкти можуть або належати одному (або більшій кількості) макрооб’єкту,
або не належати жодному. Глядачу має бути зрозуміло в чому полягає приналежність мікрооб’єкта макрооб’єкту, тобто чим поведінка такого мікрооб’єкта відрізняється від поведінки мікрооб’єкта, який не належить жодному
макрооб’єкту. Повинна обов'язково бути реалізована можливість вилучити мікрооб'єкт з всіх макрооб'єктів, в результаті чого він не буде належати жодному макрооб'єкту. Також повинна бути реалізована можливість вручну завести
мікрооб’єкт у макрооб’єкт. Всі мікрооб'єкти та макроб'єкти повинні належати універсальному об'єкту і не повинні мати змоги вийти за його межі. Повинен бути реалізований автоматичний рух деяких мікрооб’єктів: 1) при русі деякі
мікрооб'єкти взаємодіють між собою (це має бути помітно візуально в тому сенсі, що або щось змінюється у їх зображенні або у характері їх руху). 2) деякі мікрооб'єкти заходять в макрооб'єкти та деякі виходять. 3) характер руху
мікрооб'єктів повинен змінюватись при натискуванні певної клавіші клавіатури або при виборі команди меню. Під характером руху мається на увазі не просто траєкторія, а те, в який спосіб вони взаємодіють з макрооб'єктами та
іншими мікрооб'єктами. Повинна бути реалізована мінікарта, яка дозволяє прискорену навігацію: 1) На мінікарті повинна бути позначена видима область універсального об’єкта. 2) Рух видимої області універсального об’єкта
відповідно змінює мінікарту. 3) Макрооб’єкти та мікрооб’єкти позначені на мінікарті. 4) Рух та взаємодія мікрооб’єктів призводить до відповідних змін на мінікарті. 5) Натискування лівої кнопки миші на мінікарті призводить до
переміщення видимої області універсального об’єкта. Повинна бути запрограмована серіалізація/де-серіалізація всіх об’єктів у текстовий/бінарний/XML файл. Серіалізація/де-серіалізація обов’язково повинна зберігати не тільки
власне інформацію про стан макро- та мікро-об’єктів, але й про їх позицію на екрані. При серіалізації/де-серіалізації обов’язково повинні використовуватись діалогові вікна, щоб запитати у користувача ім’я файлу та його розташування
на диску (наприклад можна використовувати системне діалогове вікно FileChooser). Продемонстровано використання ОДНІЄЇ параметризованої колекції.

Зміст ПЗ до курсової роботи


Індивідуальне завдання
АНОТАЦІЯ
ВСТУП
1 АНАЛІЗ СУЧАСНОГО СТАНУ ПИТАННЯ ТА ОБҐРУНТУВАННЯ ЗАВДАННЯ НА РОБОТУ
2 РОЗРОБКА ІНТЕРФЕЙСУ ПРОГРАМИ ТА ПРИКЛАДІВ ВИКОРИСТАННЯ
3 РОЗРОБКА ПІДСИСТЕМИ ГРАФІЧНОГО ВІДОБРАЖЕННЯ
4 РОЗРОБКА ДІАГРАМ КЛАСІВ, ОБ’ЄКТІВ ТА СТАНУ
5 РОЗРОБКА ПІДСИСТЕМИ СЕРІАЛІЗАЦІЇ/ДЕСЕРІАЛІЗАЦІЇ ДАНИХ
6 КЕРІВНИЦТВО КОРИСТУВАЧА
ВИСНОВКИ
ПЕРЕЛІК ПОСИЛАНЬ
Додатки (за необхідністю)
Дата видачі ”8” лютого 2021 р. Керівник
(підпис)
Завдання отримав Захарчук М.Д.
(підпис)
3

АНОТАЦІЯ

Дана курсова робота присвячена розробці програмної системи для


моделювання битви двох середньовічних королівств та їхніх військ – героїв гри The
Crusader Stronghold , з використанням UML та мови програмування Java та
об’єктно-орієнтованих принципів. Програмна система включає в себе роботу з
графікою, класами, обробку числової інформації і роботу з файлами. Під час
розробки програмної реалізації була створена оболонка поставленої задачі і
розроблено методи графічного моделювання поведінки героїв гри The Crusader
Stronghold. В результаті виконання курсової роботи отримано програмний продукт,
який реагує на команди користувача а також здатний самостійно реалізовувати
процеси анімації згідно критеріїв виконання.
4

ЗМІСТ

ВСТУП…………………………………………………………………...5

1 АНАЛІЗ СУЧАСНОГО СТАНУ ПИТАННЯ ТА ОБҐРУНТУВАННЯ


ЗАВДАННЯ НА РОБОТУ…………………………………………………..…..7

2 РОЗРОБКА ІНТЕРФЕЙСУ ПРОГРАМИ ТА ПРИКЛАДІВ


ВИКОРИСТАННЯ………………………………………………………………16

3 РОЗРОБКА ПІДСИСТЕМИ ГРАФІЧНОГО ВІДОБРАЖЕННЯ……21

4 РОЗРОБКА ДІАГРАМ КЛАСІВ, ОБ’ЄКТІВ ТА СТАНУ…………..24

5 РОЗРОБКА ПІДСИСТЕМИ СЕРІАЛІЗАЦІЇ/ДЕСЕРІАЛІЗАЦІЇ


ДАНИХ……………………………………………………………………….……30

6 КЕРІВНИЦТВО КОРИСТУВАЧА……………………..……………….32

ВИСНОВКИ…………….………………………………………………....36

ПЕРЕЛІК ПОСИЛАНЬ.……………………………………………..……37

ДОДАТОК А. ЛІСТИНГ ПРОГРАМИ…………..………………..…..…39


5

ВСТУП
Дослідження історичних періодів завжди цікавило істориків. Особливо
привертає увагу доба середньовіччя, яка завжди характеризувалася своєю
загадковістю, жорстокістю, бідністю, занепадом економіки та найчастіше
кровопролитними битвами та хрестовими походами. Думки та здогадки істориків
та дослідників цієї історичної епохи ніколи не могли збігтися через недостатню
кількість інформації про цю містичну добу.
Доба середньовіччя [1] або ж «темні віки» — період історії від 5 століття до
кінця 15 століття — час примітивної культури та цілковитого занепаду науки,
формування нових держав, епідемій, міжусобиць та війн, поширення впливу
церкви та християнської релігії у всіх галузях суспільного і культурного життя.
Середньовічне суспільство, складалося з безлічі соціальних станів . Людина
за народженням належала до одного з них і практично не мала можливості змінити
своє соціальне становище. Майже всі представники тогочасного суспільства не
знали письма, що унеможливлювало передачу достовірної інформації між
поколіннями. Лише одиниці володіли такими знаннями і могли писати історію
тогочасного суспільства, але й вони зазнавали певного утиску з боку церкви та
влади, тому говорити про достовірність тогочасних документів з повною
впевненістю не можна. Церква фактично була головним правлячим органом влади
на той час(до 1100 року). Їй повністю підпорядковувалась система освіти,
контролювалось прийняття рішень та законів, проведення виборів. Саме вона
вирішувала долю історичних документів та іноді корегувала історичні факти, задля
власної вигоди.
Ще одним фактом , який вплинув на долю історичного надбання були
постійні війни та міжусобиці, внаслідок яких руйнувалися цілі міста, зникали
важливі документи та інформація про історичну епоху.
Саме тому інформації про середньовіччя так мало, що не дозволяє історикам
скласти єдину повноцінну картину про ті дні. Особливо мало інформації про
хрестові походи, адже повноцінні документи про них так і не дійшли до наших
часів. Твердження істориків завжди різняться між собою, що іноді призводить до
6

маштабної дискусії, але так і не вирішує проблему.


Але інформаційні технології нині прогресивно розвиваються й торкаються
всіх сфер людської діяльності. Найважливіший вплив вони мають на освіту та
дослідницьку діяльність, оскільки відкривають можливості для впровадження
нових методик навчання, моделювання та пошуку інформації. Їхні засоби
допомагають вирішувати завдання інтерактивного проектування,
автоматизованого навчання, контролю технологічних параметрів, прикладних і
теоретичних дослідів. З розвитком техніки стало можливим візуалізувати процес
меделювання, що спричинило ряд досліджень у різноманітних сферах діяльності
людини.
Саме тому в якості теми курсової роботи було обрано розробку програмної
системи моделювання діяльності тогочасного суспільства під час формування
нового королівства у хрестовому поході.
7

1 АНАЛІЗ СУЧАСНОГО СТАНУ ПИТАННЯ ТА ОБҐРУНТУВАННЯ


ЗАВДАННЯ НА РОБОТУ

1.1 Предметна область

Одною з головних проблем теми, яка потребує програмної реалізаціє є


дослідження завоювання нових земель та оборона власних. Для реалізації цієї мети
новому королівству потрібне сильне військо, яке складається з 3 типів найманців:
списоносця, лучника та лицара-тамплієра .
Списоносець – найманець типу легкої піхоти, який чудово справляється з
простими задачами. Характерними рисами є зовнішній вигляд, який складається з
шкіряного одягу та наявністю списа у якості зброї. Має високу швидкість
пересування по локації, але досить малий запас здоров’я та рівень броні. Основна
задача на полі бою – прикриття союзників та забезпечення швидкого підкріплення.
Можуть самостійно використовуватися як при наступі так і при обороні фортець.
Лучник – найманець типу стрілець, який володіє базовими навиками
стрільби із лука та має досить розвинуту спритність. Характерними ознаками є
наявність лука та стріл, легкого переважно складно помітного одягу. Має високу
швидкість пересування локацією, середній рівень здоров’я та легку броню.
Основна задача на полі бою – забезпечити прикриття основних сил. Можуть
самостійно використовуватися при обороні фортець, але не при наступі.
Лицар-тамплієр – найманець типу кавалерії, який має досить високу фізичну
підготовку та майстерне володіння мечем. Характерними рисами є наявність меча
– у якості зброї , обладунків – у якості захисної броні. Має найвищу швидкість
пересування локацією, високий рівень здоров’я, важку броню. Основна задача на
полі бою – знищення сил противника та забезпечення переваги у процесі бою.
Можуть самостійно використовуватися як при наступі так і при обороні фортець.
Фортеці (макрооб’єкти) – основні місця утворення військ, які мають свою
власну територію, жителів, ресурси, запас золота. Найманці (мікрооб’єкти) –
намагаються захопити ворожу фортецю, задля завоювання нової території та
8

ресурсів, які потрібні для розвитку фортеці та її війська. Фортеці розміщені в


випадкових точках локації, їх кількість є обмеженою.
Мапа світу (універсальний макрооб’єкт) – містить в собі
макрооб’єкти(фортеці) та мікрооб’єкти(найманців).
Усі найманці з’являються у мапі та можуть захоплювати ворожу територію.
Кожен найманець має зовнішню ознаку – різні обладунки та ім’я. Кожна фортеця
відновлює здоров’я своїм найманцям, а при заходжені ворожих військ до фортеці
– то в них зменшується рівень здоров’я. Гра закінчується коли фортеця загарбана
(рівень здоров’я фортеці рівний нулю).

1.2 Існуючі реалізації


На сьогодні існує ціла серія ігор Stronghold: Stronghold, Stronghold Crusader,
Stronghold Crusader Extream, Stronghold Crusader 2, Stronghold 2, Stronghold 3,
Stronghold Legends.
Stronghold (див. рисунок 1.1) [2] – перша із ігор серії яка побачила світ у 2001
році, розроблена компанією Firefly Studios. Відеогра в жанрі стратегії в реальному
часі , включаючи в себе широку воєнну компанію та економічний розвиток,
дозволяючи гравцям пройти всі етами розвитку середньовічного королівства.

Рисунок 1.1 – Фрагмент гри Stronghold


9

Stronghold Crusader (див. рисунок 1.2) – комп'ютерна гра в жанрі стратегії в


реальному часі, розроблене компанією Firefly Studios в 2002 році. Сюжет гри
присвячений хрестовим походам на Близькому Сході. У грі присутні елементи
розвитку війська , становлення економіки, проведення боїв, завоювання репутації.

Рисунок 1.2 – Фрагмент гри Stronghold Crusader

Stronghold Crusader Extream (див. рисунок 1.3) [2] – повноцінне самостійне


доповнення гри Stronghold Crusader, розроблене компанією Firefly Studios в 2005
році. До сюжету додані нові локації та місії, 8 нових персонажів, нові типи військ,
змінено поведінку війська та додано нові сюжетні лінії.
Stronghold Crusader 2 (див. рисунок 1.4) – відеогра в жанрі воєнно-
економічної стратегії в реальному часі, видана компанією Firefly Studios в 2014
році. Являла собою продовження Stronghold Crusader. У відеогрі було змінено
систему поведінки опонентів та військ, додано нові події, типи військ та сюжетні
лінії. Вперше у серії ігор Stronghold Crusader використано 3D графіку та додано
анімацію.
10

Рисунок 1.3 – Фрагмент гри Stronghold Crusader Extream

Рисунок 1.4 – Фрагмент гри Stronghold Crusader 2

Розглянуті аналоги є недосконалими та мають застарілу графіку, незручний


інтерфейс та недостовірну поведінку об’єктів. Тому було прийнято рішення
розробити власну реалізацію яка, завдяки новітнім засобам мови Java, надасть
користувачеві можливіть пограти в гру Stronghold Crusader, отримати виключне
задоволення від її проходження завдяки новітній графіці.
11

1.3 Розробка технічного завдання на роботу


В програмі повинно бути реалізовано: додаток Windows з графічним
інтерфейсом.
Клас мікрооб’єкта повинен містити не менше 4 елементів змінних і не менше
4 методів (окрім геттерів та сеттерів). Як мінімум одна змінна повинна бути типу
int, одна – типу double і як мінімум одна – рядок. Змінні-елементи класу мають бути
приватними, для них повинні бути створені відповідні аксесори та мутатори
(іншими словами – геттери та сетери. В класі мікрооб’єкта повинен бути присутній
конструктор без аргументів. Повинно бути використано делегування
конструкторів. Повинно бути продемонстровано як мінімум один статичний блок
ініціалізації і один нестатичний. Реалізація функцій boolean equals(Object o) та
String toString(). Додати до класу мікрооб’єкта в якості елемента посилальний тип,
щоб зробити необхідним глибинне копіювання. Реалізовано глибинне копіювання
шляхом реалізації інтерфейсу Cloneable. Повинне бути продемонстроване
використання глибинного копіювання. Продемонструвати використання як
мінімум двох функцій-статичних елементів класу java.util.Arrays (можливо для
цього потрібно буде створити тимчасовий об’єкт-масив з колекції, яка
використовується). Продемонструвати використання інтерфейсу Сomparable або
Comparer. Повинні бути продемонстровано використання віртуальних функцій.
Повинні бути продемонстровано типу доступу protected. Повинно бути
продемонстровано використання динамічного поліморфізму. Повинно бути
продемонстровано використання статичного поліморфізму. Продемонстровано
використання ключового слова instanceof.
Мікрооб'єкт: мінімум три графічних примітива (один з яких - текст) (навіть в
неактивованому стані!). Білий (=невидимий) графічний примітив НЕ рахується!
Універсальний об'єкт: мінімум три графічних примітива (один з яких - текст). Білий
(=невидимий) графічний примітив НЕ рахується! Макрооб'єкт: мінімум три
графічних примітива(один з яких - текст). Білий (=невидимий) графічний примітив
НЕ рахується! При натискуванні лівої кнопки миші на мікрооб’єкті він повинен
ставати активним/неактивним. В програмі повинна бути реалізована активація
12

декількох об’єктів одночасно. Зображення активного мікрооб’єкта повинно


відрізнятись від зображення неактивного хоча б одним графічним примітивом.
Інтерфейс програми повинен сигналізувати про те, який саме мікрооб’єкт
активував користувач. По вибору студента інформація про активований
мікрооб’єкт/мікрооб’єкти може виводитись у рядку статуса або робочій області
програми. Якщо користувач активував декілька мікрооб’єктів, то інформація про
це також має якимось чином відображатися. При натискувань клавіш-стрілок
активні об’єкти/об’єкт повинні рухатись у вікні програми. При натискувань
клавіши Delete активні об’єкти повинні знищуватись. Якщо активного об’єкта нема
– клавіша Delete ігнорується. Реалізувати в проекті: Клавіша Esc повинна відміняти
активацію обєкта. Повина бути побудована ієрархія класів мікрооб'єктів, яка
містить як мінімум три рівня наслідування, які можуть інстанціонуватись і
зображатись на екрані. Зображення кожного рівня має відрізнятись від всіх інших
хоча б одним графічним примітивом. В побудованій ієрархії класів повинні бути
продемонстровані: - виклик конструктора базового класу; - виклик метода базового
класу. При натискуванні клавіши Insert повинно з’являтись діалогове вікно, яке
повинно визначати параметри створюваного мікрооб’єкта. В нього повинна бути
присутня можливість обирати до якого з класів нащадків у ієрархії наслідування
він належить. Крім керуючого елемента Button у діалоговому вікні також повинні
бути використані як мінімум три з наступного списку: TextField, CheckBox,
{ComboBox|ListView|ChoiceBox}, RadioButton.
Додати у проект клас/класи універсального об’єкта. Універсальний об’єкт
призначений містити всі мікрооб’єкти та всі макрооб’єкти. У вікні програми
відображається лише певна частина універсального об’єкта, яка не повинна
перевищувати 25% його загального розміру. Мінімальний розмір універсального
об’єкта 1600 позицій для мікрооб’єкта (тобто на екрані одночасно можна побачити
не більше квадрата 20*20 позицій для мікрооб’єкта). Реалізувати можливість
змінювати частину універсального об’єкта, яку спостерігає користувач (будь яким
способом). Додати у проект клас/класи макрооб’єкта. Макрооб’єкт повинен мати
можливість містити більше одного мікрооб’єкта. Не обов’язково мати можливості
13

додавати/видаляти макрооб’єкти в програму. Цілком достатньо, якщо програма


буде мати деяку кількість макрооб’єктів (БІЛЬШЕ ОДНОГО!) згенеровану при
запуску програми і яка буде незмінною протягом роботи програми. Макрооб’єкти
повинні мати певні позиції в універсальному об’єкті і повинні відображатись на
екраині. Позиції макрооб’єктів в середині універсального об’єкта можуть
залишатись незмінними протягом роботи програми. Мікрооб’єкти можуть або
належати одному (або більшій кількості) макрооб’єкту, або не належати жодному.
Глядачу має бути зрозуміло в чому полягає приналежність мікрооб’єкта
макрооб’єкту, тобто чим поведінка такого мікрооб’єкта відрізняється від поведінки
мікрооб’єкта, який не належить жодному макрооб’єкту. Повинна обов'язково бути
реалізована можливість вилучити мікрооб'єкт з всіх макрооб'єктів, в результаті
чого він не буде належати жодному макрооб'єкту. Також повинна бути реалізована
можливість вручну завести мікрооб’єкт у макрооб’єкт. Всі мікрооб'єкти та
макроб'єкти повинні належати універсальному об'єкту і не повинні мати змоги
вийти за його межі.
Повинен бути реалізований автоматичний рух деяких мікрооб’єктів:
1) при русі деякі мікрооб'єкти взаємодіють між собою (це має бути помітно
візуально в тому сенсі, що або щось змінюється у їх зображенні або у характері їх
руху).
2) деякі мікрооб'єкти заходять в макрооб'єкти та деякі виходять.
3) характер руху мікрооб'єктів повинен змінюватись при натискуванні певної
клавіші клавіатури або при виборі команди меню. Під характером руху мається на
увазі не просто траєкторія, а те, в який спосіб вони взаємодіють з макрооб'єктами
та іншими мікрооб'єктами.
Повинна бути реалізована мінікарта, яка дозволяє прискорену навігацію:
1) На мінікарті повинна бути позначена видима область універсального
об’єкта.
2) Рух видимої області універсального об’єкта відповідно змінює мінікарту.
3) Макрооб’єкти та мікрооб’єкти позначені на мінікарті.
14

4) Рух та взаємодія мікрооб’єктів призводить до відповідних змін на


мінікарті.
5) Натискування лівої кнопки миші на мінікарті призводить до переміщення
видимої області універсального об’єкта.
Повинна бути запрограмована серіалізація/де-серіалізація всіх об’єктів у
текстовий/бінарний/XML файл. Серіалізація/де-серіалізація обов’язково повинна
зберігати не тільки власне інформацію про стан макро- та мікро-об’єктів, але й про
їх позицію на екрані. При серіалізації/де-серіалізації обов’язково повинні
використовуватись діалогові вікна, щоб запитати у користувача ім’я файлу та його
розташування на диску (наприклад можна використовувати системне діалогове
вікно FileChooser).
Продемонстровано використання ОДНІЄЇ параметризованої колекції.
Для нормального виконання програми необхідно наступне апаратне
забезпечення
1) комп’ютер серії IBM PC з частотою 233 МГц і вище;
2) 2 ГБ оперативної пам’яті;

3) графічний адаптер GEFORCE GT 1030;


4) відеокарта об’ємом пам’яті не менше 2ГБ;
5) клавіатура, ОС Windows 10/8.
Розмір дискового простору, що займає програма: 126 МБ.
Розмір оперативної пам’яті, що займає програма: 900 МБ.

1.4 Обгрунтування вибору мови програмування


Java [3]– об’єктно-орієнтована мова програмування, що розробляється
компанією Sun Microsystems і офіційно випущена 23 травня 1995 року. Java є одною
з найпоширеніших і найбільш комфортних мов програмування багатоцільового
застосування.
 Java є типобезпечною мовою – відсутність у програмах помилок, які важко
знайти і які пов'язані з неправильною інтерпретацією пам'яті комп'ютера. Це
робить процес розробки надійнішим і передбачуваним, а отже швидшим;
15

 спрощений та більш доступний алфавіт мови Java забезпечує краще


сприйняття коду програми;
 Java-код компілюється спочатку в проміжний код ,а не в машинний код, в той
час як багато C++ та С# компіляторів орієнтовані на компіляцію в машинний
код платформи;
 у мові Java є чіткі стандарти на введення-виведення, графіку, геометрію,
діалог, доступ до баз даних та інших типових застосувань. Завдяки цим
особливостям, програми на Java мають значно кращу кросплатформність, ніж
С++, і часто, будучи написані для певного комп'ютера і операційної системи,
працюють під іншими системами без змін;
 у Java [3] реалізовано автоматичне керування пам’яттю якого немає в C# C++;
 в Java реалізоване ієрархічне та багаторівневе успадкування класів, а також
реалізована автоматична обробка виключень, що дозволяє виправляти
помилки на етапі написання коду.

Cаме через переваги, вказані вище, мову Java було обрано мовою
програмування для курсової роботи.

1.5 Висновки
Проаналізувавши стан стратегії в реальному часі Stronghold Crusader,
переглянувши усі проблеми цього питання та зваживши усі переваги та недоліки
було вирішено створити власну реалізацію програмного продукту.
Створено список завдань, які повинні бути реалізовані в програмному
продукті. Найефективнішою мовою програмування для даного продукту шляхом
аналізу обрано Java.
16

2 РОЗРОБКА ІНТЕРФЕЙСУ ПРОГРАМИ ТА ПРИКЛАДІВ ВИКОРИСТАННЯ

2.1 Розробка інтерфейсу програми


Клієнт відображає на екрані стан універсального об’єкту і переходить в
режим очікування команд від користувача (рисунок 2.1). При цьому, паралельно,
відбувається обробка сигналів з таймеру.

Робоча область

Рисунок 2.1 – Структура вікна програми

Назва вікна – «**Stronghold Crusaider**» відповідає назві програми. Меню


містить кнопку: «File»». Робоча область вікна програми слугує для відображення
об’єктів (мікро- та макрооб’єктів): найманці, фортеці та мапи світу (універсального
об’єкту на якому розгортаються дії). Рядок стану відсутній. Для того, щоб отримати
інформацію про найманця потрібно виділити його та натиснути правою кнопкою
миші. Розміри вікна можна змінювати, вікно можна згорнути/розгорнути. При
відкритті розмір віка фіксований (1920х1080 px). У вкладці «Файл» містяться три
команди: «Open save» при натисканні з’являється вікно, що дає можливість
відкрити файл, у якому збережена інформація про стан об’єктів), «Save» (при
натисканні з’являється вікно, що дає можливість створити файл, у якому буде
збережена інформація про поточний стан об’єктів), «Exit» (при натискуванні
17

програма закривається). У вікні програми після її відкриття буде зображено мапа


світу, дві фортеці та найманці з випадково заданими координатами. 4 найманця з
випадковою командою(фортеці лордів Криси та Хрестоносця) з’являються у вікні.
Користувач може клонувати або додавати нових найманців, змінювати їх рух,
видаляти їх. Для цього використовуються команди описані далі.
За замовчуванням герої одразу ж починають свій рух в універсальному
об’єкті. У програмі реалізовано декілька сценаріїв руху: натиснення клавіші «Н»
здійснюється рух найманців до фортець, при цьому потрібно щоб фортеці були
відчинені, що керується клавішею «К», а також хаотичний рух, який здійснюють
мікрооб'єкти коли не натиснута клавіша «Н». Для ручного керування руху
найманців стрілками, їх треба виділити. Для виділення найманця слід натиснути на
нього лівою кнопкою миші. У виділеного найманця з’явиться додаткова рамка, яка
сигналізує, що об’єкт є активний. Щоб зняти виділення потрібно повторно
натиснути на героя або ж, щоб зняти виділення з усіх виділених найманців потрібно
натиснути клавішу “ESC”. Виділених найманців можна видаляти клавішею
«Delete» , а також клонувати за допомогою клавіші ”C”. Для створення нового
мікрооб’єкту (найманця) викликається діалогове вікно натисненням клавіші «I»
або «Insert». В ньому можна обрати рівень найманця, вибрати його команду
(фортецю) та задати характеристику ситності найманця.

2.2 Приклади використання


Приклади використання (use cases) - це важливий елемент проектування.
Приклад використання розкриває можливі способи вза’ємодії між користувачами
програми та самою програмою і дозволяє розробникам приділити більше уваги
поліпшенню зручності програми.

Приклад 1. Створення нового найманця у діалоговому вікні (рисунок 2.2).


Натискуванням клавіші І або Insert з’являєтся діалогове вікно, у якому
користувач має задати силу, ім’я, рівень, фортецю та виділений найманець чи ні.
18

Після натиснення кнопки «Підтвердити» мікрооб’єкт з’явится у заданій фортеці на


екрані.

Рисунок 2.2 – Створення найманця за допомогою діалогового вікна

Приклад 2. Клонування найманця (Рисунок 2.3)


Якщо виділено декілька найманців (декілька мікрооб’єктів є активними), то
при натискуванні клавіші С, відкриється діалогове вікно підтвердження
клонування.

Клонування

Ви дійсно хочете
клонувати виділених
Вікно “Клонування”
найманців?

НІ ТАК

Рисунок 2.3 – Клонування групи найманців


19

Приклад 3. Перемога однієї із сторін (Рисунок 2.4)


Якщо рівень здоров’я фортеці під час взаємодії із найманцями стане рівним
нулю то з’явиться вікно, яке сигналізуватиме про перемогу однієї із команд, при
чому гра зупиниться.

Перемога

Переміг

Лорд Христоносець Вікно “Перемоги”

Закрити

Рисунок 2.4 – Вікно завершення гри

Приклад 4. Стан мікрооб’єкту (Рисунок 2.5)


Натиснувши лівою кнопкою миші по виділеному мікрооб’єкту з’явиться
вікно, яке відображає стан активного мікрооб’єкту.

Поточна

Ім’я:

Здоров’я: Вікно “Стану”

Рівень:

Чи активний:

Закрити

Рисунок 2.5 – Вікно стану


20

Приклад 5. Попередження (Рисунок 2.6)


Якщо виділених об’єктів декілька, то з’явиться вікно, яке попереджує,що
перегрлядати інформацію можна лише про один мікрооб’єкт.

Увага

Переглядати інформацію
можна лише про один
Вікно “Попередження”
мікрооб’єкт

Закрити

Рисунок 2.6 – Вікно попередження

Отже, у другому розділі розроблено інтерфейс програми та наведено


приклади використання, які будуть реалізовані у програмі.
21

3 РОЗРОБКА ПІДСИСТЕМИ ГРАФІЧНОГО ВІДОБРАЖЕННЯ

3.1 Модель графічного відображення

Списоносець (Рисунок 3.1, а) є найслабшим найманцем (1-ший рівень


ієрархії). Лучник (Рисунок 3.1, б) є найманцем 2-го рівня в ієрархії мікрооб’єктів.
Лицар-тамплієр (Рисунок 3.1, в) є найсильнішим найманцем (3-тій рівень ієрархії).
Всі коорднитати, що створюють співвідношення між елементами найманця
(зображенням, показником здоров’я (зелений прямокутник), показником атаки
(червоний прямокутник) та ім’ям (текстом))однакові для найманців всіх рівнів
ієрархії. Зображення найманців складається із графічного
примітиву(зображення)(100х67 px), ім’я (тексту), показника здоров’я (зелений
прямокутник) та атаки(червоний прямокутник). Координати графічного примітиву
(зображення) сhordX, сhordY; Координати тексту сhordX, сhordY-30; Координати
показника здоров’я – сhordХ+ поточний рівень здоров’я найманця, сhordY-20.

Рисунок 3.1 – Модель графічного відображення найманців а)Списоносець,


б)Лучник, в)Лицар-таплієр

Фортеця (Рисунок 3.2) є макрооб'єктом. Складається з зображення(450х450


px), прямокутника (активної зони), ім'я(тексту), лічильника(тексту) та показників
здоров'я та атаки, а також може містити в собі найманців. Координати графічного
примітиву(зображення) сhordX, сhordY. Координати тексту лічильника сhordX-20,
сhordY+40. Координати тексту ім’я сhordX-20, сhordY-80. Координати активної
зони сhordX-20, сhordY-120. Координати показника здоров’я сhordX+поточний
22

показник здоров’я фортеці, сhordY-50. Координати показника атаки сhordX+


показник атаки фортеці-10, сhordY-20.

Рисунок 3.2 – Модель графічного відображення макрооб’єкту

Мапа (Рисунок 3.3) є універсальним об’єктом. Складається із


зображення(5000х5000px), текстів лічильників та текстів стану, які мають
фіксований розмір 24 px. Координати графічного примітиву(зображення) 0, 0.
Координати тексту лічильника команди криси сhordX+20, сhordY+60. Координати
тексту лічильника команди лорда сhordX+20, сhordY+90. Координати стану
контролеру стану макрооб’єктів сhordX+20, сhordY+120. Координати контролеру
стану мікрооб’єктів сhordX+20, сhordY+150. Координати контролеру стану руху
мікрооб’єктів сhordX+20, сhordY+180

3.2 Графічні процедури підсистеми графічного відображення


javafx.scene.image.Image [4] - дозволяє завантажити картинку із вказаного
файлу. javafx.scene.image.ImageView - відображає завантажену картинку за
23

Рисунок 3.3 – Модель графічного відображення універсального об’єкту

допомогою Image. javafx.scene.text – відображає примітивний тип String. Може


примати та набувати нових характеистик(колір, шрифт, розмір, розміщення).
javafx.scene.shape. Rectangle – відображає прямокутник із вказаними
розмірами(ширина й довжина), може бути залитий кольором або приймати якісь
ефекти. javafx.scene.shape.Line - використовується для відображення
прямокутника у вигляді лінії. Може приймати параметри розміру(висоти,
довжини), кольору та розміщення.
24

4 РОЗРОБКА ДІАГРАМ КЛАСІВ, ОБ’ЄКТІВ ТА СТАНУ

4.1 Діаграми класів


На діаграмах класів показано різноманітні класи, які утворюють систему і їх
взаємозв’язки.

4.1.1 Діаграми наслідуваня


Списоносець
#name: String
#team: String
#level: String
#hp: double
#speed: int
#damage: double
#armor: int
#food: int
#salary: []double
#alive: boolean
#isActive: boolean
#chordX: double
#chordY double:
#microImage: ImageViev
#microGroup: Group
#rectActive: Rectangle
#linehealth : Line
#linedamage : Line
#nAme: Text
#homeX: int Лучник
#homeY: int
#ayto_move: byte +print():void
+equalSalary():void
+setSalaryHisrory(double itm): void
+equalSalary(): void
+training():void +say_to_child():void
+eat():void
+fight(Spusonosech s1,Spusonosech s2): void
+setRandteam():void Лицар-тамплієр
+setXY(double x,double y):voud
+setmicrochord():void +print():void
+up():void +equalSalary():void
+down():void
+left():void
+right():void +say_to_child():v
+moveToFort():void oid
+healthupLort():void
+healthupKrusa():void
+auto_move():void
+print():void
+say_to_child():void
+ineteractivSpus(Spusonosech s1,Spusonosech
s2):void
+ineteractive_Spus_Fort(Spusonsech s,Fortness
fort):void

Рисунок 4.1 – Діаграма наслідування


25

Наслідування(див. рисунок 4.1) є однією з фундаментальних основ об’єктно-


орієнтованого програмування, у якому клас “отримує” всі атрибути і операції
класу, нащадком якого він є, і може додавати власні атрибути і операції [5].
Значення змінних в даній діаграмі наслідування:
 name – ім’я мікрооб’єкта;
 team – команда мікрооб’єкта;
 level – рівень мікрооб’єкта;
 hp – рівень здоров’я мікрооб’єкта;
 speed – швидкість мікрооб’єкта;
 damage – рівень атаки мікрооб’єкта;
 armor – броня мікрооб’єкта;
 food – ситність мікрооб’єкта;
 salary – зарплата мікрооб’єкта;
 isactive – чи виділяний мікрооб’єкт;
 alive – чи існує мікрооб’єкт;
 chordx – кордината х мікрооб’єкта;
 chordy – кордината у мікрооб’єкта;
 microinage – зображення мікрооб’єкта;
 microgroup – група мікрооб’єкта;
 rectactive – активна оболонка мікрооб’єкта;
 linehealrh – лінія здоров’я мікрооб’єкта;
 linedamage – лінія атаки мікрооб’єкта;
 nAme – ім’я (текст) мікрооб’єкта;
 homex – кордината х командного макрооб’єкта;
 homey – кординати у командного макрооб’єкта;
 auto_move – напрям руху мікрооб’єкта.
В основу даної ієрархії було покладено принцип “зростання за силою” , тобто
чим далі мікрооб'єкт в ієрархії, тим він сильніший ,швидший та має більшу
кількість здоров’я.
26

4.1.2 Діаграми агрегації


Макрооб’єкт – Фортеця може містити у собі деяку кількість мікрооб’єктів
(Списоносець, Лучник, Лицар).

Мікрооб’єкти Макрооб’єкт
(Spusonosech,Lychnik,Luchar (Фортеця)
) Princess)
Рисунок 4.2 – Діаграма агрегації

При вилученні мікрооб’єктів це не нашкодить самій Фортеці. Таке


відношення називається агрегацією (рисунок 4.2).

4.1.3 Діаграми композиції


Композиції — це асоціації, які відповідають дуже сильній агрегації(рисунок
4.4). Вони існують лише у межах цілого, після знищення цілого буде знищено і його
частини.

4.1.4 Діаграми асоціації


Асоціація—взаємна залежність між об’єктами різних класів, кожен з яких є
рівноправним членом залежності (рисунок 4.3).

setS alary
-Конец5 -Конец6
Spusonosech salary
1 1

Рисунок 4.3 – Діаграмa асоціації

Мікрооб’єкт Spusunosech містить об’єкт класу salary, який було додано для
того, щоб глибинне копіювання стало необхідним.
27

Вікно програми
1 1

1 1

Меню у верхній частині


вікна програми
Робоча область

Універсальний об’єкт(Map)
та макрооб’єкти (фортеці)

Рисунок 4.4 – Діаграма композиції

У композиціях ми також маємо справу з співвідношеннями ціле – частина,


але тут зв’язок є настільки сильним, що частини не можуть існувати без цілого.

4.2 Діаграми кооперації


Кооперація (collaboration) [5] – специфікація безлічі об'єктів окремих класів,
спільно взаємодіючих з метою реалізації окремих варіантів використання в
загальному контексті модельованої системи. Кооперація визначає структуру
поведінки системи в термінах взаємодії учасників цієї кооперації (рисунок 4.5).

1:serialize()
File Cеріалізація

1.1:save() 1.2:save() 1.3:save()

Spusonosech Lychnuk Luchar

Рисунок 4.5 – Діаграми кооперації


28

Її мета полягає в тому, щоб специфікувати особливості реалізації окремих


варіантів використання або найбільш значущих операцій в системі.

4.3 Діаграми послідовності


Рисунок 4.6 демонструє життєвий цикл масиву мікрооб’єктів.

sp: [ ]Spusonosech timer: AnimationTimer

newUnit
() Auto_move()
Map.addNew s:
Spusonosech
Unit()

timer.start()

Рисунок 4.6 – Діаграма послідовності

Функції руху «auto_move()» та «start()» та створення за допомогою


діалогового вікна newUnit() нового мікрооб’єкту і згодом його видалення
демонструють життевий цикл мікрооб’єкту.

4.4 Діаграми стану

Моделювання процесу функціонування складної системи, в реальному часі,


зображено на рисунку 4.7 за допомогою діаграми стану.
29

Поява на
карті

Рух

Зайшов у Пересікся
Чи Пересікся
дружню із ворожою Ні
здоровий із ворогом
фортецю фортецею

Лікування Вихід

Нанесення
урону

Бій
Найманець Ворог
живий? живий?
Так Так
Ні

Видалення

Смерть

Рисунок 4.7 – Діаграма стану

Отже, у четвертому розділі були створені діаграми стану, послідовності,


кооперації, композиції, асоціації, агрегіції та наслідування, що ілюструють повний
функціонал програми.
30

5 РОЗРОБКА ПІДСИСТЕМИ
СЕРІАЛІЗАЦІЇ/ДЕСЕРІАЛІЗАЦІЇ ДАНИХ

5.1 Розробка формату файлу


Серіалізація (serialization) [6] – це процес перетворення структури даних або
стану об'єкта у формат, який може зберігатися або передаватися і може бути
відновлений пізніше. Протилежна операція, вилучення структури даних з серії
байтів, є десеріалізацією(deserealization) – процес зчитування данних із файлу
серіалізації, які використовуються для створення ідентичного клону вихідного
об'єкта. У даній роботі використовується формат файлу зображений на таблиці 5.1.

Таблиця 5.1 – Формат файлу

Параметр Пояснення

fortness Додавання данних про макрооб’єкти (фортець)

sample.macro.LordFortress Додавання групи фортеці Лорда

2 Кількість мікрооб’єктів у фортеці Лорда

sample.macro.KrusaFortress Додавання групи фортеці Криси


0 Кількість мікрооб’єктів у фортеці Криси
units Додавання данних про мікрооб'єкти

sample.micro.Spusonosech Рівень мікрооб’єкта (клас)

2890 Кордината Х групи мікрооб’єкта

3969 Кордината У групи мікрооб’єкта

Travis Ім’я мікрооб’єкта

12 Рівень здоров’я
31

5.2 Механізми введення виведення мови Java


Для роботи з файлами в даному випадку було використано такі засоби:
 Класс XMLEncoder [7] є додатковою
альтернативою ObjectOutputStreamі. Використовується для подання інформації про
об’єкт у формі XML, де кожний елемент інформації об’єкта записується в якості
окремого методу. "Порожній" тег позначає оператор, який буде виконуватися, але
чий результат не буде використовуватися в якості параметра методу включення.
Ім'я методу позначається атрибутом "методу". Стандартні атрибути
"ідентифікатора" і "idref" XML використовуються, щоб зробити посилання на
попередні вирази - щоб мати справу з зациклення в графі об'єктів. Атрибут "класу"
використовується, щоб визначити мету статичного методу або конструктора явно;
його значення, що є повністю визначеним ім'ям класу.
 Класс XMLDecoder [8]. Використовується, щоб читати, XML-
документи, які створені за допомогою XMLEncoder і використовується точно так
само як ObjectInputStream, тобто конструктори цього класу припускають, що
кодування символів і розмір байт-буфера за замовчуванням є прийнятними.
32

6 КЕРІВНИЦТВО КОРИСТУВАЧА

6.1 Встановлення програми та необхідні файли


Для користувача існує єдина версія програми – архів файлів програмного
коду. Для виконання програми потрібно мати встановлений архіватор, який працює
з *.zip або *.rar архівами, та IntelliJ IDEA 2020.3.2 (Community Edition). Для роботи
з програмою потрібно розархівувати папку, відкрити її в IntelliJ IDEA та запустити
програму за допомогою кнопки Run. Після запуску програми користувач побачить
вікно програми (рисунок 6.1).

Рисунок 6.1 – Вигляд вікна програми

6.2 Функціональні клавіші


 ЛКМ – використовується для виділення мікрооб’єктів(з’являється жовта
рамка навколо мікрооб’єкта) (рисунок 6.2);

Рисунок 6.2—Виділення мікрооб’єкта


33

 WASD – рух виділеного мікрооб’єкта;


 H – зміна характеру руху мікрооб’єктів(усі мікрооб’єкти рухаються до
командного макрооб’єкту);
 клавіші 1-3 – створення мікрооб’єктів різних рівнів ієрархії (відповідно до
номеру клавіші) із випадково заданими кординатами та командою;
 клавіша 4 – створення мікрооб’єкту 1 рівня ієрархії команди криси із
випадково заданими кординатами;
 клавіша 5 – створення мікрооб’єкту 2 рівня ієрархії команди лорда із
випадково заданими кординатами;
 клавіша 6 – створення мікрооб’єкту 3 рівня ієрархії команди криси із
випадково заданими кординатами;
 Delete – видалення виділеного мікрооб’єкта(-ів);
 Escape – відмінити виділення всіх мікрооб’єктів;
 С – копіювання виділеного мікрооб’єкту. Якщо виділених мікрооб’єктів
декілька викликається вікно підтвердження(рисунок 6.3);

Рисунок 6.3 — Клонування мікрооб’єктів

 Enter – виділення усіх мікрооб’єктів;


 K – унеможливлює перебування мікрооб’єктів у макрооб’єктах;
34

 Insert – виклик діалогового вікна для додавання мікрооб’єкта (рисунок


6.4);

Рисунок 6.4—Виклик діалогового вікна

 ПКМ – виклик діалогового вікна, у якому міститься інформація про стан


активного мікрооб’єкта (рисунок 6.5), якщо активних мікрооб’єктів більше
2, то викликається вікно попередження(рисунок 6.6);

Рисунок 6.5—Виклик діалогового вікна стану


35

Рисунок 6.6—Виклик діалогового вікна попередження

 TAB – прибирає текст універсального об’єкту;


 Ctrl+O – виклик діалогу десеріалізації;
 J – взаємодія мікрооб’єктів;
 клавіша 0 – демонстрування інтерфейсу Comparable;
 клавіша 8 – демонстрування статичного та динамічного поліморфізму;
 Ctrl+S – виклик діалогу сереалізації;
 Ctrl+E – вихід із програми.
36

ВИСНОВКИ

В процесі роботи над курсовою роботою було створено нову реалізацію


програми по мотивах гри The Crusaider Stronghold, в якій було розкрито проблеми
дослідження та завоювання нових земель, а також врирішено низку проблем:
невибагливості до платформи, відкритості вихідного коду та відносно малого
розміру програми.
Засобами обраної мови програмування (Java) було реалізовано методи, які
забезпечують взаємодію макрооб’єктів та мікрооб’єктів.
Під час створення курсової роботи було отримано наступні навички: робота
із візуальним середовищем програмування IntelliJ IDEA 2020.3.2 (Community
Edition), класами та об’єктами, інтерфейсами, перевантаженням методів,
серіалізацією/десеріалізацією, робота з графічними засобами JavaFX такими як
AnimationTimer, діалогові вікна, графічне відображення об’єктів.
Завдяки наявності відкритого коду, присутня можливість покращення
програми користувачами з різних платформ завдяки платформонезалежності
вихідного коду.
37

ПЕРЕЛІК ПОСИЛАНЬ

1. Доба середньовіччя. URL: https://uk.wikipedia.org/wiki/Середньовіччя (дата


звернення: 27.04.21).
2. Серія ігр Stronghold. URL: https://ru.wikipedia.org/wiki/Stronghold (дата
звернення: 22.05.21).
3. Сравнение C++ с языками Java и C#. URL:
https://wiki.dieg.info/sravnenie_c_s_jazykami_java_i_c (дата звернення: 23.06.21).
4. JavaFX CSS Reference Guide. URL:
https://openjfx.io/javadoc/13/javafx.graphics/javafx/scene/doc-files/cssref.html#lin
(дата звернення: 22.05.21).
5. Бабенко Л. П. Інформаційна підтримка повторного використання у програмній
інженерії на базі UML. Вінниця: кібернетика и системний аналіз, 2003. 82с.
6. Сериализация. URL: https://ru.wikipedia.org/ wiki/Сериализация (дата
звернення: 23.06.21).
7. Класс XMLEncoder. URL: https://spec-
zone.ru/RU/Java/Docs/7/api/java/beans/XMLEncoder.html (дата звернення:
27.06.21).
8. Класс XMLDecoder. URL: https://spec-
zone.ru/RU/Java/Docs/7/api/java/beans/XMLDecoder.html (дата звернення:
27.06.21).
38

ДОДАТКИ
39

ДОДАТОК А

ЛІСТИНГ ПРОГРАМИ
//Main
package sample;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import sample.macro.Fortness;
import sample.macro.KrusaFortress;
import sample.macro.LordFortress;
import sample.micro.Luchar;
import sample.micro.Lychnik;
import sample.micro.Spusonosech;

import javax.xml.crypto.dom.DOMCryptoContext;
import java.security.Key;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.ForkJoinPool;

public class Main extends Application{

public static void setParam(Spusonosech s)


{
if(s instanceof Spusonosech)
{
s.setParametersforSpusonosech();
}
if(s instanceof Lychnik)
{
s.setParametersforLychnik();
}
if (s instanceof Luchar)
{
s.setParametersforLuchar();
}
}
private static final int sceneWidth;
private static final int sceneHeight ;

static { //статичний блок ініціалізації


sceneHeight=1080;
sceneWidth=1920;
}
40

private static final Map map = new Map();


private static final ScrollPane scrollPane = new ScrollPane(Map.getRoot());
private static final Scene scene = new Scene(scrollPane, sceneWidth,
sceneHeight);

private static double scrollX;


private static double scrollY;

public static Random random = new Random(new Date().getTime());


private static int moveSpeed = 0;

private int ckrusaFort;


private int clordFort;

private static boolean stayFortness = false;


private static boolean removeFromMap = false;
private static boolean closeFortness = false;
private static boolean infoOpacity = false;

public static LinkedList <Spusonosech> ArrayHealth =new LinkedList<>();


public static LinkedList <Spusonosech> ArrayCopy=new LinkedList<>();

private static Stage pStage;


private static Spusonosech spusConfig;

public static boolean isCheack = false;


public static Spusonosech buffSpus;
public static double nextX;
public static double nextY;

public static int spusX = 140;


public static int spusY = 2800;
public static double lychX = 10;
public static double lychY = 2800;
public static double luchX = 10;
public static double luchY = 100;

public static int spusCounter=0;


public static int lychCounter=0;
public static int luchCounter=0;

public static boolean buttonZ = false;

private static final String[] namesArray = {"Ben", "Ivan", "Stepan",


"Mukola","Platon","Jane","Mike","Steaven","ANdriy",
"Luke","Comaha","Aleg","Oleg","Nurse","Sag","Nile","Octavia",

"Roma","Rey","Bogban","Travis","Mukola","Liza","Gamura","Vinston","Alex","Hohol192
"};

//getters

protected AnimationTimer timer;


public AnimationTimer getTimer(){return timer;}
public static String[] getNamesArray() {
return namesArray;
}
public static int getSceneHeight() {
return sceneHeight;
}
41

public static int getSceneWidth() {


return sceneWidth;
}
public static ScrollPane getScrollPane() {
return scrollPane;
}
public static Map getMap() {
return map;
}
public static int getMoveSpeed() {return moveSpeed;}
public static Scene getScene() {
return scene;
}
public static Spusonosech getSpusConfig() {
return spusConfig;
}

//setters
private void setPrimaryStage(Stage pStage){
Main.pStage = pStage;
}

@Override
public void start(Stage primaryStage) throws Exception {
setPrimaryStage(primaryStage);
scrollPane.setFitToHeight(true);
scrollPane.setFitToWidth(true);

map.addFort(new LordFortress());
map.addFort(new KrusaFortress());

map.addNewUnit(new Spusonosech(),true);
map.addNewUnit(new Luchar(),true);
map.addNewUnit(new Lychnik(),true);
map.addNewUnit(new Lychnik(),true);

map.miniMapInFront();

Parent parent = FXMLLoader.load(getClass().getResource("sample.fxml"));


Map.getRoot().getChildren().add(parent);

scene.addEventHandler(KeyEvent.KEY_PRESSED, event ->{


for (Spusonosech s : map.getUnits()){
if (s.getIsActive()){
if (event.getCode() == KeyCode.W){
if (s.getMicroImage().getY() >=0)
s.up(moveSpeed);
}
if (event.getCode() == KeyCode.S){
if (s.getMicroImage().getY() +
s.getMicroImage().getFitHeight()
<= Map.getRoot().getHeight())
s.down(moveSpeed);
}
if (event.getCode() == KeyCode.A){
if (s.getMicroImage().getX() >=0)
s.left(moveSpeed);
}
if (event.getCode() == KeyCode.D){
if (s.getMicroImage().getX() +
s.getMicroImage().getFitWidth() + 100
<= Map.getRoot().getWidth())
s.right(moveSpeed);
42

}
}
}
if (event.isShiftDown()){
++moveSpeed;
}
if (event.isControlDown()){
if (moveSpeed >0)
--moveSpeed;
}
if (event.getCode() == KeyCode.DIGIT1){
map.addNewUnit(new Spusonosech(), true);
map.miniMapInFront();
}
if (event.getCode() == KeyCode.DIGIT2){
map.addNewUnit(new Lychnik(), true);
map.miniMapInFront();
}
if (event.getCode() == KeyCode.DIGIT3){
map.addNewUnit(new Luchar(), true);
map.miniMapInFront();
}
if (event.getCode() == KeyCode.DIGIT4){
map.addNewUnit(new
Spusonosech(namesArray[Main.random.nextInt(namesArray.length)], "Криси",78,false),
true);
map.miniMapInFront();
}
if (event.getCode() == KeyCode.DIGIT5){
map.addNewUnit(new
Lychnik(namesArray[Main.random.nextInt(namesArray.length)],"Лорда",78,false),
true);
map.miniMapInFront();
}
if (event.getCode() == KeyCode.DIGIT6){
map.addNewUnit(new
Luchar(namesArray[Main.random.nextInt(namesArray.length)], "Криси",78,false),
true);
map.miniMapInFront();
}

if (event.getCode() == KeyCode.DELETE){
for (int i = 0; i < map.getUnits().size(); ++i){
Spusonosech s = map.getUnits().get(i);
if (s.getIsActive()){
map.deleteUnit(s);
}
}
}
if (event.getCode() == KeyCode.ESCAPE){
for (Spusonosech s : map.getUnits()){
if (s.getIsActive()){
s.setActive();
}
}
}
if (event.getCode() == KeyCode.ENTER){
for (Spusonosech s : map.getUnits()){
if (!s.getIsActive()){
s.setActive();
}
}
}
43

if (event.getCode() == KeyCode.C){
LinkedList<Spusonosech> arr=new LinkedList<>();
int c=0;
for (int i = 0; i < map.getUnits().size(); ++i)
{
if (map.getUnits().get(i).getIsActive())
{
arr.add(map.getUnits().get(i));
c++;
}
}
if(c>=2)
{
try {
newWindOw(primaryStage);
} catch (Exception e) {
e.printStackTrace();
}
}
else {
LinkedList<Spusonosech> clone_arr = new LinkedList<>();
for (int i = 0; i < arr.size(); ++i) {
try {
clone_arr.add((Spusonosech) arr.get(i).clone());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
for (int i = 0; i < arr.size(); ++i)
map.addNewUnit(clone_arr.get(i), false);
}
}
if (event.getCode() == KeyCode.H){
stayFortness = !stayFortness;
}
if (event.getCode() == KeyCode.J){
removeFromMap = !removeFromMap;
}
if (event.getCode() == KeyCode.I ||
event.getCode() == KeyCode.INSERT ){
try {
newWindow(primaryStage);
} catch (Exception e) {
e.printStackTrace();
}
}
if (event.getCode() == KeyCode.K){
closeFortness = !closeFortness;
}
if (event.getCode() == KeyCode.DIGIT0){

for (int i = 0; i<map.getUnits().size(); ++i){


ArrayHealth.add(map.getUnits().get(i));
}

System.out.println("*********************************************");
System.out.println("Масив до використання інтерфейсу Сomparable");

System.out.println("*********************************************");
for (int i = 0; i<ArrayHealth.size(); ++i){
System.out.print( "Level: " + map.getUnits().get(i).getLevel()
+ " Name: "
44

+ map.getUnits().get(i).getnAme().getText() + "
Health: ");
System.out.println(ArrayHealth.get(i).getHp());
}

ArrayHealth.sort(Spusonosech.HPComparator);

System.out.println("*********************************************");
System.out.println("Масив після використання java.utils.Arrays;");

System.out.println("*********************************************");
for (int i = 0; i<ArrayHealth.size(); ++i){
System.out.print( "Level: " + map.getUnits().get(i).getLevel()
+ " Name: "
+ map.getUnits().get(i).getnAme().getText() + "
Health: ");
System.out.println(ArrayHealth.get(i).getHp());
}

System.out.println("*********************************************");
System.out.println("Три персонажі з найнижчим рівнем життя");

System.out.println("*********************************************");
for (int i = 0; i<3; ++i)
{
ArrayCopy.add(ArrayHealth.get(i));
}
for (int i = 0; i<ArrayCopy.size(); ++i){
System.out.print( "Level: " + map.getUnits().get(i).getLevel()
+ " Name: "
+ map.getUnits().get(i).getnAme().getText() + "
Health: ");
System.out.println(ArrayCopy.get(i).getHp());
}
ArrayCopy.clear();
ArrayHealth.clear();
}
if (event.getCode() == KeyCode.TAB){
infoOpacity = !infoOpacity;
if (infoOpacity){
map.getKrusaCounterText().setOpacity(1);
map.getLordCounterText().setOpacity(1);
map.getCloseFortText().setOpacity(1);
map.getRemoveFromMapText().setOpacity(1);
map.getStayFortressText().setOpacity(1);
}else{
map.getKrusaCounterText().setOpacity(0);
map.getLordCounterText().setOpacity(0);
map.getCloseFortText().setOpacity(0);
map.getRemoveFromMapText().setOpacity(0);
map.getStayFortressText().setOpacity(0);
}
}

if (event.getCode() == KeyCode.DIGIT8){
System.out.println("Використання статичного поліморфізму:");
sum(10,10);
sum(10,10,10);
System.out.println("Використання динамічного поліморфізму:");
Spusonosech.say_to_child();
Lychnik.say_to_child();
Luchar.say_to_child();
45

}
} );

scene.addEventHandler(MouseEvent.MOUSE_CLICKED, mouseEvent -> {


if (mouseEvent.getButton() == MouseButton.SECONDARY){
int counter = 0;
for (Spusonosech s : map.getUnits()){
if (s.getIsActive()){
counter++;
}
}
if (counter == 1){
for (Spusonosech sc : map.getUnits()){
if (sc.getIsActive()){
spusConfig = sc;
try {
unitConfig(primaryStage);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
else
{
try {
newWindw(primaryStage);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});

scrollPane.viewportBoundsProperty().addListener((observable, oldBounds,
bounds) -> {

Main.scrollX = -1 * (int) bounds.getMinX();


Main.scrollY = -1 * (int) bounds.getMinY();

parent.setLayoutX(scrollX);
parent.setLayoutY(scrollY);

updateChordINFO();

if (map.getUnits().size() == 0){
currentStatusINFO();
}

map.getMiniMap().getPane().setLayoutX(scrollX + 1430);
map.getMiniMap().getPane().setLayoutY(scrollY + scene.getHeight() -
map.getMiniMap().getPane().getHeight() - 500);
map.getMiniMap().getMap().setLayoutX(scrollX*MiniMap.getSCALE());
map.getMiniMap().getMap().setLayoutY(scrollY*MiniMap.getSCALE());
});

primaryStage.setMaximized(true);
primaryStage.setScene(scene);
primaryStage.setTitle("**Stronghold Crusaider**");
46

timer = new AnimationTimer() {


@Override
public void handle(long now) {

ckrusaFort = 0;
clordFort = 0;
for (Spusonosech s : map.getUnits()){
for (Fortness p : map.getFortness()){
switch (p.getName()){
case "Фортеця Лорда Криси":
p.setCounterKrusa(ckrusaFort);
break;
case "Фортеця Лорда Христоносця":
p.setCounterLord(clordFort);
break;
default:
break;
}

if(s.getMicroImage().getBoundsInParent().intersects(p.getFort_Image().getBoundsInP
arent())){
switch (p.getName()){
case "Фортеця Лорда Криси":
if (s.getTeam().equals("Криси")){
++ckrusaFort;
s.healthUpKrusa();
KrusaFortress.krusa.add(s);
p.setCounterKrusa(ckrusaFort);
}else {
Spusonosech.inetactive_spus_fort(p, s);
if (p.getHp() <= 0) {
if (p.getName().equals("Фортеця Лорда
Криси")) {
try {
setKrusawin(primaryStage);
} catch (Exception e) {
e.printStackTrace();
}
} else
try {
setLordwin(primaryStage);
} catch (Exception e) {
e.printStackTrace();
}
}
}
if(!stayFortness)
{
KrusaFortress.krusa.clear();
}

break;
case "Фортеця Лорда Христоносця":
if (s.getTeam().equals("Лорда")) {
++clordFort;
s.healthUpLord();
LordFortress.lord.add(s);
p.setCounterLord(clordFort);
} else {
Spusonosech.inetactive_spus_fort(p,s);
if (p.getHp()<=0)
{
47

if (p.getName().equals("Фортеця Лорда
Криси"))
{
try {
setKrusawin(primaryStage);
} catch (Exception e) {
e.printStackTrace();
}
}
else
try {
setLordwin(primaryStage);
} catch (Exception e) {
e.printStackTrace();
}
}
}
if(!stayFortness)
{
LordFortress.lord.clear();
}
break;
default:
break;
}
}
}
for (Spusonosech sp : map.getUnits())
{
if (s != sp &&
s.getMicroImage().getBoundsInParent().intersects(sp.getMicroImage().getBoundsInPar
ent())){
if(removeFromMap){Spusonosech.inetactive_spus(s, sp);}
if (s.getHp() <= 0){
map.deleteUnit(s);
}
}
}
if (closeFortness){
s.auto_move();
}else{
if (s.getHp() < 10 || stayFortness){
s.moveToFort();
}else{
s.auto_move();
}
}

s.setmicroChord();
currentStatusINFO();
}
map.getMiniMap().updateMap();
for(Fortness i: Main.getMap().getFortness())
{
if(i.getHp()<=0)
{
timer.stop();
}
}
}
};

timer.start();
48

primaryStage.show();

public void newWindow(Stage primaryStage) throws Exception{


Pane root1 =
FXMLLoader.load(getClass().getResource("CreateNewUnit.fxml"));
Scene scene1 = new Scene(root1);
Stage window = new Stage();
window.setTitle("**Створення нового юніта**");
window.setScene(scene1);
window.show();
}

public void newWindOw(Stage primaryStage) throws Exception{


Pane root1 = FXMLLoader.load(getClass().getResource("Alert.fxml"));
Scene scene1 = new Scene(root1);
Stage window = new Stage();
window.setTitle("**Попередження**");
window.setScene(scene1);
window.show();
}
public void newWindw(Stage primaryStage) throws Exception{
Pane root1 = FXMLLoader.load(getClass().getResource("ActiveAlert.fxml"));
Scene scene1 = new Scene(root1);
Stage window = new Stage();
window.setTitle("**Попередження**");
window.setScene(scene1);
window.show();
}

public void unitConfig(Stage primaryStage) throws Exception{


Pane root2 = FXMLLoader.load(getClass().getResource("StanSpus.fxml"));
Scene scene1 = new Scene(root2);
Stage window1 = new Stage();
window1.setTitle("Стан об'єкту");
window1.setScene(scene1);
window1.show();
}

public void setLordwin(Stage primaryStage) throws Exception{


primaryStage.close();
Pane root3 = FXMLLoader.load(getClass().getResource("Winner.fxml"));
Scene scene2 = new Scene(root3);
Stage window2 = new Stage();
window2.setTitle("Перемога");
window2.setScene(scene2);
window2.show();
}
public void setKrusawin(Stage primaryStage) throws Exception{
primaryStage.close();
Pane root3 = FXMLLoader.load(getClass().getResource("Winner_krusa.fxml"));
Scene scene2 = new Scene(root3);
Stage window2 = new Stage();
window2.setTitle("Перемога");
window2.setScene(scene2);
window2.show();
}

public void currentStatusINFO(){


int krusaCounter = 0;
int lordCounter = 0;
49

for (Spusonosech s : map.getUnits()){


if (s.getTeam().equals("Криси")){
krusaCounter++;
}
else{
lordCounter++;
}
}
if (closeFortness){
map.getCloseFortText().setText("Фортеці замкнені");
}else{
map.getCloseFortText().setText("Фортеці відчинені");
}

if (!removeFromMap){
map.getRemoveFromMapText().setText("Функція смерті вимкнена");
}else{
map.getRemoveFromMapText().setText("Функція смерті ввімкнена");
}

if (stayFortness){
map.getStayFortressText().setText("Залишатися у фортецях");
}else{
map.getStayFortressText().setText("Не залишатися у фортецях");
}

map.getKrusaCounterText().setText("Юніти криси : " + krusaCounter);


map.getLordCounterText().setText("Юніти лорда : " + lordCounter);
}

public void updateChordINFO(){


map.getKrusaCounterText().setX(scrollX + 20);
map.getKrusaCounterText().setY(scrollY + 60);

map.getLordCounterText().setX(scrollX + 20);
map.getLordCounterText().setY(scrollY + 90);

map.getCloseFortText().setX(scrollX + 20);
map.getCloseFortText().setY(scrollY + 120);

map.getRemoveFromMapText().setX(scrollX + 20);
map.getRemoveFromMapText().setY(scrollY + 150);

map.getStayFortressText().setX(scrollX + 20);
map.getStayFortressText().setY(scrollY + 180);
}

public int sum(int a,int b)


{
int sum=a+b;
return sum;
}
public int sum(int a,int b,int c)
{
int sum=a+b+c;
return sum;
}

public static void main(String[] args) {


launch(args);
}

}
50

//Map
package sample;

import javafx.scene.image.Image;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.ImagePattern;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import sample.macro.Fortness;
import sample.macro.KrusaFortress;
import sample.macro.LordFortress;
import sample.micro.Spusonosech;
import sun.misc.FpUtils;

import java.util.ArrayList;

public class Map {


private final static int rootHeight = 5000;
private final static int rootWidth = 5000;

private static final Pane root = new Pane();

private final ArrayList<Spusonosech> units;


private final ArrayList<Fortness> fortness;

private final Text krusaCounterText;


private final Text lordCounterText;

private final Text stayFortressText;


private final Text removeFromMapText;
private final Text closeFortText;

private final MiniMap miniMap;

//getters
public static Pane getRoot() {
return root;
}
public ArrayList<Spusonosech> getUnits() {
return units;
}
public ArrayList<Fortness> getFortness() {return fortness;}
public static int getRootHeight() {
return rootHeight;
}
public static int getRootWidth() {
return rootWidth;
}
public MiniMap getMiniMap() {return miniMap;}
public Text getKrusaCounterText() {
return krusaCounterText;
}
public Text getLordCounterText() {
return lordCounterText;
}
public Text getCloseFortText() {
return closeFortText;
}
public Text getRemoveFromMapText() {
return removeFromMapText;
51

}
public Text getStayFortressText() {
return stayFortressText;
}

public Map(){
root.setMinWidth(rootWidth);
root.setMinHeight(rootHeight);

Rectangle rectangle = new Rectangle(rootWidth, rootHeight);


Image img = new Image("image/map.png");
rectangle.setFill(new ImagePattern(img));
root.getChildren().add(rectangle);

krusaCounterText = new Text();


krusaCounterText.setFill(Color.WHITE);
krusaCounterText.setFont(new Font("Monaco", 24));
root.getChildren().add(krusaCounterText);

lordCounterText = new Text();


lordCounterText.setFill(Color.WHITE);
lordCounterText.setFont(new Font("Monaco", 24));
root.getChildren().add(lordCounterText);

stayFortressText = new Text();


stayFortressText.setFill(Color.WHITE);
stayFortressText.setFont(new Font("Monaco", 24));
root.getChildren().add(stayFortressText);

removeFromMapText = new Text();


removeFromMapText.setFill(Color.WHITE);
removeFromMapText.setFont(new Font("Monaco", 24));
root.getChildren().add(removeFromMapText);

//closePlanetsText
closeFortText = new Text();
closeFortText.setFill(Color.WHITE);
closeFortText.setFont(new Font("Monaco", 24));
root.getChildren().add(closeFortText);

this.units = new ArrayList<>();


this.fortness = new ArrayList<>();

this.miniMap = new MiniMap();


root.getChildren().addAll(miniMap.getPane());
}

public void addNewUnit(Spusonosech spusonosech, boolean rand){


this.units.add(spusonosech);
if (rand){
spusonosech.setChordX(Main.random.nextInt(Map.rootWidth));
spusonosech.setChordY(Main.random.nextInt (Map.rootHeight));
}
spusonosech.setmicroChord();
root.getChildren().add(spusonosech.getmicroGroup());
miniMap.addUnit(spusonosech);
}
52

public void deleteUnit(Spusonosech spusonosech){


this.miniMap.deleteUnit(spusonosech);
root.getChildren().remove(spusonosech.getmicroGroup());
this.units.remove(spusonosech);
Spusonosech.setNumberOfmicro_obj(Spusonosech.getNumberOfmicro_obj() - 1);
}

public void deleteFortness(Fortness f){


this.miniMap.deleteFort(f);
root.getChildren().remove(f.getGroup());
this.fortness.remove(f);
}
public void addFort(Fortness fort)
{
this.fortness.add(fort);
fort.set_FortChord();
root.getChildren().add(fort.getGroup());
miniMap.addFort(fort);
}

public void miniMapInFront(){


root.getChildren().remove(miniMap.getPane());
root.getChildren().add(miniMap.getPane());
}

}
//MiniMap
package sample;

import javafx.scene.Group;
import sample.macro.KrusaFortress;
import sample.macro.LordFortress;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.ImagePattern;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import sample.macro.Fortness;
import sample.micro.Spusonosech;

import java.util.HashMap;

public class MiniMap {


final static private double SCALE = 0.091;
private final Pane pane;
private final HashMap<Spusonosech, ImageView> unitsMap;
private final HashMap<Fortness, Group> fortMap;

private final Rectangle map;


private boolean mapOpacity;

private Image miniMap;


53

//getters
public Pane getPane() {
return pane;
}
public Rectangle getMap() {
return map;
}
public static double getSCALE() {
return SCALE;
}

public MiniMap() {
this.pane = new Pane();

this.pane.setMinWidth(Map.getRootWidth() * MiniMap.SCALE);
this.pane.setMinHeight(Map.getRootHeight() * MiniMap.SCALE);

unitsMap = new HashMap<>();


fortMap = new HashMap<>();

try {
miniMap = new Image("image/map.png");
} catch (Exception e) {
System.out.println("Не удалось загрузить изображение!");
}

this.mapOpacity = false;
Rectangle rectangle = new Rectangle(0, 0, pane.getMinWidth(),
pane.getMinHeight());
rectangle.setFill(new ImagePattern(miniMap));
rectangle.setStroke(Color.BLACK);
rectangle.setStrokeWidth(5);

map = new Rectangle(0, 0, Main.getSceneWidth() * MiniMap.SCALE,


Main.getSceneHeight() * MiniMap.SCALE);
map.setFill(Color.TRANSPARENT);
map.setStrokeWidth(2);
map.setStroke(Color.YELLOW);

this.pane.getChildren().addAll(rectangle, map);

pane.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {


if (event.getButton() == MouseButton.PRIMARY) {
if (!mapOpacity)
moveTo(event.getX(), event.getY());
}
if (event.getButton() == MouseButton.SECONDARY){
mapOpacity=!mapOpacity;
if (mapOpacity){
this.pane.setOpacity(0);
}else {
this.pane.setOpacity(1);
}
}
});
}

public void moveTo(double x, double y) {


if (x < map.getWidth() / 2) {
Main.getScrollPane().setHvalue(0);
54

} else if (x > pane.getWidth() - map.getWidth() / 2) {


Main.getScrollPane().setHvalue(1);
} else Main.getScrollPane().setHvalue(x / pane.getWidth());

if (y < map.getHeight() / 2) {
Main.getScrollPane().setVvalue(0);
} else if (y > pane.getHeight() - map.getHeight() / 2) {
Main.getScrollPane().setVvalue(1);
} else Main.getScrollPane().setVvalue(y / pane.getHeight());
}

public void addUnit(Spusonosech spusonosech) {


ImageView imageView;

switch (spusonosech.getLevel()) {
case "Списоносець":
imageView = new ImageView(new Image("image/spus.png"));
break;
case "Лучник":
imageView = new ImageView(new Image("image/lych.png"));
break;
default:
imageView = new ImageView(new Image("image/luch.png"));
break;
}

imageView.setLayoutX(spusonosech.getChordX() * SCALE);
imageView.setLayoutY(spusonosech.getChordY() * SCALE);
imageView.setPreserveRatio(true);
imageView.setFitHeight(200 * SCALE);
unitsMap.put(spusonosech, imageView);
pane.getChildren().add(imageView);
}

public void deleteUnit(Spusonosech s){


pane.getChildren().remove(unitsMap.get(s));
}

public void addFort(Fortness f){


ImageView imageView;
Group group;
Rectangle rectangle = new Rectangle(550 *
MiniMap.SCALE,650*MiniMap.SCALE);
if ("Фортеця Лорда Криси".equals(f.getName())) {
imageView = new ImageView(new Image("image/castle_right.png"));
imageView.setPreserveRatio(true);
rectangle.setFill(Color.GREY);
rectangle.setOpacity(0.4);
imageView.setFitHeight(f.getFort_Image().getFitHeight() *
MiniMap.SCALE);
} else {
imageView = new ImageView(new Image("image/castle.png"));
imageView.setPreserveRatio(true);
rectangle.setFill(Color.GREY);
rectangle.setOpacity(0.4);
imageView.setFitHeight(f.getFort_Image().getFitHeight() *
MiniMap.SCALE);
}
imageView.setLayoutX(f.getX() * MiniMap.SCALE);
imageView.setLayoutY(f.getY() * MiniMap.SCALE);
rectangle.setLayoutX((f.getX()) * MiniMap.SCALE);
55

rectangle.setLayoutY((f.getY()) * MiniMap.SCALE);
group = new Group(imageView, rectangle);

fortMap.put(f, group);
pane.getChildren().addAll(imageView, rectangle);
}

public void deleteFort(Fortness f){


pane.getChildren().remove(fortMap.get(f));
fortMap.remove(f);
}

public void updateMap() {


for (Spusonosech s : Main.getMap().getUnits()) {
ImageView imageView = unitsMap.get(s);
imageView.setLayoutX(s.getChordX() * MiniMap.SCALE);
imageView.setLayoutY(s.getChordY() * MiniMap.SCALE);
}
}
}
//Serialization
package sample;

import sample.macro.Fortness;
import sample.micro.Luchar;
import sample.micro.Lychnik;
import sample.micro.Spusonosech;

import java.awt.*;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;

public class Serialization {

public static void serializeNow(File file) {


XMLEncoder encoder;
try {
encoder = new XMLEncoder(new BufferedOutputStream(new
FileOutputStream(file)));
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("units", Main.getMap().getUnits());
hashMap.put("fortness",Main.getMap().getFortness());
encoder.writeObject(hashMap);
encoder.close();
} catch (FileNotFoundException e) {
System.out.println("Помилка відкриття файлу");
}
}
public static void deserializeNow(File file){
XMLDecoder decoder;
try {
decoder=new XMLDecoder(new BufferedInputStream(new
FileInputStream(file)));

for (int i = 0; i<Main.getMap().getUnits().size(); i++){


Spusonosech s = Main.getMap().getUnits().get(i--);
Main.getMap().deleteUnit(s);
}
for (int i = 0; i<Main.getMap().getFortness().size(); i++){
Fortness fort = Main.getMap().getFortness().get(i--);
56

Main.getMap().deleteFortness(fort);
}
HashMap<String, Object> hashMap = (HashMap<String,
Object>)decoder.readObject();

for (Fortness f: (ArrayList<Fortness>)hashMap.get("fortness")){


Main.getMap().addFort(f);
}
for (Spusonosech s:(ArrayList<Spusonosech>)hashMap.get("units")){
if (s.getTeam().equals("Лорда")){
Main.getMap().addNewUnit(s, false);
}
if (s.getTeam().equals("Криси")){
Main.getMap().addNewUnit(s,false);
}
Main.getMap().miniMapInFront();

}
decoder.close();
} catch (FileNotFoundException e) {
System.out.println("Помилка відкриття файлу");
}
}
}
//Spusonosech
package sample.micro;

import javafx.scene.Group;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import sample.Main;
import sample.Map;
import sample.macro.Fortness;
import sample.macro.KrusaFortress;

import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
import java.util.Scanner;

import static sample.Main.*;

public class Spusonosech implements Comparable<Spusonosech>,Cloneable


{
//variables
private String name;
private String team;
private String level;
private double hp;
private int speed;
private double damage;
private int strong;
private int armor;
private int food;
private double[] salary;
57

private boolean alive;


protected boolean isActive;

protected double chordX;


protected double chordY;

protected ImageView microImage;


protected Group microGroup;
protected Rectangle rectActive;
protected Line lineHealth;
protected Line lineDamage;
protected Text nAme;
protected int homeX;
protected int homeY;

protected byte auto_move;

protected boolean isLord= false;

protected boolean isCatch = false;

protected static int numberOfmicro_obj = 0;

//******************************getters and
setters*************************************************//
public String getName(){return name;} public void setName(String nm){name=nm;}
public String getTeam(){return team;} public void setTeam(String
tem){team=tem;}
public String getLevel(){return level;} public void setLevel(String
lvl){level=lvl;}
public double getDamage(){return damage;} public void setDamage(double
dmg){damage=dmg;}
public double getHp(){return hp;} public void setHp(double h){hp=h;}
public int getSpeed(){return speed;} public void setSpeed(int
spd){this.speed=spd;}
public int getStrong(){return strong;} public void setStrong(int s){strong=s;}
public int getArmor(){return armor;} public void setArmor(int ar){armor=ar;}
public int getFood(){return food;} public void setFood(int f){food=f;}
public boolean getAlive(){return alive;} public void setAlive(boolean
al){alive=al;}
public Group getmicroGroup() { return microGroup; }
public double getChordX() { return chordX; } public void setChordX(double
x){this.chordX=x;}
public double getChordY() {
return chordY;
} public void setChordY(double y){this.chordY=y;}
public boolean getIsActive(){return isActive;} public void setActive()
{this.isActive = !this.isActive; }
public ImageView getMicroImage(){return microImage;}
public static int getNumberOfmicro_obj(){return numberOfmicro_obj;}
public Text getnAme(){return nAme;}
public static void setNumberOfmicro_obj(int number) {
Spusonosech.numberOfmicro_obj = number;}
public int getHomeX(){return homeX;} public void setHomeX(int
x){this.homeX=x;}
public int getHomeY(){return homeY;} public void setHomeY(int
y){this.homeY=y;}
public boolean isCatch() {
return isCatch;
}
public boolean isLord() {
return isLord;
}
58

public void setLord(boolean l) {


isLord = l;
}

{
speed=4;
}

//*****************************methods********************************************
********//
//1.
public void setSalaryhistory(double itm)
{
if (salary == null) salary = new double[1];
else salary = Arrays.copyOf(salary, salary.length + 1);
salary[salary.length - 1] = itm;
}
public double equalSalary()
{
if (salary == null) return 0;
else{
double sum=0,c=salary.length;
for (int i=0;i<salary.length;i++)
{
sum+=salary[i];
}
return sum/c;
}
}
/*2.*/public void training(){this.strong+=5;}
/*3.*/public void eat(){this.food+=10;}
/*4.*/public static void fight(Spusonosech sp1,Spusonosech sp2) throws
InterruptedException
{
if(!sp1.alive)
{
System.out.printf("Бійка не можлива! Персонаж мертвий!\n",sp1);
return;
}
if(!sp2.alive)
{
System.out.printf("Бійка не можлива! Персонаж мертвий!\n",sp2);
return;
}
System.out.println("Здоров'я "+sp1.getName()+" = "+sp1.getHp()+"," +
"Здоров'я "+sp2.getName()+" = "+sp2.getHp());
while (true)
{
Thread.sleep(135);
sp1.hp-=sp2.damage-sp1.armor*0.1;
if(sp1.hp<=0)
{
System.out.printf("%s наніс %s - %7.2f шкоду\n%s загинув! %s
переміг!\n\n",sp2.name,sp1.name,sp2.damage-sp1.armor*0.1,sp1.name,sp2.name);
sp1.alive=false;
sp1.hp=0;
break;
}
else {
System.out.printf("%s наніс %s - %7.2f урон DMG\n в %s залишається
%7.2f\n",sp2.name,sp1.name,sp2.damage-sp1.armor*0.1,sp1.name,sp1.hp);
59

}
System.out.println();
Thread.sleep(135);
sp2.hp-=sp1.damage-sp2.armor*0.1;
if(sp2.hp<=0)
{
System.out.printf("%s наніс %s - %7.2f шкоду\n%s загинув! %s
переміг!\n\n",sp1.name,sp2.name,sp1.damage-sp2.armor*0.1,sp2.name,sp1.name);
sp2.alive=false;
sp2.hp=0;
break;
}
else {
System.out.printf("%s наніс %s - %7.2f урон DMG\n в %s залишається
%7.2f\n",sp1.name,sp2.name,sp1.damage-sp2.armor*0.1,sp2.name,sp2.hp);
}
}
}
public String setRandteam()
{
String s1="Криси",s2="Лорда";
int v=Main.random.nextInt(2);
if(v==1){return s1;}
else return s2;
}

//*****************************constructors***************************************
*******//
//constructor without arguments
public Spusonosech()
{
numberOfmicro_obj++;

this.name=Main.getNamesArray()[Main.random.nextInt(Main.getNamesArray().length)];
this.team=setRandteam();
this.alive=true;
this.food=67;
salary=new double[0];
//this.speed=4;
this.isActive=false;
Main.setParam(this);
if(this.team.equals("Криси"))
{this.homeX=500;this.homeY=4100;}
else {this.homeX=4100;this.homeY=270;}

try{this.microImage=new ImageView("image/spus.png");}catch (Exception e){


System.out.println("Eror with load spus_img");}
this.microImage.setFitHeight(100);
this.microImage.setPreserveRatio(true);

this.nAme=new Text(name);
this.nAme.setFont(new Font("Muna", 20));
this.nAme.setFill(Color.WHITE);

this.rectActive = new Rectangle(75,100);


this.rectActive.setStrokeWidth(3);
this.rectActive.setStroke(Color.YELLOW);
this.rectActive.setFill(Color.TRANSPARENT);

this.lineHealth = new Line();


this.lineHealth.setStroke(Color.GREEN);
this.lineHealth.setStrokeWidth(5);
60

this.lineDamage = new Line();


this.lineDamage.setStroke(Color.RED);
this.lineDamage.setStrokeWidth(5);

this.auto_move = (byte) Main.random.nextInt(8);

this.microGroup=new
Group(microImage,this.nAme,rectActive,lineHealth,lineDamage);

microGroup.addEventHandler(MouseEvent.MOUSE_CLICKED, event ->{


if (event.getButton() == MouseButton.PRIMARY){
this.isActive = !this.isActive;

}
// if(event.getButton() == MouseButton.SECONDARY){
// System.out.println("Ім'я: " + this.getnAme().getText());
// System.out.println("Рівень" + this.getLevel());
// System.out.println("Сторона: " + this.getTeam());
// System.out.println("Активований: " + this.getIsActive());
// System.out.println("Рівень життя: " + this.getHp());
// System.out.println("Рівень сили: " + this.getDamage());
// System.out.println("Поточна швидкість: " + this.getSpeed());
// System.out.println("Координати по Х" + this.getChordX());
// System.out.println("Координати по Y" + this.getChordY());
// }
} );
}
//constructor
public Spusonosech(String nm, String team, int fd, boolean isActive)
{
numberOfmicro_obj++;
this.name=nm;
this.team=team;
this.alive=true;
this.food=fd;
salary=new double[0];
this.isActive=isActive;
Main.setParam(this);

if(this.getTeam().equals("Криси"))
{this.homeX=500;this.homeY=4100;}
else {this.homeX=4100;this.homeY=270;}
try{this.microImage=new ImageView("image/spus.png");}catch (Exception e){
System.out.println("Eror with load spus_img");}
this.microImage.setFitHeight(100);
this.microImage.setPreserveRatio(true);

this.nAme=new Text(name);
this.nAme.setFont(new Font("Muna", 20));
this.nAme.setFill(Color.WHITE);

this.rectActive = new Rectangle(75,100);


this.rectActive.setStrokeWidth(3);
this.rectActive.setStroke(Color.YELLOW);
this.rectActive.setFill(Color.TRANSPARENT);

this.lineHealth = new Line();


this.lineHealth.setStroke(Color.GREEN);
this.lineHealth.setStrokeWidth(5);

this.lineDamage = new Line();


this.lineDamage.setStroke(Color.RED);
this.lineDamage.setStrokeWidth(5);
61

this.auto_move = (byte) Main.random.nextInt(8);

this.microGroup=new
Group(microImage,this.nAme,rectActive,lineHealth,lineDamage);

microGroup.addEventHandler(MouseEvent.MOUSE_CLICKED, event ->{


if (event.getButton() == MouseButton.PRIMARY){
this.isActive = !this.isActive;

}
if(event.getButton() == MouseButton.SECONDARY){
System.out.println("Ім'я: " + this.getnAme().getText());
System.out.println("Рівень" + this.getLevel());
System.out.println("Сторона: " + this.getTeam());
System.out.println("Активований: " + this.getIsActive());
System.out.println("Рівень життя: " + this.getHp());
System.out.println("Рівень сили: " + this.getDamage());
System.out.println("Поточна швидкість: " + this.getSpeed());
System.out.println("Координати по Х" + this.getChordX());
System.out.println("Координати по Y" + this.getChordY());
}

} );
}
//делегування конструкторів
public Spusonosech(String nm, String team, int fd, boolean isActive, double
chordX, double chordY)
{
this(nm, team, fd, isActive);
this.chordY=chordY;
this.chordX=chordX;
Main.setParam(this);
}

public void setXY(double x,double y)


{
this.chordX=x;
this.chordY=y;
}
//********************************move ang
graphic***************************************//
public void setmicroChord(){
this.microImage.setX(this.chordX);
this.microImage.setY(this.chordY);
this.lineHealth.setStartX(this.chordX);
this.lineHealth.setStartY(this.chordY-20);
this.lineHealth.setEndX(this.chordX+this.hp);
this.lineHealth.setEndY(this.chordY-20);
this.lineDamage.setStartX(this.chordX);
this.lineDamage.setStartY(this.chordY-10);
this.lineDamage.setEndX(this.chordX + (this.damage));
this.lineDamage.setEndY(this.chordY-10);
this.nAme.setX(this.chordX);
this.nAme.setY(this.chordY-30);
this.rectActive.setX(this.chordX);
this.rectActive.setY(this.chordY);
if (this.isActive){
rectActive.setOpacity(1);
}
else {
rectActive.setOpacity(0);
}
62

public void up(int delta){


this.chordY -= speed + delta;
this.setmicroChord();
}
public void down(int delta){
this.chordY += speed + delta;
this.setmicroChord();
}
public void left(int delta){
this.chordX -= speed + delta;
this.setmicroChord();
}
public void right(int delta){
this.chordX += speed + delta;
this.setmicroChord();
}
public void moveToFort(){
if (!this.isActive){

if(this.getTeam().equals("Криси")){this.setHomeX(500);this.setHomeY(3100);}
else{this.setHomeX(4100);this.setHomeY(270);}
if (homeX + 40 < this.chordX){
this.chordX -= this.speed + Main.getMoveSpeed();
}
if (homeX + 40 > this.chordX){
this.chordX += this.speed + Main.getMoveSpeed();
}
if (homeX + 40 > this.chordY){
this.chordY += this.speed + Main.getMoveSpeed();
}
if (homeX + 40 < this.chordY){
this.chordY -= this.speed + Main.getMoveSpeed();
}
}
}
public void healthUpLord(){
if (this.team.equals("Лорда")){
this.microGroup.setOpacity(0);
if (this.hp < 10){
this.hp+=4;
}
}
}
public void healthUpKrusa(){
if (this.team.equals("Криси")){
this.microGroup.setOpacity(0);
if (this.hp <10){
this.hp+=4;
}
}
}
public void auto_move(){
this.microGroup.setOpacity(1);
if (!this.isActive){
switch (this.auto_move){
case 0:
this.chordY -= this.speed + Main.getMoveSpeed();
break;
case 1:
this.chordY -= this.speed + Main.getMoveSpeed();
63

this.chordX += this.speed + Main.getMoveSpeed();


break;
case 2:
this.chordX += this.speed + Main.getMoveSpeed();
break;
case 3:
this.chordX += this.speed + Main.getMoveSpeed();
this.chordY += this.speed + Main.getMoveSpeed();
break;
case 4:
this.chordY += this.speed + Main.getMoveSpeed();
break;
case 5:
this.chordY += this.speed + Main.getMoveSpeed();
this.chordX -= this.speed + Main.getMoveSpeed();
break;
case 6:
this.chordX -= this.speed + Main.getMoveSpeed();
break;
case 7:
this.chordX -= this.speed + Main.getMoveSpeed();
this.chordY -= this.speed + Main.getMoveSpeed();
break;
}
if (this.microImage.getX() + this.microImage.getFitWidth() + 100 >=
Map.getRoot().getWidth() - this.microImage.getFitWidth()){
this.auto_move = (byte) (Main.random.nextInt(3) + 5);
}else if (this.microImage.getX() <= 0){
this.auto_move = (byte) (Main.random.nextInt(3) + 1);
}else if (this.microImage.getY() <= 0){
this.auto_move = (byte) (Main.random.nextInt(3) + 3);
}else if (this.microImage.getY() + this.microImage.getFitHeight() >=
Map.getRoot().getHeight()){
this.auto_move = (byte) (Main.random.nextInt(2));
}
}
}
//functions
//print obj
public void print(){ System.out.println(this); }
//dinamic polim

public static void say_to_child() { System.out.println("Я можу говорити"); }

public static void inetactive_spus_fort(Fortness fort, Spusonosech s) {


if (s.getHp() >= 0 && fort.getHp() >= 0) {
s.setHp(s.getHp() - fort.getDamage());
}
if (fort.getHp() >= 0 && s.getHp() >= 0) {
fort.setHp(fort.getHp() - (int) s.getDamage());
}
fort.set_FortChord();
Main.getMap().deleteUnit(s);

public static void inetactive_spus(Spusonosech s1, Spusonosech s2){

if (!s1.getTeam().equals(s2.getTeam())){
if (s1.getHp() >= 0 && s2.getHp() >= 0){
s1.setHp(s1.getHp() - s2.getDamage());
}
if (s2.getHp() >= 0 && s1.getHp() >= 0){
64

s2.setHp(s2.getHp() - s1.getDamage());
}
}
if(s1.getHp()<=0){s1.setHp(0);return;}
if(s2.getHp()<=0){s2.setHp(0);return;}
}

public void moveLeft(double x, double y, Spusonosech s){


this.chordX = x;
this.chordY = y;
//this.shipImage.setRotate(270);

for (int i = 0; i<Main.getMap().getUnits().size(); i++){


if (Main.getMap().getUnits().get(i) == s){
Main.getMap().getUnits().remove(i);
}
}
lychCounter++;
}
public void moveDown(double x, double y, Spusonosech s){
this.chordX = x;
this.chordY = y;
//this.shipImage.setRotate(180);

for (int i = 0; i<Main.getMap().getUnits().size(); i++){


if (Main.getMap().getUnits().get(i) == s){
Main.getMap().getUnits().remove(i);
}
}
spusCounter++;
}
public void moveUP(double x, double y, Spusonosech s){
this.chordX = x;
this.chordY = y;

for (int i = 0; i<Main.getMap().getUnits().size(); i++){


if (Main.getMap().getUnits().get(i) == s){
Main.getMap().getUnits().remove(i);
}
}
luchCounter++;
}
@Override
public String toString() {
return "Мікрооб'єкт{" +
"Ім'я='" + name + '\'' +
//", Команда ='" + team + '\'' +
", Рівень='" + level + '\'' +
", Здоров'я=" + hp +
", Урон=" + damage +
", Сила=" + strong +
", Броня=" + armor +
", Ситність=" + food +
", Сер.зар.= " + this.equalSalary() +
" Array:" + Arrays.toString(salary) +
//", Існує =" + alive +
'}';
}
public void
setParametersforSpusonosech(){this.armor=2;this.damage=10.0;this.hp=50;this.level=
"Списоносець";this.setSalaryhistory(50);this.strong=30;}
public void
setParametersforLychnik(){this.armor=3;this.damage=20.0;this.hp=75;this.level="Луч
65

ник";this.setSalaryhistory(100);this.strong=60;}
public void
setParametersforLuchar(){this.armor=8;this.damage=30.0;this.hp=100;this.level="Лиц
ар";this.setSalaryhistory(150);this.strong=90;}

public static Comparator <Spusonosech> SulaComparator=new


Comparator<Spusonosech>() {
@Override
public int compare(Spusonosech o1, Spusonosech o2) {
if(o1.strong<o2.strong) return 1;
if(o1.strong>o2.strong) return -1;
return 0;
}
};
public static Comparator<Spusonosech> HPComparator = new
Comparator<Spusonosech>() {
@Override
public int compare(Spusonosech o1, Spusonosech o2) {
if (o1.hp < o2.hp) return -1;
if (o1.hp > o2.hp) return 1;
return 0;
}
};
@Override
public Spusonosech clone() throws CloneNotSupportedException
{
Spusonosech tmp=(Spusonosech)super.clone();
if(this.level.equals("Списоносець"))
{
Spusonosech spusonosech=new Spusonosech(tmp.getName()+"_clone",
tmp.getTeam(),tmp.getFood(),tmp.getIsActive());spusonosech.chordX=tmp.getChordX()+
10;spusonosech.chordY=tmp.getChordY();
if(this.salary==null){tmp.salary=new double[0];}
else tmp.salary=Arrays.copyOf(this.salary,this.salary.length);
this.setActive();spusonosech.setActive();
return spusonosech;
}
else if (this.level.equals("Лучник"))
{
Lychnik lychnik=new Lychnik(tmp.getName()+"_clone",
tmp.getTeam(),tmp.getFood(),tmp.getIsActive());lychnik.chordX=tmp.getChordX()+10;l
ychnik.chordY=tmp.getChordY();
if(this.salary==null){tmp.salary=new double[0];}
else tmp.salary=Arrays.copyOf(this.salary,this.salary.length);
this.setActive();lychnik.setActive();
return lychnik;
}
else { Luchar luchar=new Luchar(tmp.getName()+"_clone",
tmp.getTeam(),tmp.getFood(),tmp.getIsActive());luchar.chordX=tmp.getChordX()+10;lu
char.chordY=tmp.getChordY();
if(this.salary==null){tmp.salary=new double[0];}
else tmp.salary=Arrays.copyOf(this.salary,this.salary.length);
this.setActive();luchar.setActive();
return luchar;
}
}
@Override
public int compareTo(Spusonosech s){return this.name.compareTo(s.name);}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Spusonosech s = (Spusonosech) o;
66

return speed == s.speed &&


hp == s.hp &&
damage == s.damage;
}

}
//Lychnik
package sample.micro;

import javafx.scene.Group;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import sample.Main;

public class Lychnik extends Spusonosech


{
//клас лучник
public Lychnik(String nm, String team, int fd, boolean isAct)
{
super(nm, team,fd,isAct);
numberOfmicro_obj++;
Main.setParam(this);
if(this.getTeam().equals("Криси"))
{this.homeX=500;this.homeY=4100;}
else {this.homeX=4100;this.homeY=270;}
try{this.microImage=new ImageView("image/lych.png");}catch (Exception e){
System.out.println("Eror with load spus_img");}
this.microImage.setFitHeight(100);
this.microImage.setPreserveRatio(true);

this.nAme=new Text(this.getName());
this.nAme.setFont(new Font("Muna", 20));
this.nAme.setFill(Color.WHITE);

this.rectActive = new Rectangle(75,100);


this.rectActive.setStrokeWidth(3);
this.rectActive.setStroke(Color.YELLOW);
this.rectActive.setFill(Color.TRANSPARENT);

this.lineHealth = new Line();


this.lineHealth.setStroke(Color.GREEN);
this.lineHealth.setStrokeWidth(5);

this.lineDamage = new Line();


this.lineDamage.setStroke(Color.RED);
this.lineDamage.setStrokeWidth(5);

this.auto_move = (byte) Main.random.nextInt(8);

this.microGroup=new
Group(microImage,this.nAme,rectActive,lineHealth,lineDamage);

microGroup.addEventHandler(MouseEvent.MOUSE_CLICKED, event ->{


if (event.getButton() == MouseButton.PRIMARY){
this.isActive = !this.isActive;
67

}
if(event.getButton() == MouseButton.SECONDARY){
System.out.println("Ім'я: " + this.getnAme().getText());
System.out.println("Рівень" + this.getLevel());
System.out.println("Сторона: " + this.getTeam());
System.out.println("Активований: " + this.getIsActive());
System.out.println("Рівень життя: " + this.getHp());
System.out.println("Рівень сили: " + this.getDamage());
System.out.println("Поточна швидкість: " + this.getSpeed());
System.out.println("Координати по Х" + this.getChordX());
System.out.println("Координати по Y" + this.getChordY());
}
} );
}

{
this.setSpeed(5);
}
public Lychnik()
{
numberOfmicro_obj++;

this.setName(Main.getNamesArray()[Main.random.nextInt(Main.getNamesArray().length)
]);
this.setTeam(setRandteam());
this.setAlive(true);
this.setFood(67);
this.isActive=false;
Main.setParam(this);

if (this.getTeam().equals("Криси")){
this.homeX = 500;
this.homeY = 4100;
}else{
this.homeX = 270;
this.homeY = 4100;
}
try{this.microImage=new ImageView("image/lych.png");}catch (Exception e){
System.out.println("Eror with load lych_img");}
this.microImage.setFitHeight(100);
this.microImage.setPreserveRatio(true);

this.nAme=new Text(this.getName());
this.nAme.setFont(new Font("Muna", 20));
this.nAme.setFill(Color.WHITE);

this.rectActive = new Rectangle(75,100);


this.rectActive.setStrokeWidth(3);
this.rectActive.setStroke(Color.YELLOW);
this.rectActive.setFill(Color.TRANSPARENT);

this.lineHealth = new Line();


this.lineHealth.setStroke(Color.GREEN);
this.lineHealth.setStrokeWidth(5);

this.lineDamage = new Line();


this.lineDamage.setStroke(Color.RED);
this.lineDamage.setStrokeWidth(5);

this.auto_move = (byte) Main.random.nextInt(8);

this.microGroup=new
Group(microImage,this.nAme,rectActive,lineHealth,lineDamage);
68

microGroup.addEventHandler(MouseEvent.MOUSE_CLICKED, event ->{


if (event.getButton() == MouseButton.PRIMARY){
this.isActive = !this.isActive;

}
// if(event.getButton() == MouseButton.SECONDARY){
// System.out.println("Ім'я: " + this.getnAme().getText());
// System.out.println("Рівень" + this.getLevel());
// System.out.println("Сторона: " + this.getTeam());
// System.out.println("Активований: " + this.getIsActive());
// System.out.println("Рівень життя: " + this.getHp());
// System.out.println("Рівень сили: " + this.getDamage());
// System.out.println("Поточна швидкість: " + this.getSpeed());
// System.out.println("Координати по Х" + this.getChordX());
// System.out.println("Координати по Y" + this.getChordY());
// }
} );
}
public Lychnik(String nm, String team, int fd, boolean isActive, double
chordX, double chordY)
{
this(nm, team, fd, isActive);
this.chordY=chordY;
this.chordX=chordX;
}

public void print()


{ System.out.println(this); }
//клас лучник
@Override
public double equalSalary()
{
return super.equalSalary()+100;
}

//динамічний поліморфізм
//клас Лучник
public static void say_to_child()
{
System.out.println("Лучник може говорити");
}

}
//Luchar
package sample.micro;

import javafx.scene.Group;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import sample.Main;

public class Luchar extends Lychnik


{

public Luchar(String nm, String team, int fd, boolean isAct)


{ super(nm, team,fd,isAct);
69

numberOfmicro_obj++;
Main.setParam(this);
if(this.getTeam().equals("Криси"))
{this.homeX=500;this.homeY=4100;}
else {this.homeX=4100;this.homeY=270;}
try{this.microImage=new ImageView("image/luch.png");}catch (Exception e){
System.out.println("Eror with load spus_img");}
this.microImage.setFitHeight(100);
this.microImage.setPreserveRatio(true);

this.nAme=new Text(this.getName());
this.nAme.setFont(new Font("Muna", 20));
this.nAme.setFill(Color.WHITE);

this.rectActive = new Rectangle(75,100);


this.rectActive.setStrokeWidth(3);
this.rectActive.setStroke(Color.YELLOW);
this.rectActive.setFill(Color.TRANSPARENT);

this.lineHealth = new Line();


this.lineHealth.setStroke(Color.GREEN);
this.lineHealth.setStrokeWidth(5);

this.lineDamage = new Line();


this.lineDamage.setStroke(Color.RED);
this.lineDamage.setStrokeWidth(5);

this.auto_move = (byte) Main.random.nextInt(8);

this.microGroup=new
Group(microImage,this.nAme,rectActive,lineHealth,lineDamage);

microGroup.addEventHandler(MouseEvent.MOUSE_CLICKED, event ->{


if (event.getButton() == MouseButton.PRIMARY){
this.isActive = !this.isActive;

}
if(event.getButton() == MouseButton.SECONDARY){
System.out.println("Ім'я: " + this.getnAme().getText());
System.out.println("Рівень" + this.getLevel());
System.out.println("Сторона: " + this.getTeam());
System.out.println("Активований: " + this.getIsActive());
System.out.println("Рівень життя: " + this.getHp());
System.out.println("Рівень сили: " + this.getDamage());
System.out.println("Поточна швидкість: " + this.getSpeed());
System.out.println("Координати по Х" + this.getChordX());
System.out.println("Координати по Y" + this.getChordY());
}
} );}

{
this.setSpeed(6);
}
public Luchar()
{
numberOfmicro_obj++;

this.setName(Main.getNamesArray()[Main.random.nextInt(Main.getNamesArray().length)
]);
this.setTeam(setRandteam());
this.setAlive(true);
this.setFood(67);
this.isActive=false;
70

Main.setParam(this);

if (this.getTeam().equals("Криси")){
this.setHomeX(500);
this.setHomeY(4100);
}else{
this.setHomeX(270);
this.setHomeY(4100);
}
try{this.microImage=new ImageView("image/luch.png");}catch (Exception e){
System.out.println("Eror with load luch_img");}
this.microImage.setFitHeight(100);
this.microImage.setPreserveRatio(true);

this.nAme=new Text(this.getName());
this.nAme.setFont(new Font("Muna", 20));
this.nAme.setFill(Color.WHITE);

this.rectActive = new Rectangle(75,100);


this.rectActive.setStrokeWidth(3);
this.rectActive.setStroke(Color.YELLOW);
this.rectActive.setFill(Color.TRANSPARENT);

this.lineHealth = new Line();


this.lineHealth.setStroke(Color.GREEN);
this.lineHealth.setStrokeWidth(5);

this.lineDamage = new Line();


this.lineDamage.setStroke(Color.RED);
this.lineDamage.setStrokeWidth(5);

this.auto_move = (byte) Main.random.nextInt(8);

this.microGroup=new
Group(microImage,this.nAme,rectActive,lineHealth,lineDamage);

microGroup.addEventHandler(MouseEvent.MOUSE_CLICKED, event ->{


if (event.getButton() == MouseButton.PRIMARY){
this.isActive = !this.isActive;

}
// if(event.getButton() == MouseButton.SECONDARY){
// System.out.println("Ім'я: " + this.getnAme().getText());
// System.out.println("Рівень" + this.getLevel());
// System.out.println("Сторона: " + this.getTeam());
// System.out.println("Активований: " + this.getIsActive());
// System.out.println("Рівень життя: " + this.getHp());
// System.out.println("Рівень сили: " + this.getDamage());
// System.out.println("Поточна швидкість: " + this.getSpeed());
// System.out.println("Координати по Х" + this.getChordX());
// System.out.println("Координати по Y" + this.getChordY());
// }
} );
}
public Luchar(String nm, String team, int fd, boolean isActive, double chordX,
double chordY)
{
this(nm, team, fd, isActive);
this.chordY=chordY;
this.chordX=chordX;
try{this.microImage=new ImageView("image/luch.png");}catch (Exception e){
System.out.println("Eror with load luch_img");}
this.microImage.setFitHeight(100);
71

this.microImage.setPreserveRatio(true);
}
public void print()
{ System.out.println(this); }

@Override
public double equalSalary()
{
return super.equalSalary()*3;
}

//динамічний поліморфізм
//клас Лицар
public static void say_to_child()
{
System.out.println("Лицар може говорити");
}
}
//Fortness
package sample.macro;

import javafx.scene.Group;
import javafx.scene.image.ImageView;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;

public abstract class Fortness


{
private int hp;
private int damage;
private static String name_lord;
private static String name_krusa;

protected double chordX;


protected double chordY;

protected ImageView Fort_Image;

protected Text FortName;


protected Text FortName1;
protected Rectangle activeZone;
protected Group group;

protected Line lineHealth;


protected Line lineDamage;

protected Text counterText;

public double getX(){return chordX;}


public double getY(){return chordY;}
public int getDamage(){return damage;}
public void setDamage(int damage){this.damage=damage;}
public void setNameKrusa(String name){this.name_krusa=name;}
public void setNameLOrd(String name){this.name_lord=name;}
public String getName_lord(){return name_lord;}
public String getName_krusa(){return name_krusa;}
public void setHp(int h){hp=h;}
public ImageView getFort_Image(){return Fort_Image;}
public int getHp(){return hp;}
public Text getFortName1(){return this.FortName1;}
72

public String getName(){


String s=String.valueOf(this.getFortName1());
if(s.equals("Text[text=\"Фортеця Лорда Христоносця\", x=0.0, y=0.0,
alignment=LEFT, origin=BASELINE, boundsType=LOGICAL, font=Font[name=System
Regular, family=System, style=Regular, size=15.0], fontSmoothingType=GRAY,
fill=0x000000ff]"))return "Фортеця Лорда Христоносця";
else return "Фортеця Лорда Криси";
}
public Group getGroup() {
return group;
}
public void setCounterKrusa(int counter) {this.counterText.setText("Всередині:
" + counter); }
public void setCounterLord(int counter) {
this.counterText.setText("Всередині: " + counter);
}
public abstract void set_FortChord();
}
//KrusaFortness
package sample.macro;

import javafx.scene.Group;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import sample.micro.Spusonosech;

import java.util.LinkedList;

public class KrusaFortress extends Fortness


{
public static LinkedList<Spusonosech> krusa;
public KrusaFortress()
{
krusa=new LinkedList<>();
this.setHp(1000);
this.setDamage(40);
this.setNameKrusa("Фортеця Лорда Криси");
this.chordX=500;
this.chordY=500;
this.activeZone=new Rectangle(550,650);
this.activeZone.setFill(Color.GREY);
this.activeZone.setOpacity(0.3);
this.Fort_Image=new ImageView(new Image("image/castle_right.png"));
this.Fort_Image.setPreserveRatio(true);
this.Fort_Image.setFitHeight(450);
this.FortName1=new Text("Фортеця Лорда Криси");
this.FortName=new Text("Фортеця Лорда Криси");
this.FortName.setFont(new Font("Monaco", 30));
this.FortName.setFill(Color.WHITE);

this.lineHealth=new Line();
this.lineHealth.setStroke(Color.GREEN);
this.lineHealth.setStrokeWidth(20);

this.lineDamage = new Line();


this.lineDamage.setStroke(Color.RED);
73

this.lineDamage.setStrokeWidth(20);

counterText = new Text("Всередині: ");


counterText.setFont(new Font("Monaco", 30));
counterText.setFill(Color.WHITE);

this.group=new
Group(activeZone,Fort_Image,this.FortName,lineHealth,lineDamage,counterText);
}

@Override
public void set_FortChord()
{
this.Fort_Image.setX(this.chordX);
this.Fort_Image.setY(this.chordY);

this.FortName.setX(this.chordX-20);
this.FortName.setY(this.chordY-80);

this.activeZone.setLayoutX(this.chordX-20);
this.activeZone.setLayoutY(this.chordY-120) ;

this.lineHealth.setStartX(this.chordX);
this.lineHealth.setStartY(this.chordY-50);
this.lineHealth.setEndX(this.chordX+this.getHp()/2);
this.lineHealth.setEndY(this.chordY-50);

this.lineDamage.setStartX(this.chordX-10);
this.lineDamage.setStartY(this.chordY-20);
this.lineDamage.setEndX(this.chordX + this.getDamage()*10);
this.lineDamage.setEndY(this.chordY-20);
counterText.setX(this.chordX-20);
counterText.setY(this.chordY + 40);
}
}
//LordFortness
package sample.macro;

import javafx.scene.Group;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import sample.micro.Spusonosech;

import java.util.LinkedList;

public class LordFortress extends Fortness


{
public static LinkedList<Spusonosech> lord;

public LordFortress()
{
this.setNameLOrd("Фортеця Лорда Христоносця");
lord=new LinkedList<>();
this.setHp(1000);
this.setDamage(40);
74

this.chordX=4000;
this.chordY=4000;
this.activeZone=new Rectangle(550,650);
this.activeZone.setFill(Color.GREY);
this.activeZone.setOpacity(0.3);
Fort_Image=new ImageView(new Image("image/castle.png"));
Fort_Image.setPreserveRatio(true);
Fort_Image.setFitHeight(450);
this.FortName1=new Text("Фортеця Лорда Христоносця");
this.FortName=new Text("Фортеця Лорда Христоносця");
this.FortName.setFont(new Font("Monaco", 30));
this.FortName.setFill(Color.WHITE);

this.lineHealth=new Line();
this.lineHealth.setStroke(Color.GREEN);
this.lineHealth.setStrokeWidth(20);

this.lineDamage = new Line();


this.lineDamage.setStroke(Color.RED);
this.lineDamage.setStrokeWidth(20);

counterText= new Text("Всередині: ");


counterText.setFont(new Font("Monaco", 30));
counterText.setFill(Color.WHITE);

this.group=new
Group(activeZone,Fort_Image,this.FortName,lineHealth,lineDamage,counterText);
}
@Override
public void set_FortChord()
{
this.Fort_Image.setX(this.chordX);
this.Fort_Image.setY(this.chordY);

this.FortName.setX(this.chordX-20);
this.FortName.setY(this.chordY-80);

this.activeZone.setLayoutX(this.chordX-20);
this.activeZone.setLayoutY(this.chordY-120) ;

this.lineHealth.setStartX(this.chordX);
this.lineHealth.setStartY(this.chordY-50);
this.lineHealth.setEndX(this.chordX+this.getHp()/2);
this.lineHealth.setEndY(this.chordY-50);

this.lineDamage.setStartX(this.chordX-10);
this.lineDamage.setStartY(this.chordY-20);
this.lineDamage.setEndX(this.chordX + this.getDamage()*10);
this.lineDamage.setEndY(this.chordY-20);

counterText.setX(this.chordX-20);
counterText.setY(this.chordY + 40);
}
}

You might also like