14 — Покрокові уроки¶
🇬🇧 English | 🇺🇦 Українська
Сім коротких уроків для тих, хто вперше робить взаємодію з предметами. Кожен урок має мету, кроки й пункт «Що має вийти»: якщо результат інший, у кінці уроку є підказки. Уроки йдуть від простого до складного, але кожен можна пройти окремо. Терміни, що можуть бути незнайомими, пояснено у словнику.
Для всіх уроків:
- плагін увімкнено в Edit → Plugins → InteractionSystem, редактор перезапущено;
- у Content Browser → Settings увімкнено Show Plugin Content, щоб бачити класи й демо плагіна;
- проєкт на Unreal Engine 5.8; підійде шаблон First Person або Third Person.
Урок 1. Перший предмет, який можна взяти¶
Мета: гравець наводить погляд на ящик, натискає E — ящик опиняється перед ним; F — кидає ящик.
Час: 10 хвилин.
Кроки¶
- Відкрийте Blueprint свого персонажа. У Components → Add додайте
InteractorComponentі перетягніть його на камеру. У Details залиштеUse Pawn Viewpointувімкненим, аGrab Offsetзадайте(70, 0, -15).
Простими словами.
InteractorComponent— це «рука з лазерною указкою». Указка (промінь) показує, що ви хочете взяти, аGrab Offset— де ця рука тримає взяте: 70 см перед камерою і трохи нижче.
- Створіть Content Browser → Add → Blueprint Class → All Classes → InteractionMasterItem і назвіть
BP_Crate. УMesh ComponentпризначтеCubeі задайте масштаб0.4. - Перетягніть
BP_Crateна рівень приблизно за 2 м перед стартом гравця. - Створіть Input Action
IA_UseіIA_Throw(тип Digital (bool)) та Input Mapping ContextIMC_Interaction:E → IA_Use,F → IA_Throw. Додайте контекст до гравця так само, як шаблон додає свій (вузол Add Mapping Context у Event Receive Controller Changed або в Begin Play). - У Event Graph персонажа:
- IA_Use → Started →
Request Grab(ціль — вашInteractorComponent); - IA_Throw → Started →
Request Release:Linear Velocity= Get Forward Vector камери ×900,Angular Velocity=(0, 120, 0). - Натисніть Play.
Що має вийти¶
- Коли ви підходите до ящика, над ним з'являється маленька точка: предмет поруч.
- Коли наводите на ящик центр екрана, точка змінюється на
E, а ящик підсвічується. - Після
Eящик опиняється перед камерою й рухається разом із вами. - Після
Fящик летить уперед і падає; його можна взяти знову.
Якщо не вийшло¶
| Що бачите | Що перевірити |
|---|---|
Немає ні точки, ні E |
Ящик ближче за 300 см (Trace Distance); колізія mesh блокує канал Visibility |
E є, але ящик не береться |
Чи викликається Request Grab (додайте Print String); чи активний контекст введення |
| Ящик береться, але не летить | Чи передаєте ненульову Linear Velocity у Request Release |
Для будь-якого незрозумілого випадку відкрийте панель налагодження командою InteractionOverlay (15): вона покаже фокус, стан руки й відповідь сервера.
Урок 2. Двері, які відчиняються для всіх гравців¶
Мета: двері відчиняються натисканням E, і всі гравці бачать їх відчиненими.
Кроки¶
- Створіть Blueprint Actor
BP_Door, у Class Defaults увімкніть Replicates. - Додайте Static Mesh
Leaf(стулка) з колізією і Mobility = Movable. - Class Settings → Interfaces → Add →
InteractableInterface. - Додайте змінну
bOpen(Boolean) і в Details → Replication виберіть RepNotify. Редактор створить функціюOnRep_bOpen. У ній:Leaf → Set Relative RotationзYaw = Select(bOpen, 90, 0). - Реалізуйте Event Interaction:
Set bOpen = NOT bOpen. - Перевизначте функцію
Can Interact: повернітьtrue, якщоAction == Interact. - У персонажа з уроку 1 додайте другу дію або змініть
IA_Use: якщо Get Focused Actor не можна взяти (не єInteractionPhysicsActorабоCan Be Grabbed = false) — викликайтеRequest InteractionзамістьRequest Grab. Готова логіка такого вибору описана в 11. - Перевірте в мережі: Play → Net Mode → Play As Client, Number of Players = 2.
Простими словами.
Interactionвиконується на сервері, ніби суддя записав «двері відчинено». RepNotify — це розсилка цієї новини: кожен клієнт отримує новеbOpenі сам повертає стулку у своїй копії світу.
Що має вийти¶
Один гравець натискає E біля дверей — у обох вікнах двері повертаються на 90°. Повторне E зачиняє їх для обох.
Якщо не вийшло¶
- Двері відчиняються лише в одному вікні: стулку повертають прямо в
Interaction, а не черезbOpenз RepNotify. - Двері не реагують у клієнта: у
BP_Doorне ввімкнено Replicates. Сервер відхиляє дії з нереплікованими акторами (причинаInvalidTarget).
Урок 3. Пояснюємо гравцеві, чому дія не вдалася¶
Мета: коли сервер відхиляє дію, гравець бачить зрозуміле повідомлення.
Кроки¶
- Виберіть
InteractorComponentперсонажа й у Details → Events натисніть + біляOn Action Result. - Подія дає
Target Actor,Action,AcceptedіReason. ЯкщоAccepted = false, підключіть Switch on EInteractionRejectReason і виведіть текст (Print String або ваш віджет):
Reason |
Що сталося | Приклад повідомлення |
|---|---|---|
Cooldown |
Натискання частіше, ніж дозволяє Min Action Interval |
«Не так швидко» |
InvalidTarget |
Ціль зникла або не реплікується | «Цей предмет недоступний» |
InvalidPose |
Сервер не повірив позиції руки: далеко від тіла, за стіною, застаріла | «Рука надто далеко» |
NotReachable |
Промінь сервера не дістав до цілі | «Не дотягнутися» |
HandBusy |
Рука вже тримає щось | «Рука зайнята» |
Claimed |
Ціль тримає інший гравець | «Цей предмет у когось у руках» |
Unavailable |
Ціль відмовила: захоплення вимкнене, немає місця, немає дії | «Зараз не можна» |
- Перевірте: запустіть двох гравців (Play As Client, 2 гравці), візьміть ящик першим гравцем, а другим спробуйте взяти той самий ящик.
Що має вийти¶
Другий гравець бачить «Цей предмет у когось у руках»: сервер відповів Claimed.
Простими словами.
On Action Result— відповідь судді на вашу заявку. Він не лише каже «ні», а й пояснює, яке правило спрацювало.
Урок 4. Шухляда, яка висувається з шафи¶
Мета: шухляда в шафі висувається за рукою, але не більше ніж на 40 см, і рухається разом із шафою.
Кроки¶
- Створіть Blueprint Actor
BP_Cabinetз Replicates. Корінь — Static Mesh корпусу. - Додайте дочірній Static Mesh
Drawer(шухляда): Mobility = Movable, колізія блокує Visibility. Component Replicates не вмикайте: рух шухляди передає маніпуляція. - Додайте
InteractionManipulationComponentі в його Details: Target Component Name = Drawer— рухати лише шухляду, а не всю шафу;- Inline Settings:
Maximum Hands = 1,Constraint = Linear,Constraint Axis— напрямок висування в осях шухляди (наприклад,(1, 0, 0), якщо її передня стінка дивиться вздовж +X),Minimum Value = 0,Maximum Value = 40,Simulate On Releaseвимкнено. - За бажанням виберіть
InteractionManipulationComponent→ Events → On Handle Changed: колиFraction ≥ 0.99, відтворіть звук повністю висунутої шухляди. - 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.
Кроки¶
- Створіть Blueprint Class → All Classes → InteractionBlueprintGrabTargetComponent і назвіть
BP_LanternGrab. Це компонент, у якому ви самі описуєте, що відбувається при захопленні. - Відкрийте
BP_LanternGrab, у Functions → Override додайте: - Begin Grip (
In Hand):Get Owner → Attach Actor To ComponentзParent = In Hand, правилаSnap to Target; повернітьtrue; - End Grip (
In Hand,In Reason, швидкості):Get Owner → Detach From ActorзKeep World; - Use (
In Hand): перемкніть світло власника (див. крок 4) і повернітьtrue. - Створіть Blueprint Actor
BP_Lantern: увімкніть Replicates і Replicate Movement (так прикріплення до руки дійде до клієнтів). Корінь — Static Mesh із колізією, яка блокує Visibility; дочірній Point Light. - У
BP_Lanternдодайте зміннуbLightOnз RepNotify; вOnRep_bLightOnвмикайте видимість світла. УBP_LanternGrab → UseвикликайтеSet bLightOn = NOT bLightOnна власнику (Cast To BP_Lantern). - Додайте
BP_LanternGrabу компонентиBP_Lanternі поставте ліхтар на рівень. - У персонажа: якщо рука вже тримає предмет (
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. Ящик, що ламається від ударів¶
Мета: ящик витримує кілька сильних ударів і розлітається з ефектом, який бачать усі.
Кроки¶
- Створіть Blueprint від
InteractionPhysicsActor—BP_FragileCrate; призначте mesh. - Створіть Data Asset від
InteractionPhysicsDataAssetзStart With Physics = trueі призначте його вObject Data. - Додайте
InteractionDestructibleComponent. У Class Defaults задайтеHealth = 30,Destroy Effect— будь-яку систему Niagara (або Cascade),Damage Per Impulse = 0.01,Minimum Impact Damage = 5. - За бажанням: Events → On Impact Destroyed → відтворіть звук у точці
Location. Подія спрацює на сервері й на кожному клієнті. - Play: візьміть інший ящик (з уроку 1) і киньте в
BP_FragileCrateкілька разів або киньте самBP_FragileCrateу стіну.
Що має вийти¶
Легкі дотики нічого не роблять. Після кількох сильних ударів ящик зникає з ефектом руйнування в усіх вікнах.
Простими словами. Шкода від удару = сила удару ×
Damage Per Impulse. Удари слабші заMinimum Impact Damageне рахуються, тож ящик, що просто лежить або повільно ковзає, не зношується.
Якщо не вийшло¶
- Ящик не ламається: зменште
Healthабо збільштеDamage Per Impulse; переконайтеся, що ящик симулює фізику. - Хочеться зламати ящик ударом меча чи вибухом: викликайте на сервері
Apply Impact Damage(Amount, Location)зі своєї логіки.
Урок 7. Перевірка в мультиплеєрі й пошук причин¶
Мета: навчитися бачити те, що бачить сервер, і знаходити причину, коли предмет «не береться».
Кроки¶
- Play → Net Mode → Play As Client, Number of Players = 2, натисніть Play.
- У вікні клієнта відкрийте консоль (
~) і введітьEnableCheats— на клієнті PIE без цього команди налагодження недоступні. - Введіть
InteractionOverlay. Праворуч з'явиться панель. - Наведіть руку на предмет і спробуйте його взяти. Подивіться на рядки State, Focus і Last answer у картці Local sources.
- Введіть
InteractionClaims: сервер надрукує в консоль, хто що тримає. - Додайте затримку мережі:
Net PktLag=150. Візьміть предмет ще раз і подивіться, як стан Waiting for the server триває довше.
Що має вийти¶
- Панель показує роль
CLIENT, ваші джерела, фокус і відповідь сервера на кожну спробу. - Під час затримки предмет у вашій руці все одно рухається одразу: рух у руці власника передбачається, а сервер лише підтверджує його.
- Повідомлення в Recent answers пояснює кожну відмову; наведіть на неї курсор, щоб прочитати пояснення.
Детально про панель і всі команди — у 15 — Інструменти налагодження.