개발일지
08-13~ 08-14 BTS_UpdateDistance, Shield 변경 사항, Enemy Smooth Turn, Boss 기초작업
ksw8596
2024. 8. 14. 17: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