Unreal Team Project - 2주차 진행상황

윤정민·2022년 8월 22일
0

셈틀

목록 보기
3/4

1. AI in UnrealEngine

(1) 구조

  • 언리얼에서 Actor는 Controller의 지배를 받는다

    • Pawn(Player Character)

    • AI

(2) Computer가 명령을 내리는 방식(Behavior Tree)

  • AI를 제작하기 위한 방법은 여러가지가 있다.(Mechine Learning, State Mechine, ...)
  • Unreal에서는 Behavior Tree를 사용함

(3) Behavior Tree

  • Behavior Tree방식은 black board와 behavior tree, 두가지 asset을 사용함

1) Black Board

: AI의 기억 저장소로 AI가 판단을 내리는데 필요한 데이터들을 저장하는 역할

2) Behavior Tree

: 블랙보드가 가진 데이터를 토대로 의사결정을 내리고 이를 실행으로 옮기는 역할

2. AIController를 사용하지 않고 AI구현

우리가 구현하고자 하는 것이 간단하니 AI Perception Component만을 사용해서 구현 가능하다.


  • Enemy의 시야에 Player Character가 들어왔다면
    : Player Character를 향해 돌진
  • 그렇지 않다면
    : 원래 자리로 돌아가는 것

(1) 구현방법

1) Enemy.h

// 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; // 두 위치 사이의 거리의 제곱

2) Enemy.cpp

  • AEnemy() : 사용될 컴포넌트 설정 및 변수 초기화
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; // 거리 : 제일 큰 
  • SetNewRotation : rotation을 목표방향으로 설정
void AEnemy::SetNewRotation(FVector TargetPosition, FVector CurrentPosition) 
{
	FVector NewDirection = TargetPosition - CurrentPosition;
	NewDirection.Z = 0.0f;

	EnemyRotation = NewDirection.Rotation();
	//현재 actor의 rotation을 구한 rotation으로 설정
	SetActorRotation(EnemyRotation);
}

  • OnSensed : 속도 update
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());
			}
		}

	}
}
  • Tick
//속도가 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);
}
profile
그냥 하자

1개의 댓글

comment-user-thumbnail
2022년 9월 2일

덕분에 사용법 잘 이해했습니다. 감사합니다!

답글 달기