Як і раніше, ми збережемо професійну структуру для цієї версії, щоб усе було організовано та послідовно.
Давайте поринемо у створення 2D гри! Але спершу розпочнемо з прототипування. Я почну з створення об'єкта куба і назву його Player
, із суцільним чорним фоном, щоб задати сцену.
Наступним кроком ми налаштуємо співвідношення сторін на 16:9, щоб наша гра відображалась однаково на різних розмірах екранів і роздільних здатностях.
Використовуючи C#, я призначу скрипт для нашого об'єкта гравця і розміщу його в координатах (0, 0, 0) для центру початкової точки.
Звертаючись до офіційної документації Unity, ми дізналися, як використовувати властивість transform
. У цьому прикладі я створив новий Vector3
, щоб наш гравець рухався вліво.
Для реалізації реального руху ми використовуємо Vector3.[direction] * [speed] * Time.deltaTime
. Це гарантує, що об'єкт рухається з постійною швидкістю в метрах на секунду, незалежно від варіацій кадрової частоти.
Використовуючи функцію Unity Input.GetAxis
, ми можемо створити змінні для горизонтального та вертикального вводу, які дозволяють гравцеві керувати рухом за допомогою стрілок або WASD
. Горизонтальна ось рухає гравця вліво і вправо, а вертикальна — вгору та вниз.
Ось більш чистий і оптимізований спосіб написати той самий код руху, як і раніше.
Тепер ми встановили межі для нашого гравця, з функціональністю, яка дозволяє обертатись по екрану по осі X, коли гравець виходить за межі екрану.
Порада професіонала: 🛡️ Mathf.Clamp
утримує значення в межах визначеного діапазону, запобігаючи помилкам виходу за межі та підтримуючи контрольований рух.
Порада професіонала: ✏️ Написання псевдокоду та чистого коду покращує читабельність, полегшує налагодження та допомагає створювати масштабовані функції.
Наступним кроком ми додамо лазер для нашого гравця! Я створив папку Prefabs
для зберігання багаторазових ігрових об'єктів і призначив матеріал Laser_mat
, щоб дати лазеру унікальний вигляд.
Тепер давайте спавнимо наш лазер, інстанціюючи його щоразу, коли гравець натискає пробіл!
Я додав напрямок руху до нашого лазера, щоб він рухався вгору з реальною швидкістю, використовуючи функцію:
transform.Translate(Vector3.up * _speed * Time.deltaTime);
Швидкість встановлена змінною:
private float _speed = 8.0f;
Наступним кроком я застосую зсув до інстанційованого лазерного променя, щоб вирівняти його позицію, так щоб він стріляв з правильного кута, а не зі сторін.
Я реалізував швидкість стрільби та охолодження для лазера мого гравця, використовуючи Time.time
, щоб контролювати, коли лазер можна випустити.
Я не можу швидко натискати пробіл, щоб стріляти кількома лазерами через інтервал охолодження.
Я додав ворога до моєї гри з подібною поведінкою руху, як у гравця.
Ворог постійно з'являється знову вгорі екрану, коли досягає певної точки по осі Y.
Використовуючи Random.Range
, ворог тепер з'являється в випадковій позиції по осі X, додаючи більше різноманітності до його патерну руху.
Порада професіонала: 📚 Перегляд офіційної документації є корисним способом знайти приклади синтаксису та краще зрозуміти, як реалізувати нові функції!
https://docs.unity3d.com/2019.4/Documentation/ScriptReference/Random.Range.html
Використовуючи OnTriggerEnter
та Debug.Log()
, ми тепер можемо виявляти, коли та з чим ворог стикається!
👀 Перевірте лівий нижній кут, щоб побачити результати зіткнень, що відображаються в консолі! 🖥️🔍
"Я натрапив на проблему, коли мої вороги взагалі не з'являлися…
Проблема виникла, коли я додав ще одного ворога, і вони з'являлися в тій самій позиції, стикаючись один з одним і ефективно знищуючи себе.
Давайте перемістимо ворогів і знову запустимо гру, щоб побачити зміни в дії.
“У програмному забезпеченні найпростіше рішення майже завжди є правильним.” — C.A.R. Hoare
Я додав метод GetComponent
, щоб виявити, коли ворог стикається з гравцем і викликати функцію Damage()
на об'єкті гравця. Коли ворог стикається з об'єктом, позначеним як 'Player', скрипт намагається отримати компонент Player
з об'єкта. Якщо компонент успішно отримано (тобто player != null
), викликається функція Damage()
, і ворог знищується після нанесення шкоди.
Я реалізував систему життів, де гравець починає з 3 життів. Кожного разу, коли гравець отримує удар, функція Damage()
зменшує кількість життів на 1. Коли життєвий запас гравця досягає 0, гравець вважається "мертвим" і видаляється зі сцени гри.
В інспекторі Unity ми можемо побачити, як кількість життів гравця зменшується на 1 кожного разу, коли його вражає ворог.
Після того, як гравець втрачає останнє життя, об'єкт гравця видаляється зі сцени, і його деталі зникають з інспектора.
У цій реалізації я створив Spawn_Manager
, який використовує корутину для спавну ворогів у випадкових позиціях по осі X кожні 5 секунд. Корутіна запускає нескінченний цикл, інстанціюючи префаб ворога і роблячи паузу на певний період за допомогою yield return new WaitForSeconds(5.0f)
. Такий підхід дозволяє процесу спавну працювати незалежно, не блокуючи головний ігровий цикл.
Перекладено з: Day 5: 2D Game Development: Prototyping