Skip to content

14 — Покрокові уроки

🇬🇧 English | 🇺🇦 Українська

Сім коротких уроків для тих, хто вперше робить взаємодію з предметами. Кожен урок має мету, кроки й пункт «Що має вийти»: якщо результат інший, у кінці уроку є підказки. Уроки йдуть від простого до складного, але кожен можна пройти окремо. Терміни, що можуть бути незнайомими, пояснено у словнику.

Для всіх уроків:

  • плагін увімкнено в Edit → Plugins → InteractionSystem, редактор перезапущено;
  • у Content Browser → Settings увімкнено Show Plugin Content, щоб бачити класи й демо плагіна;
  • проєкт на Unreal Engine 5.8; підійде шаблон First Person або Third Person.

Урок 1. Перший предмет, який можна взяти

Мета: гравець наводить погляд на ящик, натискає E — ящик опиняється перед ним; F — кидає ящик.

Час: 10 хвилин.

Кроки

  1. Відкрийте Blueprint свого персонажа. У Components → Add додайте InteractorComponent і перетягніть його на камеру. У Details залиште Use Pawn Viewpoint увімкненим, а Grab Offset задайте (70, 0, -15).

Простими словами. InteractorComponent — це «рука з лазерною указкою». Указка (промінь) показує, що ви хочете взяти, а Grab Offset — де ця рука тримає взяте: 70 см перед камерою і трохи нижче.

  1. Створіть Content Browser → Add → Blueprint Class → All Classes → InteractionMasterItem і назвіть BP_Crate. У Mesh Component призначте Cube і задайте масштаб 0.4.
  2. Перетягніть BP_Crate на рівень приблизно за 2 м перед стартом гравця.
  3. Створіть Input Action IA_Use і IA_Throw (тип Digital (bool)) та Input Mapping Context IMC_Interaction: E → IA_Use, F → IA_Throw. Додайте контекст до гравця так само, як шаблон додає свій (вузол Add Mapping Context у Event Receive Controller Changed або в Begin Play).
  4. У Event Graph персонажа:
  5. IA_Use → Started → Request Grab (ціль — ваш InteractorComponent);
  6. IA_Throw → Started → Request Release: Linear Velocity = Get Forward Vector камери × 900, Angular Velocity = (0, 120, 0).
  7. Натисніть Play.

Що має вийти

  • Коли ви підходите до ящика, над ним з'являється маленька точка: предмет поруч.
  • Коли наводите на ящик центр екрана, точка змінюється на E, а ящик підсвічується.
  • Після E ящик опиняється перед камерою й рухається разом із вами.
  • Після F ящик летить уперед і падає; його можна взяти знову.

Якщо не вийшло

Що бачите Що перевірити
Немає ні точки, ні E Ящик ближче за 300 см (Trace Distance); колізія mesh блокує канал Visibility
E є, але ящик не береться Чи викликається Request Grab (додайте Print String); чи активний контекст введення
Ящик береться, але не летить Чи передаєте ненульову Linear Velocity у Request Release

Для будь-якого незрозумілого випадку відкрийте панель налагодження командою InteractionOverlay (15): вона покаже фокус, стан руки й відповідь сервера.

Урок 2. Двері, які відчиняються для всіх гравців

Мета: двері відчиняються натисканням E, і всі гравці бачать їх відчиненими.

Кроки

  1. Створіть Blueprint Actor BP_Door, у Class Defaults увімкніть Replicates.
  2. Додайте Static Mesh Leaf (стулка) з колізією і Mobility = Movable.
  3. Class Settings → Interfaces → Add → InteractableInterface.
  4. Додайте змінну bOpen (Boolean) і в Details → Replication виберіть RepNotify. Редактор створить функцію OnRep_bOpen. У ній: Leaf → Set Relative Rotation з Yaw = Select(bOpen, 90, 0).
  5. Реалізуйте Event Interaction: Set bOpen = NOT bOpen.
  6. Перевизначте функцію Can Interact: поверніть true, якщо Action == Interact.
  7. У персонажа з уроку 1 додайте другу дію або змініть IA_Use: якщо Get Focused Actor не можна взяти (не є InteractionPhysicsActor або Can Be Grabbed = false) — викликайте Request Interaction замість Request Grab. Готова логіка такого вибору описана в 11.
  8. Перевірте в мережі: Play → Net Mode → Play As Client, Number of Players = 2.

Простими словами. Interaction виконується на сервері, ніби суддя записав «двері відчинено». RepNotify — це розсилка цієї новини: кожен клієнт отримує нове bOpen і сам повертає стулку у своїй копії світу.

Що має вийти

Один гравець натискає E біля дверей — у обох вікнах двері повертаються на 90°. Повторне E зачиняє їх для обох.

