// AIConfigData.h
#pragma once
#include "AI/EGAIState.h"
#include "Engine/DataAsset.h"
#include "AIConfigData.generated.h"
USTRUCT(BlueprintType)
struct FAIActionProbability
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadOnly)
EAIState ActionState = EAIState::Idle;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
float Probability = 0.f;
};
UCLASS(BlueprintType)
class EG_API UAIConfigData : public UDataAsset
{
GENERATED_BODY()
public:
UAIConfigData();
// Idle Action
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Idle")
float MinWaitTime;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Idle")
float MaxWaitTime;
// Move Action
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Move")
float MoveRadius;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Move")
float MoveSpeed;
// Action State Probability
UPROPERTY(EditAnywhere, BlueprintReadOnly)
TArray<FAIActionProbability> ActionProbabilities;
};
// BTTask_RandomWait.cpp
#include "AI/Tasks/BTTask_RandomWait.h"
#include "AI/EGAIController.h"
#include "AI/DataAsset/AIConfigData.h"
UBTTask_RandomWait::UBTTask_RandomWait()
: RemainingTime(0.f)
{
bNotifyTick = true;
NodeName = TEXT("Random Wait");
}
EBTNodeResult::Type UBTTask_RandomWait::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
if (AAIController* AIController = OwnerComp.GetAIOwner())
{
if (AEGAIController* EGAIController = Cast<AEGAIController>(AIController))
{
float MinWaitTime = EGAIController->GetConfigData()->MinWaitTime;
float MaxWaitTime = EGAIController->GetConfigData()->MaxWaitTime;
RemainingTime = FMath::FRandRange(MinWaitTime, MaxWaitTime);
return EBTNodeResult::InProgress;
}
}
return EBTNodeResult::Failed;
}
void UBTTask_RandomWait::TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
Super::TickTask(OwnerComp, NodeMemory, DeltaSeconds);
RemainingTime -= DeltaSeconds;
if (RemainingTime <= 0.f)
{
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
}
}
MoveToLocation() 함수는 비동기로 처리가 되기 때문에 노드가 종료될 때까지 기다리는 것이 아니라 자동으로 종료가 되기 때문에, Tick을 통해서 이동이 완료될 시에 태스크 종료// BTTask_CustomMoveTo.cpp
#include "AI/Tasks/BTTask_CustomMoveTo.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Navigation/PathFollowingComponent.h"
#include "AI/EGAICharacter.h"
#include "AI/EGAIController.h"
#include "AI/DataAsset/AIConfigData.h"
UBTTask_CustomMoveTo::UBTTask_CustomMoveTo()
{
bNotifyTick = true;
NodeName = TEXT("Custom Move To");
}
EBTNodeResult::Type UBTTask_CustomMoveTo::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
if (AAIController* AIController = OwnerComp.GetAIOwner())
{
if (AEGAIController* EGAIController = Cast<AEGAIController>(AIController))
{
if (AEGAICharacter* EGAICharacter = Cast<AEGAICharacter>(EGAIController->GetPawn()))
{
float Speed = EGAIController->GetConfigData()->MoveSpeed;
EGAICharacter->GetCharacterMovement()->MaxWalkSpeed = Speed;
if (UBlackboardComponent* Blackboard = OwnerComp.GetBlackboardComponent())
{
FVector TargetLocation = Blackboard->GetValueAsVector("TargetLocation");
EPathFollowingRequestResult::Type Result = EGAIController->MoveToLocation(TargetLocation);
if (Result == EPathFollowingRequestResult::Type::RequestSuccessful)
{
return EBTNodeResult::InProgress;
}
}
}
}
}
return EBTNodeResult::Failed;
}
void UBTTask_CustomMoveTo::TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
Super::TickTask(OwnerComp, NodeMemory, DeltaSeconds);
if (AAIController* AIController = OwnerComp.GetAIOwner())
{
EPathFollowingStatus::Type Status = AIController->GetMoveStatus();
if (Status == EPathFollowingStatus::Idle)
{
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
}
}
}
공통점 : vector에서 가장 뒤에 원소를 추가함
push_back()
vector에 넣음#include <iostream>
#include <vector>
#include <string>
using namespace std;
struct Person {
string name;
int age;
Person(string n, int a) : name(move(n)), age(a) {
cout << "Constructed\n";
}
Person(const Person& p) {
cout << "Copied\n";
}
Person(Person&& p) noexcept {
cout << "Moved\n";
}
};
int main() {
vector<Person> v;
Person p("Alice", 20); // Constructed
v.push_back(p); // Copied
v.push_back(Person("Bob", 25)); // Constructed + Moved
}
-> vector 내부 capacity 부족으로 재할당이 발생했기 때문에 Moved가 2번 발생
emplace_back()
vector 안에서 직접 객체를 생성vector 내부에서 바로 생성자 호출에 쓰임v.emplace_back("Charlie", 30); // Constructed
