초보 코린이의 성장 일지
UE4 Behavior, AI Hitted 본문
Behavior Tree를 통해 Enemy Hitted를 구현해 볼 것이다.
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/BTTaskNode.h"
#include "CBTTaskNode_Hitted.generated.h"
UCLASS()
class U2212_06_API UCBTTaskNode_Hitted : public UBTTaskNode
{
GENERATED_BODY()
public:
UCBTTaskNode_Hitted();
protected:
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
virtual void TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;
};
#include "BehaviorTree/CBTTaskNode_Hitted.h"
#include "Global.h"
#include "Characters/CEnemy_AI.h"
#include "Characters/CAIController.h"
#include "Components/CStateComponent.h"
UCBTTaskNode_Hitted::UCBTTaskNode_Hitted()
{
bNotifyTick = true;
NodeName = "Hitted";
}
EBTNodeResult::Type UCBTTaskNode_Hitted::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
Super::ExecuteTask(OwnerComp, NodeMemory);
ACAIController* controller = Cast<ACAIController>(OwnerComp.GetOwner());
controller->StopMovement(); // Hit시 움직임 off
return EBTNodeResult::InProgress;
}
void UCBTTaskNode_Hitted::TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
Super::TickTask(OwnerComp, NodeMemory, DeltaSeconds);
ACAIController* controller = Cast<ACAIController>(OwnerComp.GetOwner());
ACEnemy_AI* ai = Cast<ACEnemy_AI>(controller->GetPawn());
UCStateComponent* state = CHelpers::GetComponent<UCStateComponent>(ai);
if (state->IsHittedMode() == false)
{
// hit가 아니라면 종료.
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return;
}
}
1. Task Hitted 조건을 체크해주고, Hit가 아니라면 Tick에서 종료시켜준다.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Characters/ICharacter.h"
#include "CEnemy.generated.h"
UCLASS()
class U2212_06_API ACEnemy
: public ACharacter
, public IICharacter
{
GENERATED_BODY()
protected:
virtual void Hitted();
public:
virtual void End_Hitted() override;
};
#include "Characters/CEnemy.h"
#include "Global.h"
#include "CAnimInstance.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/CMontagesComponent.h"
#include "Components/CMovementComponent.h"
#include "Components/CStatusComponent.h"
#include "Weapons/CWeaponStructures.h"
void ACEnemy::Hitted()
{
// Apply Damage
{
Status->Damage(Damage.Power);
Damage.Power = 0;
}
//TODO: 데미지 처리
//TODO: 사망 처리
// Change Color
{
// 맞으면 색 변경
Change_Color(this, FLinearColor::Red);
// 데미지 저장
FTimerDelegate timerDelegate;
timerDelegate.BindUFunction(this, "RestoreColor");
GetWorld()->GetTimerManager().SetTimer(RestoreColor_TimerHandle, timerDelegate, 0.2f, false);
}
if (!!Damage.Event && !!Damage.Event->HitData)
{
FHitData* data = Damage.Event->HitData;
data->PlayMontage(this);
data->PlayHitStop(GetWorld());
data->PlaySoundWave(this);
data->PlayEffect(GetWorld(), GetActorLocation(), GetActorRotation());
if (Status->IsDead() == false)
{
// 때린 객체 바라보게 만들기.
FVector start = GetActorLocation();
FVector target = Damage.Character->GetActorLocation();
FVector direction = target - start;
direction.Normalize();
LaunchCharacter(-direction * data->Launch, false, false); // 밀리는 Launch값
SetActorRotation(UKismetMathLibrary::FindLookAtRotation(start, target)); // 바라보게 만들기
}
}
if (Status->IsDead())
{
State->SetDeadMode();
return;
}
Damage.Character = nullptr;
Damage.Causer = nullptr;
Damage.Event = nullptr;
}
1. Hitted에 관련된 함수들 자식에서 재정의해서 사용할 수 있도록 virtual로 만들어준다.
2. 구조를 보면 부모인 Enemy에서 SetDeadMode로 들어오는 조건이 보일 것이다.
3. Enemy AI에서는 이 조건이 성립된 후 자신의 Hitted가 실행되기 때문에, 재정의해서 사용해야한다.
#pragma once
#include "CoreMinimal.h"
#include "Characters/CEnemy.h"
#include "CEnemy_AI.generated.h"
UCLASS()
class U2212_06_API ACEnemy_AI : public ACEnemy
{
GENERATED_BODY()
protected:
void Hitted() override;
public:
void End_Hitted() override;
};
#include "Characters/CEnemy_AI.h"
#include "Global.h"
#include "Components/CWeaponComponent.h"
#include "Components/CAIBehaviorComponent.h"
#include "Components/WidgetComponent.h"
#include "Components/CStatusComponent.h"
#include "Widgets/CUserWidget_Label.h"
void ACEnemy_AI::Hitted()
{
Super::Hitted();
CheckTrue(State->IsDeadMode());
Behavior->SetHittedMode();
}
void ACEnemy_AI::End_Hitted()
{
Super::End_Hitted();
Behavior->SetWaitMode();
}
1. 부모에서 DeadMode라면 실행하면 안되므로, 체크후 모드를 전환해준다.
2. End에서는 Wait로 돌려준다.
1. Hit될 몽타주에서 Hitted로 타입을 변경시켜준다.
1. Hit가되도 Hitted Task로 들어가질 않는다. 그 이유가 처음 시작할때 루트에서 Wait 상태로 들어와서 아래로 내려오는 구조이다.
2. Wait로 들어오게될때 Wait를 판단할 데코레이터가 없기 때문에, Wait를 Patrol전에 줌으로써 실행 시키게 만들어 준다.
https://www.youtube.com/watch?v=NvMKSK3eiiY
'언리얼' 카테고리의 다른 글
UE4 Behavior, AI Abort, Range (0) | 2023.08.07 |
---|---|
UE4 Behavior, AI Equip (0) | 2023.08.03 |
UE4 Behavior, AI Action (2) | 2023.07.27 |
UE4 Behavior, AI Equip (0) | 2023.07.26 |
UE4 Behavior Tree, Patrol (0) | 2023.07.25 |
Comments