Якщо не вийшло

  • Двері відчиняються лише в одному вікні: стулку повертають прямо в Interaction, а не через bOpen з RepNotify.
  • Двері не реагують у клієнта: у BP_Door не ввімкнено Replicates. Сервер відхиляє дії з нереплікованими акторами (причина InvalidTarget).

Урок 3. Пояснюємо гравцеві, чому дія не вдалася

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

Кроки

  1. Виберіть InteractorComponent персонажа й у Details → Events натисніть + біля On Action Result.
  2. Подія дає Target Actor, Action, Accepted і Reason. Якщо Accepted = false, підключіть Switch on EInteractionRejectReason і виведіть текст (Print String або ваш віджет):
Reason Що сталося Приклад повідомлення
Cooldown Натискання частіше, ніж дозволяє Min Action Interval «Не так швидко»
InvalidTarget Ціль зникла або не реплікується «Цей предмет недоступний»
InvalidPose Сервер не повірив позиції руки: далеко від тіла, за стіною, застаріла «Рука надто далеко»
NotReachable Промінь сервера не дістав до цілі «Не дотягнутися»
HandBusy Рука вже тримає щось «Рука зайнята»
Claimed Ціль тримає інший гравець «Цей предмет у когось у руках»
Unavailable Ціль відмовила: захоплення вимкнене, немає місця, немає дії «Зараз не можна»
  1. Перевірте: запустіть двох гравців (Play As Client, 2 гравці), візьміть ящик першим гравцем, а другим спробуйте взяти той самий ящик.

Що має вийти

Другий гравець бачить «Цей предмет у когось у руках»: сервер відповів Claimed.

Простими словами. On Action Result — відповідь судді на вашу заявку. Він не лише каже «ні», а й пояснює, яке правило спрацювало.

Урок 4. Шухляда, яка висувається з шафи

Мета: шухляда в шафі висувається за рукою, але не більше ніж на 40 см, і рухається разом із шафою.

Кроки

  1. Створіть Blueprint Actor BP_Cabinet з Replicates. Корінь — Static Mesh корпусу.
  2. Додайте дочірній Static Mesh Drawer (шухляда): Mobility = Movable, колізія блокує Visibility. Component Replicates не вмикайте: рух шухляди передає маніпуляція.
  3. Додайте InteractionManipulationComponent і в його Details:
  4. Target Component Name = Drawer — рухати лише шухляду, а не всю шафу;
  5. Inline Settings: Maximum Hands = 1, Constraint = Linear, Constraint Axis — напрямок висування в осях шухляди (наприклад, (1, 0, 0), якщо її передня стінка дивиться вздовж +X), Minimum Value = 0, Maximum Value = 40, Simulate On Release вимкнено.
  6. За бажанням виберіть InteractionManipulationComponent → Events → On Handle Changed: коли Fraction ≥ 0.99, відтворіть звук повністю висунутої шухляди.
  7. Play: візьміть шухляду (E з уроку 1) і відходьте назад.

Що має вийти

  • Шухляда їде лише вздовж своєї осі й зупиняється через 40 см, хоч би як далеко ви відійшли.
  • Після відпускання шухляда залишається висунутою й лишається частиною шафи.
  • Якщо шафа рухається (наприклад, ви переміщуєте її в Blueprint), шухляда рухається з нею й далі висувається відносно шафи.
  • Виклик Reset Manipulation на сервері закриває шухляду.

Простими словами. Constraint = Linear — це рейки для шухляди. Minimum Value і Maximum Value — упори на кінцях рейок у сантиметрах.

Якщо не вийшло

  • Береться вся шафа: не задано Target Component Name або в ньому помилка в імені.
  • Шухляда не береться: у профілі Maximum Hands = 2 (для обмеження потрібна одна рука) або Movement = Physics (для обмеження потрібен Direct). Причину покаже Validate Setup і панель налагодження.

Урок 5. Ліхтар на Blueprint: власна ціль захоплення без C++

Мета: ліхтар, який береться в руку, вмикається кнопкою використання й залишається там, де його поставили. Усі правила — у Blueprint.

