Skip to content

17 — Демо Fuzzy Drone Arena

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

Опціональний модуль плагіна FuzzyLogicDemo постачає яскраву демонстраційну сцену, де дев'ять дронів обчислюють одну спільну нечітку систему Мамдані кожного кадру. Тут немає заскриптованої хореографії: кожен дрон передає власну відстань орбіти, спільний тепловий стан реактора та власну симульовану цілісність в один і той самий UFuzzySystemAsset, а отримані числа в реальному часі керують його швидкістю, висотою та кольором.

Як запустити

У Content Browser увімкніть іконку налаштувань (шестерня) → Show Plugin Content, якщо Plugins не видно, а потім перейдіть у Plugins → Fuzzy Logic Content → Demo → FuzzyDroneArena → Maps і відкрийте FuzzyDroneArena.

Запустіть Play або Standalone Game. Камера обертається навколо арени, центральний реактор пульсує, а дрони змінюють траєкторію та колір.

Асети

Усі асети цього демо лежать у Content Browser під Plugins → Fuzzy Logic Content → Demo → FuzzyDroneArena (увімкніть Show Plugin Content, якщо Plugins не видно):

Ресурс Призначення
Maps/FuzzyDroneArena Демонстраційна карта
DA_DroneBehavior Спільний UFuzzySystemAsset
Materials/M_DemoGlow Параметричний emissive-матеріал
DroneBehavior.json Редагований JSON-вихідник системи

Як читати систему

На відміну від трьох послідовних систем демо Turret Defense, Drone Behavior — це одна система Мамдані з трьома входами й трьома виходами, яку кожен дрон обчислює незалежно. Вона повністю використовує типові налаштування плагіна: Minimum для AND, Maximum для OR, імплікація Clip, агрегація Maximum і дефазифікація Centroid на 201 семплі. Trapezoid і Triangle моделюють обмежені входи й виходи; Ramp моделює два відкриті входи 0…1, де спадна рампа (Shoulder менше за Foot) дає високе значення на нижньому краю, а зростаюча — на верхньому. Див. Функції належності.

Drone Behavior — нечітка система

Змінна Діапазон Типове Множина Параметри Значення
Distance 350…1500 900 Near Trapezoid: 350 / 350 / 520 / 850 впритул до реактора; повна належність до 520, зникає до 850
Mid Triangle: 600 / 900 / 1200 робоча орбіта; найтиповіша близько 900
Far Trapezoid: 950 / 1250 / 1500 / 1500 зовнішня орбіта; повна належність від 1250
ReactorHeat 0…1 0.5 Cool Ramp: 0.75 → 0.15 реактор холодний; повна належність біля 0.15 і менше, зникає до 0.75
Hot Ramp: 0.25 → 0.85 реактор перегрівається; сила зростає після 0.25 і повна біля 0.85
Integrity 0…1 0.8 Low Ramp: 0.65 → 0.10 пошкоджений; повна належність біля 0.10 і менше, зникає до 0.65
High Ramp: 0.35 → 0.90 справний; сила зростає після 0.35 і повна біля 0.90
Aggression 0…1 0.5 Cautious Triangle: 0 / 0.18 / 0.55 триматися віддалік; найсильніша біля 0.18
Watchful Triangle: 0.25 / 0.52 / 0.78 утримувати позицію й спостерігати; найсильніша біля 0.52
Aggressive Triangle: 0.55 / 0.88 / 1 зближуватися; найсильніша біля 0.88
OrbitSpeed 0…1 0.5 Slow Triangle: 0 / 0.15 / 0.52 дрейф; найсильніша біля 0.15
Fast Triangle: 0.42 / 0.88 / 1 ривок; найсильніша біля 0.88
Altitude 0…1 0.5 Low Triangle: 0 / 0.18 / 0.58 триматися низько над платформою; найсильніша біля 0.18
High Triangle: 0.42 / 0.82 / 1 підійматися значно вище реактора; найсильніша біля 0.82

