언리얼 엔진을 이용한 히트박스형 3인칭 액션 게임 프로젝트
언리얼 엔진 Behaviour Tree를 이용한 AI 구성을 중점적으로 다룸
사용 엔진
Unreal Engine 4 - 4.19
플랫폼
Window 64bit
장르
3인칭 액션
비헤이비어 트리와 블랙보드를 이용하여 값에 따라 보스가 어떤 행동을 할지 구성
비헤이비어 트리가 루트에서 부터 실행되면 플레이어를 감지하고 난수를 발생시킨 다음 공격할 수 있는 거리를 체크하고 생성된 난수에따라(확률) 공격 애니메이션을 실행
일반 패턴이 끝나면 잠시 대기후 플레이어 방향으로 회전
타겟의 좌우를 판별하는 로직
몬스터에서 타겟으로 향하는 벡터(타겟위치 - 몬스터위치) 와 Forward 벡터를 외적한다음 Up 벡터와 내적하면 그 값이 양수일때 왼쪽 음수일때 오른쪽으로 판별 할 수 있다.
보스와 플레이어와의 거리가 멀어 공격할 수 없는 상황일 때 난수를 발생시켜 원거리 패턴을 구사하고 일정거리 이하일땐 플레이어를 추격
메테오 액터 구성
메테오가 떨어질 위치를 표시할 데칼 머티리얼 구성
메테오 액터 구성
메테오 스폰 서비스
메테오 스폰 서비스 Blueprint
실행 결과
거리 측정 서비스
UBTService_Distance::UBTService_Distance()
{
NodeName = TEXT("Distance");
Interval = 1.0f;
}
void UBTService_Distance::TickNode(UBehaviorTreeComponent & OwnerComp, uint8 * NodeMemory, float DeltaSeconds)
{
Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);
APawn* ControllingPawn = OwnerComp.GetAIOwner()->GetPawn();
if (nullptr == ControllingPawn) return;
auto Grux = Cast<AGrux>(OwnerComp.GetAIOwner()->GetPawn());
bool bResult;
auto Target = Cast<ARaidPlayer>(OwnerComp.GetBlackboardComponent()->GetValueAsObject(AGruxAIController::TargetKey));
if (nullptr == Target)
return;
bResult = (Target->GetDistanceTo(ControllingPawn) >= 1000.0f);
OwnerComp.GetBlackboardComponent()->SetValueAsBool(AGruxAIController::Distance, bResult);
}
캐릭터와 몬스터의 거리가 1000이 넘으면 true를 반환하는 서비스
돌진 이동속도 서비스
블랙보드 설정
Distance
가 1000이하일때 거리가 1000이상 벌어지면 중단하고 바로 돌진패턴을 시작하도록 On Value Change
로 수정
실행 결과
범위 패턴 AnimNotify
RadialDamage
void AGrux::ServerApplyRadialDamage_Implementation(float RDamage,float Radius)
{
UGameplayStatics::ApplyRadialDamage(GetWorld(), RDamage, this->GetActorLocation(), Radius, nullptr, TArray<AActor*>(), this, false, ECC_GameTraceChannel5);
GruxLeftCheck->SetCollisionEnabled(ECollisionEnabled::NoCollision);
GruxRightCheck->SetCollisionEnabled(ECollisionEnabled::NoCollision);
FVector Center = this->GetActorLocation();
UWorld* World = GetWorld();
TArray<FOverlapResult> OverlapResults;
FCollisionQueryParams CollisionQueryParam(NAME_None, false, this);
bool bResult = World->OverlapMultiByChannel(
OverlapResults,
Center,
FQuat::Identity,
ECollisionChannel::ECC_GameTraceChannel5,
FCollisionShape::MakeSphere(Radius),
CollisionQueryParam
);
if (bResult)
{
for (auto OverlapResult : OverlapResults)
{
ARaidPlayer* Player = Cast<ARaidPlayer>(OverlapResult.GetActor());
if (Player != nullptr)
{
CHECK(Player != nullptr);
FVector PlayerLocation = Player->GetActorLocation();
FTransform PlayerTransform = Player->GetActorTransform();
if (!Player->IsDodge)
{
UGameplayStatics::PlaySoundAtLocation(this, GruxGroundHit, PlayerLocation);
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), GruxFireEffect, PlayerTransform, true);
}
}
}
}
}
데모조작키
W,A,S,D - 이동
오른쪽 마우스 클릭 - 공격
왼쪽 마우스 클릭 - 콤보 공격
왼쪽 Shift - 달리기
ESC - 메뉴
Z - 스킬