RVO
RVO (Reciprocal Velocity Obstacles) 는 움직이는 객체들끼리 서로의 속도와 방향을 고려하여 충돌을 실시간으로 피하는 알고리즘이다.
RVO 핵심 코드
GetCharacterMovement()->bUseRVOAvoidance = true;
GetCharacterMovement()->AvoidanceConsiderationRadius = 200.0f;
GetCharacterMovement()->AvoidanceWeight = 0.5f;
GetCharacterMovement()->bUseRVOAvoidance = true;
이 코드는 RVO(Reciprocal Velocity Obstacles) 회피 시스템의 활성화 여부를 결정하는 가장 기본적인 설정이다.
- 기능: RVO 충돌 회피 알고리즘 활성화 On/Off
- 값의 의미: true로 설정하면 캐릭터가 다른 오브젝트나 장애물과의 충돌을 피하기 위한 자동 회피 기능이 작동한다. 이 값이 false라면 회피 기능이 작동하지 않는다.
- 적합한 상황: 여러 AI 캐릭터가 서로 상호작용하며 이동해야 하는 상황에서 필수적이다.
GetCharacterMovement()->AvoidanceConsiderationRadius = 200.0f;
이 코드는 AI가 다른 오브젝트를 감지하고 회피를 시작하는 거리를 결정한다.
- 기능: 회피 반경 세팅
- 값의 의미: 200 uu(Unreal Unit) 내에 다른 오브젝트가 들어오면 회피를 시작한다.
- 영향:
- 값이 작을 경우 오브젝트가 가까워질 때까지 회피하지 않으므로 급격한 회피 동작이 발생할 수 있으며, 충돌 위험이 높아진다.
- 값이 클 경우 오브젝트가 멀리 있을 때부터 회피를 시작하므로 부드러운 회피가 가능하지만, 불필요한 자원낭비가 증가할 수 있다.
GetCharacterMovement()->AvoidanceWeight = 0.5f;
이 코드는 해당 클래스를 상속받은 캐릭터의 회피 우선순위를 결정한다.
- 기능: 회피 가중치 세팅
- 값의 범위: 0.0f ~ 1.0f
- 값의 의미:
- 0.0f에 가까울수록 이 캐릭터가 다른 캐릭터를 먼저 회피한다. (낮은 계급이 됨)
- 1.0f에 가까울수록 다른 캐릭터들이 이 캐릭터를 먼저 회피한다. (높은 계급이 됨)
RVO를 적용한 AICharacter 전체 코드
AI_RVO_Character.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "AI_RVO_Character.generated.h"
UCLASS()
class AI_TEST_API AI_RVO_Character : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AI_RVO_Character();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// 타겟 위치로 이동
UFUNCTION(BlueprintCallable, Category = "AI Movement")
void MoveToTarget();
// RVO 회피 활성화/비활성화
UFUNCTION(BlueprintCallable, Category = "RVO")
void SetRVOAvoidanceEnabled(bool bEnable);
public:
// 이동할 타겟 액터
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI Movement")
AActor* TargetActor;
// RVO 회피 설정
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RVO")
float AvoidanceRadius = 300.0f;
// RVO 계급 설정
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "RVO")
float AvoidanceWeight = 0.5f;
private:
// AI 컨트롤러 캐싱
class AAIController* AIController;
};
AI_RVO_Character.cpp
#include "AI_RVO_Character.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "AIController.h"
// Sets default values
AI_RVO_Character::AI_RVO_Character()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
// RVO 회피 시스템 활성화
UCharacterMovementComponent* MovementComponent = GetCharacterMovement();
if (MovementComponent)
{
MovementComponent->bUseRVOAvoidance = true;
MovementComponent->AvoidanceConsiderationRadius = AvoidanceRadius;
MovementComponent->AvoidanceWeight = 0.5f;
}
}
// Called when the game starts or when spawned
void AI_RVO_Character::BeginPlay()
{
Super::BeginPlay();
// AI 컨트롤러 참조 얻기
AIController = Cast<AAIController>(GetController());
// AI 컨트롤러가 없으면 로그 출력
if (!AIController)
{
UE_LOG(LogTemp, Warning, TEXT("%s is not controlled by an AIController. Movement functions will not work."), *GetName());
}
else if (TargetActor)
{
// 타겟 액터가 설정되어 있으면 자동으로 이동 시작
MoveToTarget();
}
}
// Called every frame
void AI_RVO_Character::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void AI_RVO_Character::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
void AI_RVO_Character::MoveToTarget()
{
if (!AIController)
{
UE_LOG(LogTemp, Warning, TEXT("MoveToTarget failed: No AI Controller for %s"), *GetName());
return;
}
if (!TargetActor)
{
UE_LOG(LogTemp, Warning, TEXT("MoveToTarget failed: No Target Actor set for %s"), *GetName());
return;
}
// 타겟 액터를 향해 이동
AIController->MoveToActor(
TargetActor, // 목표 액터
50.0f, // 도착 판정 반경
true, // 충돌 영역이 겹치면 도착으로 간주
true, // 경로 탐색 사용
false // 목적지를 네비게이션 메시에 투영(Projection)하지 않음
);
UE_LOG(LogTemp, Display, TEXT("%s moving to target: %s"),
*GetName(), *TargetActor->GetName());
}
void AI_RVO_Character::SetRVOAvoidanceEnabled(bool bEnable)
{
UCharacterMovementComponent* MovementComponent = GetCharacterMovement();
if (MovementComponent)
{
MovementComponent->bUseRVOAvoidance = bEnable;
}
}
충돌 처리 확인
언리얼 에디터를 실행하고 생성한 RVOCharacter를 레벨에 배치한 다음 TargetActor를 설정해준다.
길이 좁을 때 RVO를 끄게되면 일어나는 상황
RVO Character 블루프린트에서 "캐릭터 무브먼트"를 클릭하고 디테일창에서 RVO회피 사용을 false로 변경해준다.
서로 충돌해서 지나갈 수 없는걸 확인할 수 있다.
다시 RVO를 켜주면
충돌을 피해서 정상적으로 MoveToActor로 설정된 Actor까지 이동하는것을 확인할 수 있다.
AICharcter가 이동하는 목표를 디버깅하는 방법
Tick 이벤트노드에 Draw Debug Arrow 노드를 연결하고 Line Start/End노드에 각각 Get Actor Location노드를 연결해준 다음 Line End노드 Get Actor Location에 Target에는 AICharacter가 MoveToActor로 이동하는 목표인 Target Actor를 연결해준다.
'Unreal_Engine 5 > UE5 AI(NPC, Enemy)' 카테고리의 다른 글
UE5 AI(NPC, Enemy)(4) AIController의 MoveToActor와 MoveToLocation (0) | 2025.04.26 |
---|---|
UE5 AI(NPC, Enemy)(3) Nav Modifier Volume (0) | 2025.04.25 |
UE5 AI(NPC, Enemy)(2) NavMeshBoundsVolume, Navigation Invoker (1) | 2025.04.24 |
UE5 AI(NPC, Enemy)(1) AIController, Behavior Tree, Blackboard (0) | 2025.04.23 |