Distance замикає петлю зі власним рухом дрона: щокадру їй присвоюється поточний радіус орбіти дрона (обмежений діапазоном змінної), а отримана Aggression потім трохи змінює цей самий радіус для наступного кадру (див. нижче). ReactorHeat та Integrity — симульовані сигнали: спільна теплова хвиля для першого, і незалежне коливання зі зсувом фази для кожного дрона для другого, — вони імітують ту телеметрію, яку в реальній грі повідомляв би геймплей-код.

Правила

IF Distance IS Near AND ReactorHeat IS Hot THEN Aggression IS Aggressive
IF Distance IS Near AND Integrity IS Low THEN Aggression IS Cautious
IF Distance IS Mid AND Integrity IS High THEN Aggression IS Watchful
IF Distance IS Far THEN Aggression IS Watchful

IF Distance IS Near THEN OrbitSpeed IS Slow
IF Distance IS Mid THEN OrbitSpeed IS Fast
IF Distance IS Far THEN OrbitSpeed IS Fast

IF ReactorHeat IS Cool THEN Altitude IS Low
IF ReactorHeat IS Hot THEN Altitude IS High
IF Integrity IS Low THEN Altitude IS High WITH 0.75

Aggression балансує можливість проти ризику: близькість до гарячого реактора підвищує її, але низька цілісність поблизу тягне її назад униз, а дрон середньої дистанції обирає Watchful лише за умови справності. Далекі дрони завжди Watchful — немає правила Far AND *, що веде до Aggressive чи Cautious, тож самотній далекий дрон практично незалежно від інших входів осідає на середній множині. OrbitSpeed залежить лише від Distance: дрони впритул до реактора сповільнюються (щоб не проскочити повз нього), тоді як дрони середньої й далекої дистанції обидва рухаються швидко. Altitude напряму слідує за ReactorHeat, а пошкоджені дрони (Integrity IS Low) також підіймаються — але зі зниженою вагою WITH 0.75, тож у разі розбіжності тепло все одно домінує над висотою.

Як дев’ять дронів ділять одну систему

Усі дев’ять дронів обчислюють той самий асет DA_DroneBehavior, тож ця демонстрація йде шляхом натовпу, а не компонента: в AFuzzyDroneAgent немає UFuzzyLogicComponent. Кожен дрон один раз, у BeginPlay, просить у UFuzzyLogicSubsystem скомпільований рушій і тримає його все своє життя:

if (UGameInstance* GameInstance = GetGameInstance())
{
    Brain = GameInstance->GetSubsystem<UFuzzyLogicSubsystem>()->GetEngine(Behavior);
}

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

Оскільки спільний рушій не зберігає стану на агента, кожен тік передає всі три входи, а не лише те, що змінилося: компонента, який би пам’ятав їх між викликами, тут немає. Сама мапа перевикористовується, тож тік записує три float, а не виділяє пам’ять:

Inputs.Add(FuzzyDroneArena::DistanceInput, DistanceInput);
Inputs.Add(FuzzyDroneArena::HeatInput, ReactorHeat);
Inputs.Add(FuzzyDroneArena::IntegrityInput, Integrity);

const FFuzzyInferenceResult Result = Brain->Evaluate(Inputs);

Але щодо масштабу варто бути чесними: дев’ять дронів — це надто мало, щоб профайлер це помітив. Демонстрація показує форму патерну, а не виміряний виграш — економія стає реальною на сотнях. Для одного детального агента компонент лишається кращим за замовчуванням, і саме це показує 18 — Fuzzy Turret Defense Demo: три зчеплені системи на одній турелі, кожна на власному компоненті.

Обидва шляхи порівняно поруч у 14 — Архітектура та продуктивність.

Від чітких виходів до руху

Три чіткі числа зчитуються раз на кадр і напряму керують трансформом і матеріалами дрона — жодного проміжного стейт-машину немає:

