언리얼에서 Actor는 Controller의 지배를 받는다
Pawn(Player Character)
AI
: AI의 기억 저장소로 AI가 판단을 내리는데 필요한 데이터들을 저장하는 역할
: 블랙보드가 가진 데이터를 토대로 의사결정을 내리고 이를 실행으로 옮기는 역할
우리가 구현하고자 하는 것이 간단하니 AI Perception Component만을 사용해서 구현 가능하다.
// AI구현을 위한 AIPerceptionComponent 선언
UPROPERTY(VisibleDefaultsOnly, Category = Enemy)
class UAIPerceptionComponent* AIPerComp;
// AI 시야를 위한 AISenseConfig_Sight 생성
UPROPERTY(VisibleDefaultsOnly, Category = Enemy)
class UAISenseConfig_Sight* SightConfig;
UFUNCTION()
void OnSensed(const TArray<AActor*>& UpdatedActors);
// AI Rotation 정보를 저장할 변수
UPROPERTY(VisibleAnywhere, Category = Movement)
FRotator EnemyRotation;
// 생성시 Location을 저장할 변수
UPROPERTY(VisibleAnywhere, Category = Movement)
FVector BaseLocation;
// 속도를 저장할 변수
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Movement)
FVector CurrentVelocity;
// 속력을 저장할 변수
UPROPERTY(VisibleAnywhere, Category = Movement)
float MovementSpeed;
// 가고자 하는 위치로 rotation을 설정해줄 함수
void SetNewRotation(FVector TargetPosition, FVector CurrentPosition);
bool BackToBaseLocation; //원래 위치로 되돌아가고 있음
FVector NewLocation; //목표 위치
float DistanceSquared; // 두 위치 사이의 거리의 제곱
AIPerComp = CreateDefaultSubobject<UAIPerceptionComponent>(TEXT("AI Perception Component"));
SightConfig = CreateDefaultSubobject<UAISenseConfig_Sight>(TEXT("Sight Config"));
SightConfig->SightRadius = 1250.0f; // 시야 거리
SightConfig->LoseSightRadius = 1280.0f; // 비 시야 거리
SightConfig->PeripheralVisionAngleDegrees = 90.0f; // 시야각
// 모든 감감이 Sight를 유발하도록 설정
SightConfig->DetectionByAffiliation.bDetectEnemies = true;
SightConfig->DetectionByAffiliation.bDetectFriendlies = true;
SightConfig->DetectionByAffiliation.bDetectNeutrals = true;
SightConfig->SetMaxAge(0.1f); //감각을 잃는 기간 (0이면 잊혀지지 않음)
// 설정해준 시각을 AIPerComp이 관리하도록 함
AIPerComp->ConfigureSense(*SightConfig);
// 설정해준 시각을 최우선순위로 둠
AIPerComp->SetDominantSense(SightConfig->GetSenseImplementation());
//AIPerComp을 업데이트 시 Onsensed 함수 발동
AIPerComp->OnPerceptionUpdated.AddDynamic(this, &AEnemy::OnSensed);
CurrentVelocity = FVector::ZeroVector; //현재 속도를 0
MovementSpeed = 375.0f; //움직일때 속도 : 375
DistanceSquared = BIG_NUMBER; // 거리 : 제일 큰
void AEnemy::SetNewRotation(FVector TargetPosition, FVector CurrentPosition)
{
FVector NewDirection = TargetPosition - CurrentPosition;
NewDirection.Z = 0.0f;
EnemyRotation = NewDirection.Rotation();
//현재 actor의 rotation을 구한 rotation으로 설정
SetActorRotation(EnemyRotation);
}
void AEnemy::OnSensed(const TArray<AActor*>& UpdatedActors)
{
// 감지된 actor만큼 반복
for (int i = 0; i < UpdatedActors.Num(); i++)
{
감지된 actor의 정보를 info에 저장
FActorPerceptionBlueprintInfo Info;
AIPerComp->GetActorsPerception(UpdatedActors[i], Info);
//actor가 잘 감지되었다면 actor에게 돌진하도록 속도 update
if (Info.LastSensedStimuli[0].WasSuccessfullySensed())
{
FVector dir = UpdatedActors[i]->GetActorLocation() - GetActorLocation();
dir.Z = 0.0f;
CurrentVelocity = dir.GetSafeNormal() * MovementSpeed;
SetNewRotation(UpdatedActors[i]->GetActorLocation(), GetActorLocation());
}
//그렇지 않다면 원래 위치로 돌아가도록 속도 update
else
{
FVector dir = BaseLocation - GetActorLocation();
dir.Z = 0.0f;
//거리가 1보다 크다면 즉, 돌아갈 거리가 있다면
if (dir.SizeSquared2D() > 1.0f)
{
//속도 update
CurrentVelocity = dir.GetSafeNormal() * MovementSpeed;
BackToBaseLocation = true;
SetNewRotation(BaseLocation, GetActorLocation());
}
}
}
}
//속도가 0이 아니라면
if (!CurrentVelocity.IsZero())
{
//actor의 위치값를 update
NewLocation = GetActorLocation() + CurrentVelocity * DeltaTime;
//돌아가는 중이라면
if (BackToBaseLocation)
{
//남은 거리가 더 적다면 즉, 돌아갈 거리가 더 있다면
if ((NewLocation - BaseLocation).SizeSquared2D() < DistanceSquared)
{
// Distance 업데이트
DistanceSquared = (NewLocation - BaseLocation).SizeSquared2D();
}
//그렇지 않다면 즉, 도착했다면
else
{
//속도를 제로벡터로 설정
CurrentVelocity = FVector::ZeroVector;
//남은 거리도 초기값과 똑같이 설정
DistanceSquared = BIG_NUMBER;
//목적지에 도달 했으니 돌아가고 있음을 false로 설정
BackToBaseLocation = false;
//초기 rotation으로 rotatoin설정
SetNewRotation(GetActorForwardVector(), GetActorLocation());
}
}
//actor의 위치를 update한 위치값으로 set
SetActorLocation(NewLocation);
}
덕분에 사용법 잘 이해했습니다. 감사합니다!