적의 상태에 따라 이동속도를 다르게 설정해보자.  적 Behavior Tree에 순찰 기능을 추가하고 Player가 접근하면 달려오도록 수정해보자.

 

 

목차

     

     


     

     

     

     
    Plugins
     
      Weapon
     
        Resource
     
          Icon128.png
    weapon_thumbnail_icon.png
     
        Source
     
          Weapon  
          SWeaponCheckBoxes.h .cpp
    SWeaponDetailsView.h .cpp

    SWeaponDoActionData.h .cpp
    SWeaponEquipmentData.h .cpp
    SWeaponHitData.h .cpp

    SWeaponLeftArea.h .cpp
    Weapon.Build.cs
    WeaponAssetEditor.h .cpp
    WeaponAssetFactory.h .cpp
    WeaponCommand.h .cpp 
    WeaponContextMenu.h .cpp
    WeaponModule.h .cpp
    WeaponStyle.h .cpp 
     
       

     

     
    Source
        BehaviorTree
        CBTService_Melee.h .cpp
    CBTTaskNode_Patrol.h .cpp 생성
    CBTTaskNode_Speed.h .cpp 생성
    CPatrol.h .cpp 생성
        Characters
        CAIController.h .cpp
    CAnimInstance.h .cpp
    CEnemy.h .cpp 
    CEnemy_AI.h .cpp
    CPlayer.h.cpp
    ICharacter.h .cpp
        Components
        CAIBehaviorComponent.h .cpp
    CFeetComponent.h .cpp

    CMontagesComponent.h .cpp 
    CMovementComponent.h .cpp 
    CStateComponent.h .cpp
    CStatusComponent.h .cpp  
    CWeaponComponent.h .cpp 
    CZoomComponent.h .cpp
        Notifies
        CAnimNotifyState_BeginAction.h .cpp
    CAnimNotifyState_BowString.h .cpp
    CAnimNotify_CameraShake.h .cpp 
    CAnimNotify_End_Parkour
    CAnimNotifyState_EndAction.h .cpp
    CAnimNotify_EndState.h .cpp
    CAnimNotifyState.h .cpp
    CAnimNotifyState_CameraAnim.h .cpp
    CAnimNotifyState_Collision.h .cpp 
    CAnimNotifyState_Combo.h .cpp
    CAnimNotifyState_Equip.h .cpp
    CAnimNotifyState_SubAction.h .cpp
        Parkour
        CParkourComponent.h .cpp
        Utilities
        CHelper.h
    CLog.h .cpp
        Weapons
        CArrow.h .cpp
    CAura.h .cpp
    CCamerModifier.h .cpp
    CGhostTrail.h .cpp
    CRotate_Object.h .cpp
    CThornObject.h .cpp
    CAnimInstance_Bow.h .cpp
    CAttachment_Bow.h .cpp
    CDoAction_Around.h .cpp
    CDoAction_Bow.h .cpp
    CDoAction_Combo.h .cpp
    CDoAction_Warp.h .cpp
    CSubAction_Around.h .cpp
    CSubAction_Bow.h .cpp
    CSubAction_Fist.h .cpp
    CSubAction_Hammer.h .cpp
    CSubAction_Sword.h .cpp
    CDoAction_Warp.h .cpp

    CAttachment.h .cpp
    CDoAction.h .cpp
    CEquipment.h .cpp
    CSubAction.h .cpp
    CWeaponAsset.h .cpp
    CWeaponStructures.h .cpp
        Global.h
    CGameMode.h .cpp
    U2212_06.Build.cs
        U2212_06.uproject
     

     

     

     

    Speed 변경하기

     

     


     

    CBTTaskNode_Speed 생성

     

    새 C++ 클래스 - BTTaskNode - CBTTaskNode_Speed  생성

     

    CBTTaskNode_Speed.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "BehaviorTree/BTTaskNode.h"
    #include "Components/CMovementComponent.h"
    #include "CBTTaskNode_Speed.generated.h"
    
    UCLASS()
    class U2212_06_API UCBTTaskNode_Speed : public UBTTaskNode
    {
    	GENERATED_BODY()
    
    private:
    	UPROPERTY(EditAnywhere, Category = "Type")
    		ESpeedType Type;
    
    public:
    	UCBTTaskNode_Speed();
    
    private:
    	EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
    };

     

     

     

    CBTTaskNode_Speed.cpp

    더보기
    #include "BehaviorTree/CBTTaskNode_Speed.h"
    #include "Global.h"
    #include "Characters/CEnemy_AI.h"
    #include "Characters/CAIController.h"
    
    UCBTTaskNode_Speed::UCBTTaskNode_Speed()
    {
    	NodeName = "Speed";
    }
    
    EBTNodeResult::Type UCBTTaskNode_Speed::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
    {
    	//EBTNodeResult::Type은 Composite과 Task 공유해서 사용한다.
    	Super::ExecuteTask(OwnerComp, NodeMemory);
    
    	
    	ACAIController* controller = Cast<ACAIController>(OwnerComp.GetOwner());//OwnerComp로부터 controller를 가져온다.
    	ACEnemy_AI* ai = Cast<ACEnemy_AI>(controller->GetPawn());//가져온 controller의 Pawn을 사용하여 Enemy_AI를 캐스팅한다.
    	UCMovementComponent* movement = CHelpers::GetComponent<UCMovementComponent>(ai);
    
    	movement->SetSpeed(Type);//CMovementComponent의 SetSpeed함수로 Type으로 지정한 속도를 넣고 변경한다.
    
    	return EBTNodeResult::Succeeded;
    }

     


     

     

    ※ 참고) EBTNodeResult의 Type들 - Succeeded, Failed, Aborted, InProgress

     

    EBTNodeResultBehaviorTreeTypes.h에 선언되어 있고,

    Behavior Tree 내의 Composite, Task 모두 사용한다. 

     

     


     

     

    BT_Melee

     

     


     

     

    실행화면

     

     

     


     

     

     

     

    Patrol

     


     

    Build.cs

     

    Build.cs

    using UnrealBuildTool;
    
    public class U2212_06 : ModuleRules
    {
    	public U2212_06(ReadOnlyTargetRules Target) : base(Target)
    	{
            PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
    
    		PublicIncludePaths.Add(ModuleDirectory);
    
    
            PublicDependencyModuleNames.Add("Core");
    
            PrivateDependencyModuleNames.Add("CoreUObject");
            PrivateDependencyModuleNames.Add("Engine");
            PrivateDependencyModuleNames.Add("InputCore");
    
            PublicDependencyModuleNames.Add("Niagara");
    
            PublicDependencyModuleNames.Add("AIModule");
            PublicDependencyModuleNames.Add("GameplayTasks");
            PublicDependencyModuleNames.Add("NavigationSystem");
        }
    }

    모듈 추가

    •  PublicDependencyModuleNames.Add("NavigationSystem");

     


     

     

     

    CPatrolPath 생성

     

    새 C++ 클래스 - Actor - CPatrolPath 생성

     

     

    CPatrolPath.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "GameFramework/Actor.h"
    #include "CPatrolPath.generated.h"
    
    UCLASS()
    class U2212_06_API ACPatrolPath : public AActor
    {
    	GENERATED_BODY()
    
    private:
    	UPROPERTY(EditAnywhere, Category = "Loop")
    		bool bLoop;
    
    	UPROPERTY(EditAnywhere, Category = "Path")
    		int32 Index;
    
    	UPROPERTY(EditAnywhere, Category = "Path")
    		bool bReverse;
    
    private:
    	UPROPERTY(VisibleDefaultsOnly)
    		class USceneComponent* Root;
    
    	UPROPERTY(VisibleDefaultsOnly)
    		class USplineComponent* Spline;
    
    	UPROPERTY(VisibleDefaultsOnly)
    		class UTextRenderComponent* Text;
    
    public:
    	FORCEINLINE class USplineComponent* GetSpline() { return Spline; }
    
    public:	
    	ACPatrolPath();
    	void OnConstruction(const FTransform& Transform) override;
    
    protected:
    	virtual void BeginPlay() override;
    
    public:
    	FVector GetMoveTo();
    	void UpdateIndex();
    
    };

     

     

     

    CPatrolPath.cpp

    더보기
    #include "BehaviorTree/CPatrolPath.h"
    #include "Global.h"
    #include "Components/SplineComponent.h"
    #include "Components/TextRenderComponent.h"
    
    ACPatrolPath::ACPatrolPath()
    {
    	bRunConstructionScriptOnDrag = false;
    
    	CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
    	CHelpers::CreateComponent<USplineComponent>(this, &Spline, "Spline", Root);
    	CHelpers::CreateComponent<UTextRenderComponent>(this, &Text, "Text", Root);
    
    	Spline->SetRelativeLocation(FVector(0, 0, 30));
    	Spline->bHiddenInGame = false;
    
    	Text->SetRelativeLocation(FVector(0, 0, 120));
    	Text->SetRelativeRotation(FRotator(0, 180, 0));
    	Text->HorizontalAlignment = EHorizTextAligment::EHTA_Center;
    	Text->TextRenderColor = FColor::Red;
    	Text->bHiddenInGame = true;
    }
    
    void ACPatrolPath::OnConstruction(const FTransform& Transform)
    {
    	Super::OnConstruction(Transform);
    
    #if WITH_EDITOR
    	Text->Text = FText::FromString(GetActorLabel());//GetActorLabel()은 Editor에 있는 함수라서 Project Package 시에는 지워줘야 한다.
    #endif
    
    	Spline->SetClosedLoop(bLoop);
    }
    
    void ACPatrolPath::BeginPlay()
    {
    	Super::BeginPlay();
    }
    
    FVector ACPatrolPath::GetMoveTo()
    {
    	//다음 Spline Point 이동을 위해 Spline의 다음 Point의 World 위치를 리턴. 
    	return Spline->GetLocationAtSplinePoint(Index, ESplineCoordinateSpace::World);
    }
    
    void ACPatrolPath::UpdateIndex()
    {
    	int32 count = Spline->GetNumberOfSplinePoints();//cout변수에 Spline Points 숫자를 넣어준다.
    
    	if (bReverse)//역방향
    	{
    		if (Index > 0)
    		{
    			Index--;
    
    			return;
    		}
    
    		if (Spline->IsClosedLoop())
    		{
    			Index = count - 1;
    
    			return;
    		}
    
    		Index = 1;
    		bReverse = false;
    
    		return;
    	}
    
    	if (Index < count - 1)//정방향
    	{
    		Index++;
    
    		return;
    	}
    
    	if(Spline->IsClosedLoop())
    	{
    		Index = 0;
    
    		return;
    	}
    
    	Index = count - 2;
    	bReverse = true;//역방향으로 만든다.
    }

     

     


     

     

    BP_CPatrolPath 생성 + Viewport에 Spline 그리기

     

    BP_CPatrolPath 생성 후 Viewport에 Spline을 배치한다.

    BP_Enemy_Melee의 Patrol - Project Path에 Viewport에 배치한 BP_CPatrolPath 중 하나를 할당한다.


     

     

     

    CBTTaskNode_Patrol 생성

     

    새 C++ 클래스 - BTTaskNode - CBTTaskNode_Patrol 생성

     

    CBTTaskNode_Patrol.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "BehaviorTree/BTTaskNode.h"
    #include "CBTTaskNode_Patrol.generated.h"
    
    UCLASS()
    class U2212_06_API UCBTTaskNode_Patrol : public UBTTaskNode
    {
    	GENERATED_BODY()
    
    private:
        UPROPERTY(EditAnywhere, Category = "Patrol")
            bool bDebugMode;//디버그 모드 on/off
    
        UPROPERTY(EditAnywhere, Category = "Patrol")
            float AcceptanceDistance = 20;//순찰 경로 간격
    
        UPROPERTY(EditAnywhere, Category = "Random")
            float RandomRadius = 1500;//순찰 경로가 없을 때 랜덤으로 움직이는 범위
    
    public:
        UCBTTaskNode_Patrol();
    
    protected:
        virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
        virtual void TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;
    
    };

     

     

     

    CBTTaskNode_Patrol.cpp

    더보기
    #include "BehaviorTree/CBTTaskNode_Patrol.h"
    #include "Global.h"
    #include "CPatrolPath.h"
    #include "Components/SplineComponent.h"
    #include "Components/CAIBehaviorComponent.h"
    #include "Characters/CEnemy_AI.h"
    #include "Characters/CAIController.h"
    #include "NavigationSystem.h"
    
    UCBTTaskNode_Patrol::UCBTTaskNode_Patrol()
    {
    	NodeName = "Patrol";
    
    	bNotifyTick = true;//작성해야 Tick이 실행된다. Tick을 실행하려면 반드시 작성해야 한다.
    }
    
    EBTNodeResult::Type UCBTTaskNode_Patrol::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
    {
    	Super::ExecuteTask(OwnerComp, NodeMemory);
    
    	ACAIController* controller = Cast<ACAIController>(OwnerComp.GetOwner());
    	ACEnemy_AI* ai = Cast<ACEnemy_AI>(controller->GetPawn());
    	UCAIBehaviorComponent* behavior = CHelpers::GetComponent<UCAIBehaviorComponent>(ai);
    
    	//PatrolPath가 있을때
    	if (!!ai->GetPatrolPath())
    	{
    		//움직일 위치를 Blackboard에 넣는다.
    		FVector moveToPoint = ai->GetPatrolPath()->GetMoveTo();
    		behavior->SetPatrolLocation(moveToPoint);
    
    		if (bDebugMode)//순찰 경로 DrawDebug
    			DrawDebugSphere(ai->GetWorld(), moveToPoint, 25, 25, FColor::Green, true, 5);
    	
    		return EBTNodeResult::InProgress;
    	}
    
    	//PatrolPath가 없을때
    	FVector location = ai->GetActorLocation();
    
    	UNavigationSystemV1* navSystem = FNavigationSystem::GetCurrent<UNavigationSystemV1>(ai->GetWorld());
    	CheckNullResult(navSystem, EBTNodeResult::Failed);//navSystem이 없다면 EBTNodeResult::Failed 리턴
    
    	//결과값을 리턴 받는다.
    	FNavLocation point(location);
    	while (true)
    	{
    		//갈 수 있는 위치가 나올때까지 계속 돌린다.
    		if (navSystem->GetRandomPointInNavigableRadius(location, RandomRadius, point))
    			break;
    	}
    
    	behavior->SetPatrolLocation(point.Location);
    
    	if (bDebugMode)//순찰 경로 DrawDebug
    		DrawDebugSphere(ai->GetWorld(), point.Location, 25, 25, FColor::Green, true, 5);
    
    	return EBTNodeResult::InProgress;
    }
    
    void UCBTTaskNode_Patrol::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());
    	UCAIBehaviorComponent* behavior = CHelpers::GetComponent<UCAIBehaviorComponent>(ai);
    
    	FVector location = behavior->GetPatrolLocation();//이동할 위치를 location 변수에 담아준다.
    	EPathFollowingRequestResult::Type result = controller->MoveToLocation(location, AcceptanceDistance, false);
    
    	switch(result)
    	{
    		case EPathFollowingRequestResult::Failed:
    		{
    			FinishLatentTask(OwnerComp, EBTNodeResult::Failed);			
    		}
    		break;
    
    		case EPathFollowingRequestResult::AlreadyAtGoal:
    		{
    			if (ai->GetPatrolPath())
    				ai->GetPatrolPath()->UpdateIndex();//다음 위치를 갱신해준다.
    
    			FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
    		}
    		break;
    	}
    }

     

     

     

     

     

    ※ 참고) PathFollwingComponent.h의  EPathFollowingRequestResult


     

    CEnemy_AI

     

    CEnemy_AI.h

    더보기
    #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()
    
    private:
    	UPROPERTY(EditDefaultsOnly, Category = "AI")
    		class UBehaviorTree* BehaviorTree;
    
    	UPROPERTY(EditDefaultsOnly, Category = "AI")
    		uint8 TeamID = 2;//TeamID를 0~255번까지 지정가능하다. 255번은 중립이다. ID 같으면 아군이고 ID가 다르면 적이다.
    
    private:
    	UPROPERTY(EditDefaultsOnly, Category = "Label")
    		float LabelViewAmount = 3000.0f;
    
    private:
    	UPROPERTY(EditAnywhere, Category = "Patrol")
    		class ACPatrolPath* PatrolPath;//클래스 밖에서도 지정할 수 있어야 한다. 서로간 만들어진 객체를 참조할것이라서 softObjectPtr 사용
    
    #if WITH_EDITOR
    private:
    	UPROPERTY(VisibleDefaultsOnly)
    		class UWidgetComponent* LabelWidget;
    #endif
    	
    private:
    	UPROPERTY(VisibleDefaultsOnly)
    		class UCWeaponComponent* Weapon;
    
    	UPROPERTY(VisibleDefaultsOnly)
    		class UCAIBehaviorComponent* Behavior;
    
    public:
    	FORCEINLINE uint8 GetTeamID() { return TeamID; }
    	FORCEINLINE class UBehaviorTree* GetBehaviorTree() { return BehaviorTree; }
    	FORCEINLINE class ACPatrolPath* GetPatrolPath() { return PatrolPath; }
    
    public:
    	ACEnemy_AI();
    
    protected:
    	virtual void BeginPlay() override;
    
    public:
    	virtual void Tick(float DeltaTime) override;
    
    private:
    	void UpdateLabelRenderScale();
    };

    변수 추가

    • UPROPERTY(EditAnywhere, Category = "Patrol")
      class ACPatrolPath* PatrolPath;
      • 클래스 밖에서도 지정할 수 있어야 한다. 서로간 만들어진 객체를 참조할것이라서 softObjectPtr 사용

     

    인라인 함수 추가

    • FORCEINLINE class ACPatrolPath* GetPatrolPath() { return PatrolPath; }

     

     

     

    CEnemy_AI.cpp

    더보기
    #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"
    
    ACEnemy_AI::ACEnemy_AI()
    {
    	PrimaryActorTick.bCanEverTick = true;
    
    	CHelpers::CreateComponent<UWidgetComponent>(this, &LabelWidget, "Label", GetMesh());
    
    	CHelpers::CreateActorComponent<UCWeaponComponent>(this, &Weapon, "Weapon");
    	CHelpers::CreateActorComponent<UCAIBehaviorComponent>(this, &Behavior, "Behavior");
    
    
    	TSubclassOf<UCUserWidget_Label> labelClass;
    	CHelpers::GetClass<UCUserWidget_Label>(&labelClass, "WidgetBlueprint'/Game/Widgets/WB_Label.WB_Label_C'");
    	LabelWidget->SetWidgetClass(labelClass);
    	LabelWidget->SetRelativeLocation(FVector(0, 0, 220));
    	LabelWidget->SetDrawSize(FVector2D(120, 0));
    	LabelWidget->SetWidgetSpace(EWidgetSpace::Screen);
    }
    
    void ACEnemy_AI::BeginPlay()
    {
    	Super::BeginPlay();
    
    	LabelWidget->InitWidget();
    
    	UCUserWidget_Label* label = Cast<UCUserWidget_Label>(LabelWidget->GetUserWidgetObject());
    	label->UpdateHealth(Status->GetHealth(), Status->GetMaxHealth());
    	label->UpdateName(GetName());
    	label->UpdateControllerName(GetController()->GetName());
    }
    
    void ACEnemy_AI::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    
    	UCUserWidget_Label* label = Cast<UCUserWidget_Label>(LabelWidget->GetUserWidgetObject());
    
    	if (!!label)
    	{
    		label->UpdateHealth(Status->GetHealth(), Status->GetMaxHealth());
    
    		UpdateLabelRenderScale();
    	}
    }
    
    void ACEnemy_AI::UpdateLabelRenderScale()
    {
    	UCUserWidget_Label* label = Cast<UCUserWidget_Label>(LabelWidget->GetUserWidgetObject());
    	CheckNull(label);
    
    
    	APlayerCameraManager* cameraManager = UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0);
    
    	FVector cameraLocation = cameraManager->GetCameraLocation();
    	FVector targetLocation = GetController()->GetTargetLocation();
    
    	float distance = FVector::Distance(cameraLocation, targetLocation);
    	float sizeRate = 1.0f - (distance / LabelViewAmount);
    
    	if (distance > LabelViewAmount)
    	{
    		label->SetVisibility(ESlateVisibility::Collapsed);
    
    		return;
    	}
    
    	label->SetVisibility(ESlateVisibility::Visible);
    	label->SetRenderScale(FVector2D(sizeRate, sizeRate));
    }

    변경사항 없음.

     

     

     


     

     

    CAIBehaviorComponent

     

     

    CAIBehaviorComponent.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "Components/ActorComponent.h"
    #include "CAIBehaviorComponent.generated.h"
    
    UENUM(BlueprintType)
    enum class EAIStateType : uint8
    {
    	Wait = 0, Approach, Action, Patrol, Hitted, Avoid, Dead, Max,
    };
    DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FAIStateTypeChanged, EAIStateType, InPrevType, EAIStateType, InNewType);
    
    UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
    class U2212_06_API UCAIBehaviorComponent : public UActorComponent
    {
    	GENERATED_BODY()
    
    private:
    	UPROPERTY(EditAnywhere, Category = "Key")
    		FName AIStateTypeKey = "AIState";
    
    	UPROPERTY(EditAnywhere, Category = "Key")
    		FName TargetKey = "Target";
    
    	UPROPERTY(EditAnywhere, Category = "Key")
    		FName PatrolLocationKey = "Patrol_Location";
    	
    private:
    	EAIStateType GetType();
    
    public:
    	bool IsWaitMode();
    	bool IsApproachMode();
    	bool IsActionMode();
    	bool IsPatrolMode();
    	bool IsHittedMode();
    	bool IsAvoidMode();
    	bool IsDeadMode();
    
    public:	
    	UCAIBehaviorComponent();
    
    protected:
    	virtual void BeginPlay() override;
    
    public:
    	FORCEINLINE void SetBlackboard(class UBlackboardComponent* InBlackboard) { Blackboard = InBlackboard; }
    
    public:
    	class ACharacter* GetTarget();
    
    public:
    	FVector GetPatrolLocation();
    	void SetPatrolLocation(const FVector& InLocation);
    
    public:
    	void SetWaitMode();
    	void SetApproachMode();
    	void SetActionMode();
    	void SetPatrolMode();
    	void SetHittedMode();
    	void SetAvoidMode();
    	void SetDeadMode();
    
    private:
    	void ChangeType(EAIStateType InType);
    
    public:
    	FAIStateTypeChanged OnAIStateTypeChanged;
    
    private:
    	class UBlackboardComponent* Blackboard;
    	
    };

    변수 추가

    • UPROPERTY(EditAnywhere, Category = "Key")
              FName PatrolLocationKey = "Patrol_Location";

    함수 추가

    • FVector GetPatrolLocation();
    • void SetPatrolLocation(const FVector& InLocation);

     

     

     

    CAIBehaviorComponent.cpp

    더보기
    #include "Components/CAIBehaviorComponent.h"
    #include "Global.h"
    #include "GameFramework/Character.h"
    #include "BehaviorTree/BlackboardComponent.h"
    
    UCAIBehaviorComponent::UCAIBehaviorComponent()
    {
    }
    
    void UCAIBehaviorComponent::BeginPlay()
    {
    	Super::BeginPlay();
    }
    
    EAIStateType UCAIBehaviorComponent::GetType()
    {
    	return (EAIStateType)Blackboard->GetValueAsEnum(AIStateTypeKey);
    }
    
    bool UCAIBehaviorComponent::IsWaitMode()
    {
    	return GetType() == EAIStateType::Wait;
    }
    
    bool UCAIBehaviorComponent::IsApproachMode()
    {
    	return GetType() == EAIStateType::Approach;
    }
    
    bool UCAIBehaviorComponent::IsActionMode()
    {
    	return GetType() == EAIStateType::Action;
    }
    
    bool UCAIBehaviorComponent::IsPatrolMode()
    {
    	return GetType() == EAIStateType::Patrol;
    }
    
    bool UCAIBehaviorComponent::IsHittedMode()
    {
    	return GetType() == EAIStateType::Hitted;
    }
    
    bool UCAIBehaviorComponent::IsAvoidMode()
    {
    	return GetType() == EAIStateType::Avoid;
    }
    
    bool UCAIBehaviorComponent::IsDeadMode()
    {
    	return GetType() == EAIStateType::Dead;
    }
    
    ACharacter* UCAIBehaviorComponent::GetTarget()
    {
    	//Blackboard 내의 TargetKey를 리턴해준다.
    	return Cast<ACharacter>(Blackboard->GetValueAsObject(TargetKey));
    }
    
    FVector UCAIBehaviorComponent::GetPatrolLocation()
    {
    	return Blackboard->GetValueAsVector(PatrolLocationKey);
    }
    
    void UCAIBehaviorComponent::SetPatrolLocation(const FVector& InLocation)
    {
    	Blackboard->SetValueAsVector(PatrolLocationKey, InLocation);
    }
    
    void UCAIBehaviorComponent::SetWaitMode()
    {
    	ChangeType(EAIStateType::Wait);
    }
    
    void UCAIBehaviorComponent::SetApproachMode()
    {
    	ChangeType(EAIStateType::Approach);
    }
    
    void UCAIBehaviorComponent::SetActionMode()
    {
    	ChangeType(EAIStateType::Action);
    }
    
    void UCAIBehaviorComponent::SetPatrolMode()
    {
    	ChangeType(EAIStateType::Patrol);
    }
    
    void UCAIBehaviorComponent::SetHittedMode()
    {
    	ChangeType(EAIStateType::Hitted);
    }
    
    void UCAIBehaviorComponent::SetAvoidMode()
    {
    	ChangeType(EAIStateType::Avoid);
    }
    
    void UCAIBehaviorComponent::SetDeadMode()
    {
    	ChangeType(EAIStateType::Dead);
    }
    
    void UCAIBehaviorComponent::ChangeType(EAIStateType InType)
    {
    	EAIStateType prevType = GetType();
    
    	Blackboard->SetValueAsEnum(AIStateTypeKey, (uint8)InType);
    
    	if (OnAIStateTypeChanged.IsBound())
    		OnAIStateTypeChanged.Broadcast(prevType, InType);
    }

    FVector UCAIBehaviorComponent::GetPatrolLocation()

    • return Blackboard->GetValueAsVector(PatrolLocationKey);

     

    void UCAIBehaviorComponent::SetPatrolLocation(const FVector& InLocation)

    • Blackboard->SetValueAsVector(PatrolLocationKey, InLocation);

     


     

     

    BB_Melee

     

    새 키 - Patrol_Location 추가

     

     

     

    ※ 참고) Instance Synced

    • 같은 Blackboard를 가진 애들 끼리 해당 값을 공유해준다.
    • Instance Synced를 체크하면 군집 이동 등이 용이하다. ex. Enemy 한 명이 Player를 발견하면 발견한 Enemy뿐만 아니라 나머지 Enemy들이 다 같이 접근한다.

     

     

    MT_Melee

     


     

     

     

    실행화면