Стрибання і розчавлювання монстрів

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

Спершу ми повинні змінити кілька налаштувань, пов'язаних з фізичними взаємодіями. Вступ до світу фізичних шарів.

Контроль фізичних взаємодій

Фізичні тіла мають доступ до двох додаткових властивостей: шарів і масок. Шари визначають, на яких фізичних шарах (шарі) знаходиться об'єкт.

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

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

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

За замовчуванням для всіх фізичних тіл і областей встановлено як шар, так і маску, 0. Це означає, що всі вони стикаються один з одним.

Шари фізики представлені числами, але ми можемо дати їм імена, щоб відстежувати їх вміст.

Встановлення назв шарів

Давайте дамо нашим фізичним шарам назву. Перейдіть до Проект -> Параметри проекту.

image0

У лівому меню перейдіть до розділу Layer Names -> 3D Physics. Праворуч ви можете побачити список шарів з полем поруч з кожним з них. В цьому полі ви можете встановити їхні імена. Назвіть перші три шари player, enemies, і world відповідно.

image1

Тепер ми можемо призначити їх нашим фізичним вузлам.

Призначення шарів і масок

На головній сцені Main виберіть вузол землі Ground. У розділі Інспектор розгорніть розділ Collision (Зіткнення). Там ви можете побачити шари вузла та маски у вигляді сітки кнопок.

image2

Земля є частиною світу, тому ми хочемо, щоб вона була частиною третього шару. Натисніть підсвічену кнопку Layer , щоб вимкнути перший шар і увімкнути третій. Потім вимкніть маску Mask, натиснувши таку ж кнопку.

image3

Як я вже згадував вище, властивість Mask дозволяє вузлу виявляти взаємодію з іншими фізичними об'єктами, але вона не потрібна для того, щоб бути предметом для зіткнення. Земля не повинна нічого виявляти; вона всього лише запобігає падінню істот.

Зверніть увагу, що ви можете натиснути кнопку "..." у правій частині властивостей, щоб переглянути список іменованих галочок.

image4

Далі йдуть Player і Mob. Відкрийте Player.tscn, двічі клацнувши файл на панелі Файлова система.

Виберіть вузол гравця Player та встановіть йому маску зіткнення Collision -> Mask як для "enemies", так і для "world". Ви можете залишити властивість Layer за замовчуванням, оскільки перший шар є "player".

image5

Потім відкрийте сцену Mob, двічі клацнувши по Mob.tscn і вибравши вузол Mob.

Встановіть йому Collision -> Layer на "enemies", а маску зіткнення Collision -> Mask, залишіть порожньою.

Зображення

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

Примітка

Мобам не потрібна маска "world", тому що вони рухаються тільки на площині XZ. Ми не застосовуємо до них ніякої гравітації.

Стрибки

Сам механізм стрибка вимагає всього двох рядків коду. Відкрийте скрипт гравця Player. Нам потрібно значення, щоб контролювати силу стрибка і оновлення _physics_process(), щоб закодувати стрибок.

Після рядка, який визначає fall_acceleration, у верхній частині скрипту, додайте jump_impulse.

#...
# Vertical impulse applied to the character upon jumping in meters per second.
export var jump_impulse = 20

Усередині _physics_process() додайте наступний код перед рядком, де ми викликаємо move_and_slide().

func _physics_process(delta):
    #...

    # Jumping.
    if is_on_floor() and Input.is_action_just_pressed("jump"):
        velocity.y += jump_impulse

    #...

Це все, що вам потрібно, для стрибка!

Метод is_on_floor() є інструментом з класу KinematicBody. Він повертає true, якщо тіло зіткнулося з підлогою в цьому кадрі. Ось чому ми застосовуємо гравітацію до гравця: ми стикаємося з підлогою, а не пливемо над нею, як монстри.

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

Зверніть увагу, що вісь Y позитивна вгору. На відміну від 2D, де вісь Y позитивна вниз.

Розчавлення монстрів

Давайте додамо далі механізм розчавлення. Ми збираємося змусити персонажа відскакувати від монстрів і вбивати їх одночасно.

Нам потрібно виявити зіткнення з монстром і відрізнити їх від зіткнень з підлогою. Для цього ми можемо використовувати функцію тегування груп Godot.

Відкрийте сцену Mob.tscn ще раз і виберіть вузол Mob. Перейдіть до панелі Вузол справа, щоб побачити список сигналів. Панель Вузол має дві вкладки: Сигнали, які ви вже використовували, і Групи, що дозволяє призначати вузлам теги.

Натисніть на поле введення, щоб написати ім'я тега. Введіть в поле "mob" і натисніть кнопку Додати.

image7

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

image8

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

Кодування механізму розчавлення

Поверніться до скрипта гравця Player, щоб закодувати розчавлення.

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

# Vertical impulse applied to the character upon bouncing over a mob in
# meters per second.
export var bounce_impulse = 16

Потім у нижній частині _physics_process() додайте наступний цикл. За допомогою move_and_slide(), Godot змушує тіло рухатися іноді кілька разів поспіль, щоб згладити рух персонажа. Отже, ми повинні опрацювати всі зіткнення, які могли статися.

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

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

func _physics_process(delta):
    #...
    for index in range(get_slide_count()):
        # We check every collision that occurred this frame.
        var collision = get_slide_collision(index)
        # If we collide with a monster...
        if collision.collider.is_in_group("mob"):
            var mob = collision.collider
            # ...we check that we are hitting it from above.
            if Vector3.UP.dot(collision.normal) > 0.1:
                # If so, we squash it and bounce.
                mob.squash()
                velocity.y = bounce_impulse

Тут багато нових функцій. Ось ще трохи інформації про них.

Функції get_slide_count() та get_slide_collision() походять з класу KinematicBody і пов'язані з move_and_slide().

get_slide_collision() повертає об'єкт KinematicCollision, який містить інформацію про те, де і як сталося зіткнення. Наприклад, ми використовуємо його властивість collider, щоб перевірити, чи зіткнулися ми з "mob", викликаючи з неї is_in_group(): collision.collider.is_in_group("mob").

Примітка

Метод is_in_group() доступний на кожному вузлі.

Щоб перевірити, чи ми приземляємося на монстра, ми використовуємо векторний точковий добуток: Vector3.UP.dot(collision.normal) > 0.1. Нормальне зіткнення - це 3D-вектор, який перпендикулярний площині, де сталося зіткнення. Точковий добуток дозволяє порівняти його з напрямком вгору.

З точковими добутками, коли результат більший 0, два вектори знаходяться під кутом менше 90 градусів. Вище 0.1 говорить нам, що ми приблизно вище монстра.

Ми викликаємо ще одну невизначену функцію, mob.squash(). Ми повинні додати її до класу Mob.

Відкрийте скрипт Mob.gd, двічі клацнувши по ньому на панелі Файлова система. У верхній частині скрипту ми хочемо визначити новий сигнал з назвою squashed. А внизу можна додати функцію розчавлення, де ми випромінюємо сигнал і руйнуємо монстра.

# Emitted when the player jumped on the mob.
signal squashed

# ...


func squash():
    emit_signal("squashed")
    queue_free()

Ми будемо використовувати сигнал, щоб додати бали до рахунку на наступному уроці.

З цим, ви повинні бути в змозі вбивати монстрів, стрибаючи на них. Ви можете натиснути F5, щоб спробувати гру і встановити Main.tscn в якості головної сцени вашого проекту.

Однак гравець безсмертний. Ми поправимо це у наступній частині.