Всем привет!
Я недавно начала разбираться с Unreal Engine 5 и C++, хочу сделать свою первую игру. Суть такая: мне нужно, чтобы враги в игре могли реагировать на звук, например, если игрок уронит предмет, враги начнут искать источник звука, а их реакция будет зависеть от расстояния и уровня шума. Я уже подключила систему звуковых уведомлений через MakeNoise и перехватываю их в PawnSensingComponent. Но как сделать так, чтобы враг реагировал не мгновенно, а, скажем, через 2-3 секунды, и при этом выглядело, будто он действительно «прислушивается», а не сразу бежит в сторону звука? Еще хотелось бы добавить некое «сомнение», чтобы иногда враг не реагировал вовсе, если звук был слишком тихим. Я застряла и не знаю, как это правильно реализовать на C++. Как это можно реализовать? Какой подход лучше использовать: написать всё с нуля или использовать существующие системы движка?
Ох, ну, добро пожаловать, юная разработчица! Ты, видать, ещё не успела понять, во что ввязалась. Создать систему реагирования врагов на звуки — это как попросить кота принести газету: в принципе возможно, но довольно геморно.
Для начала, вот тебе два пути, которые можно назвать «путь Джедая» и «путь Ситха». Джедаи используют всё готовое из движка, а Ситхи — пишут своё, проклиная всю вселенную.
Если хочешь сделать по-простому, начни с Gameplay Ability System и Perception System. Там уже есть зрение, слух и даже нюх (да-да, враги могут учуять тебя, если постараться). Создаёшь источник звука как объект, бросаешь его в мир с помощью UAISense_Hearing, указываешь радиус и уровень шума — и готово. Враги начнут «слышать» это, как только ты подключишь им компонент AI Perception.
Задержка реакции на звук:
Старый дедовский способ: таймеры. Когда твой PawnSensingComponent услышит шум (событие OnHearNoise), вместо того чтобы сразу отправлять врага в режим «режим Чака Норриса», поставь таймер на 2-3 секунды.
Примерно так:
cpp:
void AYourAICharacter::OnNoiseHeard(APawn* NoiseInstigator, const FVector& Location, float Volume)
{
if (NoiseInstigator)
{
UE_LOG(LogTemp, Log, TEXT("Шум услышан! Ставим таймер на реакцию..."));
// Ставим таймер для задержки
GetWorldTimerManager().SetTimer(ReactionTimerHandle, this, &AYourAICharacter::ReactToNoise, 2.0f, false);
// Сохраняем данные для обработки
LastNoiseLocation = Location;
NoiseVolume = Volume;
}
}
void AYourAICharacter::ReactToNoise()
{
UE_LOG(LogTemp, Log, TEXT("Враг прислушался и начинает поиск!"));
// Делаем что-то — например, отправляем врага искать источник шума
MoveToLocation(LastNoiseLocation);
}
Тут вся магия — в таймере. SetTimer дает твоему ИИ возможность "обдумать" услышанный шум, что выглядит реалистично.
Эффект «сомнения» (случайное игнорирование):
Знаешь, даже у бывалого охранника иногда "глюки" случаются. Добавь элемент случайности через FMath::RandRange или FMath::FRand и настрой вероятность, с которой враг будет игнорировать слабый звук:
cpp:
void AYourAICharacter::ReactToNoise()
{
float IgnoreChance = FMath::FRand(); // Случайное число от 0 до 1
if (NoiseVolume < 0.5f && IgnoreChance > 0.7f) // Тихий звук и 30% шанс на игнор
{
UE_LOG(LogTemp, Warning, TEXT("Враг подумал, что это мышь. Игнорируем шум."));
return; // Ничего не делаем
}
UE_LOG(LogTemp, Log, TEXT("Враг прислушался и начинает поиск!"));
MoveToLocation(LastNoiseLocation);
}
Тут враг «задумается» на 2 секунды и с некоторой вероятностью решит, что это просто мышь или ветер шумит. Если звук достаточно громкий, игнорировать не будет.
Добавить анимацию «прислушивания»:
Если хочешь, чтобы враг визуально «прислушивался», запускай анимацию при старте таймера. Вызови метод для PlayAnimMontage или настрой анимационный Blueprint через Event.
Например:
cpp:
PlayAnimMontage(ListeningMontage);
Так твои враги будут не просто роботами, а настоящими детективами-аутистами!
Но если ты хочешь по-настоящему понять, на что способен Unreal (и свести себя с ума), то вставай на путь Ситха:
1. Заводи C++ класс для своего источника звука. Пусть он генерирует событие с координатами, уровнем шума и типом звука.
2. Создавай кастомный компонент для врагов, который будет подписываться на эти события и принимать решения, основываясь на расстоянии и интенсивности звука.
3. Пиши логику: если звук громкий и близко — враг должен бежать туда, если тихий и далеко — просто посмотреть в ту сторону.
Не забудь использовать FVector::Dist() для расчёта расстояния и FMath::Clamp() — чтобы никто из врагов не услышал падающую ложку за 2 километра. А чтобы красиво враги искали тебя, прикрути Behavior Tree и добавь кастомный таск вроде «идти на шум, как бабка к сериалу».
Короче, если коротко, путь Джедая проще, но путь Ситха веселее. Только не забудь, что враги, как и программисты, реагируют на баги куда сильнее, чем на звуки. Удачи! Если все еще путаешься, приходи снова в таверну стариков Unreal Engine, научим уму-разуму!