Кроки

  1. Створіть Blueprint Class → All Classes → InteractionBlueprintGrabTargetComponent і назвіть BP_LanternGrab. Це компонент, у якому ви самі описуєте, що відбувається при захопленні.
  2. Відкрийте BP_LanternGrab, у Functions → Override додайте:
  3. Begin Grip (In Hand): Get Owner → Attach Actor To Component з Parent = In Hand, правила Snap to Target; поверніть true;
  4. End Grip (In Hand, In Reason, швидкості): Get Owner → Detach From Actor з Keep World;
  5. Use (In Hand): перемкніть світло власника (див. крок 4) і поверніть true.
  6. Створіть Blueprint Actor BP_Lantern: увімкніть Replicates і Replicate Movement (так прикріплення до руки дійде до клієнтів). Корінь — Static Mesh із колізією, яка блокує Visibility; дочірній Point Light.
  7. У BP_Lantern додайте змінну bLightOn з RepNotify; в OnRep_bLightOn вмикайте видимість світла. У BP_LanternGrab → Use викликайте Set bLightOn = NOT bLightOn на власнику (Cast To BP_Lantern).
  8. Додайте BP_LanternGrab у компоненти BP_Lantern і поставте ліхтар на рівень.
  9. У персонажа: якщо рука вже тримає предмет (Get Held Actor дійсний), натискання E має викликати Request Interaction — це і є «використати предмет у руці».

Що має вийти

  • E по ліхтарю — він опиняється в руці й рухається за вами; другий гравець бачить ліхтар у вашій руці.
  • Ще одне E — світло вмикається або вимикається для всіх.
  • F — ліхтар залишається висіти там, де ви його відпустили (фізики немає: так вирішив ваш End Grip).

Простими словами. Плагін залишає за собою роль судді: хто може взяти, чи не тримає хтось інший, чи не надто далеко рука. А що робити з ліхтарем після дозволу — вирішує ваш Blueprint.

Корисно знати

  • Can Begin Grip викликається і на клієнті (для підказки), і на сервері. Читайте в ньому лише реплікований стан, нічого не змінюйте.
  • Begin Grip, End Grip і Use виконуються лише на сервері.
  • In Reason = Released означає навмисне відпускання; інші причини — скасування, і кидати предмет тоді не слід.
  • Set Grab Enabled(false) на сервері забороняє нові захоплення й відпускає поточні руки.

Урок 6. Ящик, що ламається від ударів

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

Кроки

  1. Створіть Blueprint від InteractionPhysicsActor — BP_FragileCrate; призначте mesh.
  2. Створіть Data Asset від InteractionPhysicsDataAsset з Start With Physics = true і призначте його в Object Data.
  3. Додайте InteractionDestructibleComponent. У Class Defaults задайте Health = 30, Destroy Effect — будь-яку систему Niagara (або Cascade), Damage Per Impulse = 0.01, Minimum Impact Damage = 5.
  4. За бажанням: Events → On Impact Destroyed → відтворіть звук у точці Location. Подія спрацює на сервері й на кожному клієнті.
  5. Play: візьміть інший ящик (з уроку 1) і киньте в BP_FragileCrate кілька разів або киньте сам BP_FragileCrate у стіну.

Що має вийти

Легкі дотики нічого не роблять. Після кількох сильних ударів ящик зникає з ефектом руйнування в усіх вікнах.

Простими словами. Шкода від удару = сила удару × Damage Per Impulse. Удари слабші за Minimum Impact Damage не рахуються, тож ящик, що просто лежить або повільно ковзає, не зношується.

Якщо не вийшло

  • Ящик не ламається: зменште Health або збільште Damage Per Impulse; переконайтеся, що ящик симулює фізику.
  • Хочеться зламати ящик ударом меча чи вибухом: викликайте на сервері Apply Impact Damage(Amount, Location) зі своєї логіки.

Урок 7. Перевірка в мультиплеєрі й пошук причин

Мета: навчитися бачити те, що бачить сервер, і знаходити причину, коли предмет «не береться».

Кроки

  1. Play → Net Mode → Play As Client, Number of Players = 2, натисніть Play.
  2. У вікні клієнта відкрийте консоль (~) і введіть EnableCheats — на клієнті PIE без цього команди налагодження недоступні.
  3. Введіть InteractionOverlay. Праворуч з'явиться панель.
  4. Наведіть руку на предмет і спробуйте його взяти. Подивіться на рядки State, Focus і Last answer у картці Local sources.
  5. Введіть InteractionClaims: сервер надрукує в консоль, хто що тримає.
  6. Додайте затримку мережі: Net PktLag=150. Візьміть предмет ще раз і подивіться, як стан Waiting for the server триває довше.

Що має вийти

  • Панель показує роль CLIENT, ваші джерела, фокус і відповідь сервера на кожну спробу.
  • Під час затримки предмет у вашій руці все одно рухається одразу: рух у руці власника передбачається, а сервер лише підтверджує його.
  • Повідомлення в Recent answers пояснює кожну відмову; наведіть на неї курсор, щоб прочитати пояснення.

Детально про панель і всі команди — у 15 — Інструменти налагодження.

Що далі

  • Повний опис Blueprint-інтеграції — 11.
  • VR-руки, дворучні предмети й профілі — 08.
  • Як сервер ухвалює рішення — 13.