День 5: Розробка 2D ігор: Прототипування

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

pic

Давайте поринемо у створення 2D гри! Але спершу розпочнемо з прототипування. Я почну з створення об'єкта куба і назву його Player, із суцільним чорним фоном, щоб задати сцену.

pic

Наступним кроком ми налаштуємо співвідношення сторін на 16:9, щоб наша гра відображалась однаково на різних розмірах екранів і роздільних здатностях.

pic

Використовуючи C#, я призначу скрипт для нашого об'єкта гравця і розміщу його в координатах (0, 0, 0) для центру початкової точки.

pic

Звертаючись до офіційної документації Unity, ми дізналися, як використовувати властивість transform. У цьому прикладі я створив новий Vector3, щоб наш гравець рухався вліво.

pic

Для реалізації реального руху ми використовуємо Vector3.[direction] * [speed] * Time.deltaTime. Це гарантує, що об'єкт рухається з постійною швидкістю в метрах на секунду, незалежно від варіацій кадрової частоти.

pic

Використовуючи функцію Unity Input.GetAxis, ми можемо створити змінні для горизонтального та вертикального вводу, які дозволяють гравцеві керувати рухом за допомогою стрілок або WASD. Горизонтальна ось рухає гравця вліво і вправо, а вертикальна — вгору та вниз.

pic

pic

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

pic

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

pic

Порада професіонала: 🛡️ Mathf.Clamp утримує значення в межах визначеного діапазону, запобігаючи помилкам виходу за межі та підтримуючи контрольований рух.

Порада професіонала: ✏️ Написання псевдокоду та чистого коду покращує читабельність, полегшує налагодження та допомагає створювати масштабовані функції.

Наступним кроком ми додамо лазер для нашого гравця! Я створив папку Prefabs для зберігання багаторазових ігрових об'єктів і призначив матеріал Laser_mat, щоб дати лазеру унікальний вигляд.

pic

Тепер давайте спавнимо наш лазер, інстанціюючи його щоразу, коли гравець натискає пробіл!

pic

Я додав напрямок руху до нашого лазера, щоб він рухався вгору з реальною швидкістю, використовуючи функцію:
transform.Translate(Vector3.up * _speed * Time.deltaTime);
Швидкість встановлена змінною:
private float _speed = 8.0f;

pic

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

pic

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

pic

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

Я додав ворога до моєї гри з подібною поведінкою руху, як у гравця.
Ворог постійно з'являється знову вгорі екрану, коли досягає певної точки по осі Y.

pic

Використовуючи Random.Range, ворог тепер з'являється в випадковій позиції по осі X, додаючи більше різноманітності до його патерну руху.

pic

Порада професіонала: 📚 Перегляд офіційної документації є корисним способом знайти приклади синтаксису та краще зрозуміти, як реалізувати нові функції!

pic

https://docs.unity3d.com/2019.4/Documentation/ScriptReference/Random.Range.html

pic

Використовуючи OnTriggerEnter та Debug.Log(), ми тепер можемо виявляти, коли та з чим ворог стикається!

pic

👀 Перевірте лівий нижній кут, щоб побачити результати зіткнень, що відображаються в консолі! 🖥️🔍

"Я натрапив на проблему, коли мої вороги взагалі не з'являлися…

pic

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

Давайте перемістимо ворогів і знову запустимо гру, щоб побачити зміни в дії.

pic

“У програмному забезпеченні найпростіше рішення майже завжди є правильним.” — C.A.R. Hoare

Я додав метод GetComponent, щоб виявити, коли ворог стикається з гравцем і викликати функцію Damage() на об'єкті гравця. Коли ворог стикається з об'єктом, позначеним як 'Player', скрипт намагається отримати компонент Player з об'єкта. Якщо компонент успішно отримано (тобто player != null), викликається функція Damage(), і ворог знищується після нанесення шкоди.

Я реалізував систему життів, де гравець починає з 3 життів. Кожного разу, коли гравець отримує удар, функція Damage() зменшує кількість життів на 1. Коли життєвий запас гравця досягає 0, гравець вважається "мертвим" і видаляється зі сцени гри.

pic

В інспекторі Unity ми можемо побачити, як кількість життів гравця зменшується на 1 кожного разу, коли його вражає ворог.

pic

Після того, як гравець втрачає останнє життя, об'єкт гравця видаляється зі сцени, і його деталі зникають з інспектора.

У цій реалізації я створив Spawn_Manager, який використовує корутину для спавну ворогів у випадкових позиціях по осі X кожні 5 секунд. Корутіна запускає нескінченний цикл, інстанціюючи префаб ворога і роблячи паузу на певний період за допомогою yield return new WaitForSeconds(5.0f). Такий підхід дозволяє процесу спавну працювати незалежно, не блокуючи головний ігровий цикл.

pic

Перекладено з: Day 5: 2D Game Development: Prototyping

Leave a Reply

Your email address will not be published. Required fields are marked *