본문 바로가기
개발일지

08-13~ 08-14 BTS_UpdateDistance, Shield 변경 사항, Enemy Smooth Turn, Boss 기초작업

by ksw8596 2024. 8. 14.
  • BTS_UpdateDistance
#include "Enemy/BTTask/FBTS_UpdateDistance.h"
#include "AIController.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "Skill/Action/FActionComponent.h"

UFBTS_UpdateDistance::UFBTS_UpdateDistance()
{
	NodeName = "BTS_UpdateDistance";

	bNotifyBecomeRelevant = true;
	Interval = 0.1f; // 0.1초마다 실행
	RandomDeviation = 0;
}

void UFBTS_UpdateDistance::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
	Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);

	AAIController* Owner = OwnerComp.GetAIOwner();
	APawn* ControllPawn = Owner->GetPawn();
	UBlackboardComponent* BlackboardComp = OwnerComp.GetBlackboardComponent();

	AActor* TargetActor = Cast<AActor>(BlackboardComp->GetValueAsObject(TEXT("TargetActor")));

	FVector V1 = ControllPawn->GetActorLocation();
	FVector V2 = TargetActor->GetActorLocation();
	
	float Distance = FVector::Distance(V1, V2);

	if (BlackboardComp)
	{
		BlackboardComp->SetValueAsFloat(DistanceName, Distance);
	}
}

FBTS_UpdateDistance.cpp

 

  거리값을 계산하기위한 BTService

 

  • Shield
AFShield::AFShield()
{
	StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ShiledMesh"));
    //추가
	StaticMesh->OnComponentBeginOverlap.AddDynamic(this, &AFShield::OnComponentBeginOverlap);
}

===================================중략===================================

//Actor와 Shield와 겹쳤을때 밀어주는 로직
void AFShield::OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	if(OtherActor && OtherActor != this)
	{
		PushActor(OtherActor);
	}
}

void AFShield::PushActor(AActor* ActorPush)
{
	if(ActorPush)
	{
		ACharacter* Character = Cast<ACharacter>(ActorPush);
		if(Character)
		{
			FVector ActorLocation = ActorPush->GetActorLocation();
			FVector ShiledLocation = GetActorLocation();

			FVector Distance = (ActorLocation - ShiledLocation);
			Distance.Normalize();

			if (Distance.Size() < 300)
			{
				Character->LaunchCharacter(Distance * 300, true, true);
			}
		}
	}
}

FShield.cpp

 

  쉴드에서 밀어주는 로직을 Overlap형태로 변경

 

  • Enemy Smooth Turn
//EnemyAIController.h
protected:
	/** Update direction AI is looking based on FocalPoint */
	virtual void UpdateControlRotation(float DeltaTime, bool bUpdatePawn = true);
	FRotator SmoothTargetRotation;

 

//EnemyAIController.cpp
#include "Enemy/FEnemyAIController.h"
#include "Enemy/FEnemyCharacterBase.h"
#include "Kismet/KismetMathLibrary.h"
#include "BehaviorTree/BehaviorTree.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "Player/FAttributeComponent.h"

===================================중략===================================

void AFEnemyAIController::UpdateControlRotation(float DeltaTime, bool bUpdatePawn)
{
	Super::UpdateControlRotation(DeltaTime, false);

	if (bUpdatePawn)
	{
		APawn* const MyPawn = GetPawn();
		const FRotator CurrentPawnRotation = MyPawn->GetActorRotation();

		//Calculate smoothed rotation
		SmoothTargetRotation = UKismetMathLibrary::RInterpTo_Constant(MyPawn->GetActorRotation(), ControlRotation, DeltaTime, SmoothFocusInterpSpeed);
		//Check if we need to change
		if (CurrentPawnRotation.Equals(SmoothTargetRotation, 1e-3f) == false)
		{
			//Change rotation using the Smooth Target Rotation
			MyPawn->FaceRotation(SmoothTargetRotation, DeltaTime);
		}
	}
}

FEnemyAIController.cpp

 

  SmoothFocusInterpSpeed를통해 회전하는 속도를 조절할 수 있다.

 

 

  • Boss 기초작업
//EnemyAIController.cpp
#include "Enemy/FEnemyAIController.h"
#include "Enemy/FEnemyCharacterBase.h"
#include "Kismet/KismetMathLibrary.h"
#include "BehaviorTree/BehaviorTree.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "Player/FAttributeComponent.h"

===================================중략===================================
void AFEnemyAIController::OnTargetDetected(AActor* Actor, FAIStimulus const Stimulus)
{
	AFEnemyCharacterBase* Enemy = Cast<AFEnemyCharacterBase>(Self);
	int32 Revival = Enemy->AttributeComp->CharacterStatusInfo.RevivalCount;
	//Tag컴포넌트화되면 변경
	//Tag가 Player이고 Player를 봤을때

	if (Actor->ActorHasTag("Player"))
	{
		TargetActor = Actor;
		//Blackboard에 값을 넣어준다.
		if(Stimulus.WasSuccessfullySensed())
		{
			SetAttacking(Actor);
		}
	}
	if (Enemy->bBoss && Revival > 0)
	{
		SetPhase1();
	}
	else if (Enemy->bBoss && Revival == 0)
	{
		SetPhase2();
	}
}

===================================중략===================================

void AFEnemyAIController::SetPhase1()
{
	GetBlackboardComponent()->SetValueAsEnum(TEXT("PhaseType"), 0);
}

void AFEnemyAIController::SetPhase2()
{
	GetBlackboardComponent()->SetValueAsEnum(TEXT("PhaseType"), 1);
}

 

  AIController에서 Boss가 체크되면 Revival(부활 개수)검사에 따라서 페이즈를 나누었다.

 

 

참조자료

Smooth Focus AI

https://dev.epicgames.com/community/learning/tutorials/ZYVB/unreal-engine-smooth-focus-using-ai-setfocus-setfocalpoint