Вихід Керує Формула
Aggression Бажаний радіус орбіти Lerp(1180, 560, Aggression) см, згладжено через FInterpTo
Колір корпусу див. «Що означає колір дрона» нижче
Інтенсивність точкового світла Lerp(420, 1050, Aggression)
Сила світіння корпусу Lerp(0.22, 0.58, Aggression)
Товщина енергетичного променя 0.009 + Aggression * 0.013
OrbitSpeed Кутова швидкість Lerp(10, 38, OrbitSpeed) градусів/секунду
Швидкість обертання роторів Lerp(180, 660, OrbitSpeed) і Lerp(240, 820, OrbitSpeed) градусів/секунду, у протилежних напрямках
Altitude Висота орбіти Lerp(290, 820, Altitude) см, плюс невелике синусоїдальне похитування для кожного дрона

Зворотний зв'язок через Distance замикає описану вище петлю: висока Aggression тягне бажаний радіус до 560, що знижує Distance наступного кадру, а правила зчитують це як Near — підсилюючи ту саму поведінку, доки Integrity чи ReactorHeat не потягнуть в інший бік.

Що означає колір дрона

Колір корпусу — не власний вихід нечіткої системи, а окреме двоетапне HSV-змішування на основі того самого значення Aggression, незалежне від того, де саме розташовані піки власних множин Aggression (Cautious/Watchful/Aggressive):

  • 0.0 → 0.5: перехід від Calm (блакитний, 0.015, 0.55, 1.0) до Adaptive (фіолетовий, 0.42, 0.08, 1.0).
  • 0.5 → 1.0: перехід від Adaptive до Approach (червоний, 1.0, 0.015, 0.04).

Кольорові зразки легенди HUD (0.0 CALM, 0.5 ADAPT, 1.0 APPROACH) позначають саме цей поділ — свідоме, жорстко закодоване рішення візуалізації, а не межу, яку визначає сама нечітка система. Праворуч на HUD показано живу телеметрію першого дрона (D-01): його входи Distance/ReactorHeat/Integrity та виходи Aggression/OrbitSpeed/Altitude оновлюються щокадру; пульсувальна рамка TELEMETRY LOCK супроводжує цей дрон у кадрі й має той самий колір. Зміни чисел демонструють, що сцена використовує runtime-висновок, а не заздалегідь записану анімацію.

Роль JSON

DA_DroneBehavior побудовано з DroneBehavior.json через FuzzyLogicStatics.load_fuzzy_system_from_json. Під час виконання дрони читають Data Asset напряму; JSON не парситься кожного кадру й не потрібен запакованій сцені.

Можна також відкрити DA_DroneBehavior, змінити систему в редакторі та натиснути Save To JSON, щоб синхронізувати зовнішній пресет вручну.

Що спробувати

  • змініть форму ReactorHeat.Hot і перегляньте реакцію висоти;
  • збільшіть вагу правила низької цілісності;
  • перемкніть Centroid на Weighted Average та порівняйте поведінку;
  • додайте вихід для яскравості променя;
  • використайте один Data Asset для десятків додаткових агентів.

Демо-класи живуть у власному модулі плагіна FuzzyLogicDemo (Plugins/FuzzyLogic/Source/FuzzyLogicDemo) — вони постачаються з плагіном за замовчуванням, але можуть бути повністю виключені зі збірки; див. 16 — Демонстраційний контент.

Значення DefaultValue

DefaultValue в input має значення лише до першого Tick дрона й як стартова точка для preview на вкладці Inference — під час виконання Set Input щокадру перезаписує Distance, ReactorHeat та Integrity живими симульованими значеннями, тож типові значення асета в запущеному демо фактично ніколи не обчислюються.

DefaultValue в output узагалі не бере участі у висновку. Це лише значення за замовчуванням у структурі змінної; результат завжди обчислюється з правил і функцій належності.