Player에 구현한 화살 발사를 궁수 AI에도 적용한다. SetFocus를 사용하여 적을 지속적으로 바라보게 만든다. 몽타주를 재생시켜 활의 시위를 당기고 화살 발사 준비를 마친 후 CSubAction_Bow 코드를 재사용하여 화살을 발사한다.  CSubAction_Bow 코드 내에 AIController일 때도 Press()와 Released(), 즉 조준 후 발사가 가능하도록 코드를 추가한다.

 

 

목차

     

     


     

     

     

     
    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
    CBTService_Range.h .cpp
    CBTTaskNode_Action.h .cpp

    CBTTaskNode_Equip.h .cpp
    CBTTaskNode_Hitted.h .cpp

    CBTTaskNode_Patrol.h .cpp
    CBTTaskNode_Speed.h .cpp
    CEnvQueryContext_Target.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.h .cpp
    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
    CWeaponData.h .cpp
    CWeaponStructures.h .cpp
        Global.h
    CGameMode.h .cpp
    U2212_06.Build.cs
        U2212_06.uproject
     

     

     

     

     

    방법1. 활을 쏘는 Enemy: 화살 발사하기

     

     


     

    CWeaponComponent

     

    CWeaponComponent.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Components/ActorComponent.h"
    #include "CWeaponComponent.generated.h"
    
    UENUM(BlueprintType)
    enum class EWeaponType : uint8
    {
    	Fist, Sword, Hammer, Warp, Around, Bow, Max,
    };
    DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FWeaponTypeChanged, EWeaponType, InPrevType, EWeaponType, InNewType);
    
    UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
    class U2212_06_API UCWeaponComponent : public UActorComponent
    {
    	GENERATED_BODY()
    
    private://DataAsset을 받아온다.
    	UPROPERTY(EditAnywhere, Category = "DataAsset")
    		class UCWeaponAsset* DataAssets[(int32)EWeaponType::Max];
    
    public:
    	FORCEINLINE EWeaponType GetWeaponType() { return Type; }
    
    public: //무기 Type이 맞는지 확인해주는 함수들
    	FORCEINLINE bool IsUnarmedMode() { return Type == EWeaponType::Max; }
    	FORCEINLINE bool IsFistMode() { return Type == EWeaponType::Fist; }
    	FORCEINLINE bool IsSwordMode() { return Type == EWeaponType::Sword; }
    	FORCEINLINE bool IsHammerMode() { return Type == EWeaponType::Hammer; }
    	FORCEINLINE bool IsWarpMode() { return Type == EWeaponType::Warp; }
    	FORCEINLINE bool IsAroundMode() { return Type == EWeaponType::Around; }
    	FORCEINLINE bool IsBowMode() { return Type == EWeaponType::Bow; }
    
    public:
    	UCWeaponComponent();
    
    protected:
    	virtual void BeginPlay() override;
    
    public:
    	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
    
    private:
    	bool IsIdleMode();//StateComponent, WeaponComponent 둘 다 같은 레벨이다. 서로 소유할 수 없는 관계이기 때문에 참조만해서 리턴받기 위해 IsIdleMode를 사용한다.
    
    public:
    	class ACAttachment* GetAttachment();
    	class UCEquipment* GetEquipment();
    	class UCDoAction* GetDoAction();
    
    public:
    	UFUNCTION(BlueprintCallable)
    	class UCSubAction* GetSubAction();
    
    public: //무기 세팅
    	void SetUnarmedMode();
    	void SetFistMode();
    	void SetSwordMode();
    	void SetHammerMode();
    	void SetWarpMode();
    	void SetAroundMode();
    	void SetBowMode();
    
    	void DoAction();
    
    public:
    	UFUNCTION(BlueprintCallable)
    	void SubAction_Pressed();
    
    	UFUNCTION(BlueprintCallable)
    	void SubAction_Released();
    
    private:
    	void SetMode(EWeaponType InType);
    	void ChangeType(EWeaponType InType);
    
    public: //무기가 바뀌었을때 통보해줄 delegate
    	FWeaponTypeChanged OnWeaponTypeChange;
    
    private:
    	class ACharacter* OwnerCharacter;
    
    	EWeaponType Type = EWeaponType::Max;
    
    private:
    	//가비지 콜랙터가 삭제하지 않도록 UPROPERTY를 붙여 직렬화 시켜준다. 직렬화되면 가비지 콜렉터가 삭제하지 않는다. UPROPERTY가 없으면 터진다.
    	UPROPERTY()
    	class UCWeaponData* Datas[(int32)EWeaponType::Max];//실제로 생성된 데이터
    };

    직렬화하여 블루프린트에서 보이게 하기

    • UFUNCTION(BlueprintCallable)
          class UCSubAction* GetSubAction();
    • UFUNCTION(BlueprintCallable)
          void SubAction_Pressed();
    • UFUNCTION(BlueprintCallable)
          void SubAction_Released();

     

     

     

    CWeaponComponent.cpp

    더보기
    #include "Components/CWeaponComponent.h"
    #include "Global.h"
    #include "CStateComponent.h"
    #include "GameFramework/Character.h"
    #include "Weapons/CWeaponAsset.h"
    #include "Weapons/CWeaponData.h"
    #include "Weapons/CAttachment.h"
    #include "Weapons/CEquipment.h"
    #include "Weapons/CDoAction.h"
    #include "Weapons/CSubAction.h"
    
    UCWeaponComponent::UCWeaponComponent()
    {
    	//Tick을 실행시켜주는 코드
    	PrimaryComponentTick.bCanEverTick = true;
    }
    
    void UCWeaponComponent::BeginPlay()
    {
    	Super::BeginPlay();
    
    	OwnerCharacter = Cast<ACharacter>(GetOwner());
    	for (int32 i=0; i < (int32)EWeaponType::Max; i++)
    	{
    		if (!!DataAssets[i]) //DataAssets[i]이 있다면(=무기가 할당되어 있다면)
    			DataAssets[i]->BeginPlay(OwnerCharacter, &Datas[i]);//BeginPla y 시 OwnerCharacter에 Spawn시켜준다.
    	}
    }
    
    void UCWeaponComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
    {
    	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
    
    	if (!!GetDoAction())//DoAction이 있다면
    		GetDoAction()->Tick(DeltaTime);//DoAction의 Tick을 콜 해준다.
    
    	if (!!GetSubAction())//SubAction이 있다면
    		GetSubAction()->Tick(DeltaTime);//SubAction의 Tick을 콜 해준다.
    }
    
    bool UCWeaponComponent::IsIdleMode()
    {
    	return CHelpers::GetComponent<UCStateComponent>(OwnerCharacter)->IsIdleMode();
    }
    
    ACAttachment* UCWeaponComponent::GetAttachment()
    {
    	CheckTrueResult(IsUnarmedMode(), nullptr);
    	CheckFalseResult(!!Datas[(int32)Type], nullptr);
    
    	return Datas[(int32)Type]->GetAttachment();//실제 데이터를 리턴
    }
    
    UCEquipment* UCWeaponComponent::GetEquipment()
    {
    	CheckTrueResult(IsUnarmedMode(), nullptr);
    	CheckFalseResult(!!Datas[(int32)Type], nullptr);
    
    	return Datas[(int32)Type]->GetEquipment();//실제 데이터를 리턴
    }
    
    UCDoAction* UCWeaponComponent::GetDoAction()
    {
    	CheckTrueResult(IsUnarmedMode(), nullptr);
    	CheckFalseResult(!!Datas[(int32)Type], nullptr);
    
    	return Datas[(int32)Type]->GetDoAction();//실제 데이터를 리턴
    }
    
    UCSubAction* UCWeaponComponent::GetSubAction()
    {
    	CheckTrueResult(IsUnarmedMode(), nullptr);
    	CheckFalseResult(!!Datas[(int32)Type], nullptr);
    
    	return Datas[(int32)Type]->GetSubAction();//실제 데이터를 리턴
    }
    
    void UCWeaponComponent::SetUnarmedMode()
    {
    	GetEquipment()->Unequip();
    
    	ChangeType(EWeaponType::Max);
    }
    
    void UCWeaponComponent::SetFistMode()
    {
    	CheckFalse(IsIdleMode());
    
    	SetMode(EWeaponType::Fist);
    }
    
    void UCWeaponComponent::SetSwordMode()
    {
    	CheckFalse(IsIdleMode());
    
    	SetMode(EWeaponType::Sword);
    }
    
    void UCWeaponComponent::SetHammerMode()
    {
    	CheckFalse(IsIdleMode());
    
    	SetMode(EWeaponType::Hammer);
    }
    
    void UCWeaponComponent::SetWarpMode()
    {
    	CheckFalse(IsIdleMode());
    
    	SetMode(EWeaponType::Warp);
    }
    
    void UCWeaponComponent::SetAroundMode()
    {
    	CheckFalse(IsIdleMode());
    
    	SetMode(EWeaponType::Around);
    }
    
    void UCWeaponComponent::SetBowMode()
    {
    	CheckFalse(IsIdleMode());
    
    	SetMode(EWeaponType::Bow);
    }
    
    void UCWeaponComponent::SetMode(EWeaponType InType)
    {
    	if (Type == InType)
    	{
    		SetUnarmedMode();
    
    		return;
    	}
    	else if (IsUnarmedMode() == false)
    	{
    		GetEquipment()->Unequip();
    	}
    
    	if (!!Datas[(int32)InType])//실제 데이터가 있다면
    	{
    		Datas[(int32)InType]->GetEquipment()->Equip();
    
    		ChangeType(InType);
    	}
    }
    
    void UCWeaponComponent::ChangeType(EWeaponType InType)
    {
    	EWeaponType prevType = Type;
    	Type = InType;
    
    	if (OnWeaponTypeChange.IsBound())
    		OnWeaponTypeChange.Broadcast(prevType, InType);
    }
    
    void UCWeaponComponent::DoAction()
    {
    	if (!!GetDoAction())
    		GetDoAction()->DoAction();
    }
    
    void UCWeaponComponent::SubAction_Pressed()
    {
    	if (!!GetSubAction())
    		GetSubAction()->Pressed();
    }
    
    void UCWeaponComponent::SubAction_Released()
    {
    	if (!!GetSubAction())
    		GetSubAction()->Released();
    }

    변경사항 없음

     


     

    CSubAction_Bow

     

    CSubAction_Bow.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Weapons/CSubAction.h"
    #include "Components/TimelineComponent.h"
    #include "CSubAction_Bow.generated.h"
    
    USTRUCT()
    struct FAimData
    {
        GENERATED_BODY()
    
    public:
        UPROPERTY(EditAnywhere)
            float TargetArmLength = 100;
    
        UPROPERTY(EditAnywhere)
            FVector SocketOffset = FVector(0, 30, 10);
    
        UPROPERTY(EditAnywhere)
            bool bEnableCameraLag;
    
        UPROPERTY(EditAnywhere)
            FVector CameraLocation;
    };
    
    UCLASS(Blueprintable)
    class U2212_06_API UCSubAction_Bow : public UCSubAction
    {
    	GENERATED_BODY()
    
    private:
        UPROPERTY(EditAnywhere, Category = "Aiming")
            class UCurveVector* Curve;
    
        UPROPERTY(EditAnywhere, Category = "Aiming")
            FAimData AimData;
    
        UPROPERTY(EditAnywhere, Category = "Aiming")
            float AimingSpeed = 200;
    
    public:
        UCSubAction_Bow();
    
    public:
        virtual void Pressed() override;
        virtual void Released() override;
    
    public:
        void BeginPlay(class ACharacter* InOwner, class ACAttachment* InAttachment, class UCDoAction* InDoAction) override;
    
    public:
        void Tick_Implementation(float InDeltaTime) override;
    
    private:
        UFUNCTION()
            void OnAiming(FVector Output);
    
    private:
        class USpringArmComponent* SpringArm;
        class UCameraComponent* Camera;
    
    private:
        FTimeline Timeline;
        //SubAction는 Actor가 아니기 때문에 Component를 가질 수 없다. SubAction은 UObject 상속이다.
        //그래서 TimelineComponent가 아닌 Timeline으로 작업한다.
    
    private:
        FAimData OriginData;
    
    private:
        float* Bend;
    };

    변경사항 없음.

     

     

     

    CSubAction_Bow.cpp

    더보기
    #include "Weapons/SubActions/CSubAction_Bow.h"
    #include "Global.h"
    #include "AIController.h"
    #include "GameFramework/Character.h"
    #include "GameFramework/PlayerController.h"
    #include "GameFramework/SpringArmComponent.h"
    #include "Camera/CameraComponent.h"
    #include "Components/CStateComponent.h"
    #include "Weapons/Attachments/CAttachment_Bow.h"
    
    UCSubAction_Bow::UCSubAction_Bow()
    {
    	CHelpers::GetAsset<UCurveVector>(&Curve, "CurveVector'/Game/Weapons/Bow/Curve_Aiming.Curve_Aiming'");//Editor에서 만든 CurveVector를 할당한다.
    }
    
    void UCSubAction_Bow::Pressed()
    {
    	CheckTrue(State->IsSubActionMode());
    
    	//Enemy AI
    	if (!!Owner->GetController<AAIController>())
    	{
    		Super::Pressed();
    		State->OnSubActionMode();
    
    		return;
    	}
    
    	CheckNull(SpringArm);
    	CheckNull(Camera);
    
    	Super::Pressed();
    
    	State->OnSubActionMode();
    
    	OriginData.TargetArmLength = SpringArm->TargetArmLength;
    	OriginData.SocketOffset = SpringArm->SocketOffset;
    	OriginData.bEnableCameraLag = SpringArm->bEnableCameraLag;
    	OriginData.CameraLocation = Camera->GetRelativeLocation();
    
    	SpringArm->TargetArmLength = AimData.TargetArmLength;
    	SpringArm->SocketOffset = AimData.SocketOffset;
    	SpringArm->bEnableCameraLag = AimData.bEnableCameraLag;
    	Camera->SetRelativeLocation(AimData.CameraLocation);
    	
    	Timeline.PlayFromStart();//Timeline 동작 시작.
    }
    
    void UCSubAction_Bow::Released()
    {
    	CheckFalse(State->IsSubActionMode());
    
    	//Enemy AI
    	if (!!Owner->GetController<AAIController>())
    	{
    		Super::Pressed();
    		State->OffSubActionMode();
    
    		return;
    	}
    
    
    	CheckNull(SpringArm);
    	CheckNull(Camera);
    
    	Super::Released();
    
    	State->OffSubActionMode();
    
    	SpringArm->TargetArmLength = OriginData.TargetArmLength;
    	SpringArm->SocketOffset = OriginData.SocketOffset;
    	SpringArm->bEnableCameraLag = OriginData.bEnableCameraLag;
    	Camera->SetRelativeLocation(OriginData.CameraLocation);
    
    	Timeline.ReverseFromEnd();//Timeline 뒤집기
    }
    
    void UCSubAction_Bow::BeginPlay(ACharacter* InOwner, ACAttachment* InAttachment, UCDoAction* InDoAction)
    {
    	Super::BeginPlay(InOwner, InAttachment, InDoAction);
    
    	SpringArm = CHelpers::GetComponent<USpringArmComponent>(InOwner);
    	Camera = CHelpers::GetComponent<UCameraComponent>(InOwner);
    
    
    	FOnTimelineVector timeline;
    	timeline.BindUFunction(this, "OnAiming");//OnAiming함수를 묶어서 콜한다.
    
    	Timeline.AddInterpVector(Curve, timeline);
    	Timeline.SetPlayRate(AimingSpeed);
    
    	ACAttachment_Bow* bow = Cast<ACAttachment_Bow>(InAttachment);//CAttachment_Bow의 멤버를 사용하기 위해 캐스팅한다.
    
    	if (!!bow)
    		Bend = bow->GetBend();//CSubAction_Bow에서 선언한 Bend 변수에 CAttachment_Bow의 Bend값을 GetBend()로 가져와서 넣어준다.
    }
    
    void UCSubAction_Bow::Tick_Implementation(float InDeltaTime)
    {
    	Super::Tick_Implementation(InDeltaTime);
    
    	//TimelineComponent로 사용하는 경우 자기자신이 Tick이 있기 때문에 아래 작업을 안 해도 상관없으나 CSubAction_Bow의 경우 TimelineComponent가 없기 때문에 Tick을 반드시 넣어주어야 한다.
    	Timeline.TickTimeline(InDeltaTime);
    }
    
    void UCSubAction_Bow::OnAiming(FVector Output)
    {
    	Camera->FieldOfView = Output.X;//조준 활성화와 해제에 앞뒤 ZoomIn&Out에 Output.X값이 쓰인다.
    
    	if (!!Bend)
    		*Bend = Output.Y;//에디터의 Curve_Aiming에서 설정한 Y값. 0~100까지 나온다.
    }

    헤더 추가

    • #include "AIController.h"

     

    Enemy_AI에서 화살 쏘기를 실행하기 위해 코드를 추가. 아래의 코드가 없으면 활 조준을 하지 않아 화살을 발사하지 않는다.

    • void UCSubAction_Bow::Pressed()
      • if (!!Owner->GetController<AAIController>())
            {
                Super::Pressed();
                State->OnSubActionMode();

                return;
            }
        • 명령을 수행하는 주체(Owner)의 Controller가 AIIController 캐스팅이 가능하다면 Enemy라는 의미다. 해당 경우, 화살을 쏘고 리턴한다.  
    • void UCSubAction_Bow::Released()
      • if (!!Owner->GetController<AAIController>())
            {
                Super::Pressed();
                State->OffSubActionMode();

                return;
            }

     


     

     

    BP_CEquipment_Bow 생성

     

     

    Event Graph


     

    DA_Bow

     

     


     

     

    BT_Range

     


     

     

     

    실행화면

     

     

     


     

     

     

     

    Avoid 구현하기

     


     

     

    CEnvQueryContext_Target 생성

     

    새 C++ 클래스 - EnvQueryContext - CEnvQueryContext_Target 생성

     

    CEnvQueryContext_Target.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "EnvironmentQuery/EnvQueryContext.h"
    #include "CEnvQueryContext_Target.generated.h"
    
    UCLASS()
    class U2212_06_API UCEnvQueryContext_Target : public UEnvQueryContext
    {
    	GENERATED_BODY()
    
    private:
    	void ProvideContext(FEnvQueryInstance& QueryInstance, FEnvQueryContextData& ContextData) const override;
    };

     

     

     

    CEnvQueryContext_Target.cpp

    더보기
    #include "BehaviorTree/CEnvQueryContext_Target.h"
    #include "Global.h"
    #include "EnvironmentQuery/EnvQueryTypes.h"
    #include "EnvironmentQuery/Items/EnvQueryItemType_Actor.h"
    #include "Characters/CEnemy_AI.h"
    #include "Characters/CAIController.h"
    #include "BehaviorTree/BlackboardComponent.h"
    
    void UCEnvQueryContext_Target::ProvideContext(FEnvQueryInstance& QueryInstance, FEnvQueryContextData& ContextData) const
    {
    	Super::ProvideContext(QueryInstance, ContextData);
    
    	//Query를 수행하는 Actor인 ACEnemy_AI 캐스팅
    	ACEnemy_AI* ai = Cast<ACEnemy_AI>(QueryInstance.Owner.Get());//QueryInstance.Owner.Get()는 UObject 리턴이다. Querier가 Object, Actor, Location 등이 될 수 있으니 어느것이든 다 받을수 있도록 최상위형인 UObject로 받기 위해QueryInstance.Owner.Get()으로 받았다.
    	ACAIController* controller = ai->GetController<ACAIController>();//Blackboard를 가져오기 위해 먼저 controller를 캐스팅한다.
    	UBlackboardComponent* blackboard = controller->GetBlackboardComponent();//controller 내의 Blackboard를 가져온다.
    	AActor* target = Cast<AActor>(blackboard->GetValueAsObject("Target"));//Blackboard의 Target를 가져다쓴다.
    
    	//target을 리턴할 것이기 때문에 Actor return이 되는 UEnvQueryItemType_Actor를 사용한다.
    	UEnvQueryItemType_Actor::SetContextHelper(ContextData, target);
    
    	//위치를 리턴해야 되는 경우 아래처럼 UEnvQueryItemType_VectorBase를 사용하면 된다.
    	//UEnvQueryItemType_VectorBase::
    }

    void UCEnvQueryContext_Target::ProvideContext(FEnvQueryInstance& QueryInstance, FEnvQueryContextData& ContextData) const

    • ACEnemy_AI* ai = Cast<ACEnemy_AI>(QueryInstance.Owner.Get());
      • Query를 수행하는 Actor인 ACEnemy_AI 캐스팅 
      • QueryInstance.Owner.Get()는 UObject 리턴이다. Querier가 Object, Actor, Location 등이 될 수 있으니 어느것이든 다 받을수 있도록 최상위형인 UObject로 받기 위해QueryInstance.Owner.Get()으로 받았다.
    • ACAIController* controller = ai->GetController<ACAIController>();
      • Blackboard를 가져오기 위해 먼저 controller를 캐스팅한다.
    • UBlackboardComponent* blackboard = controller->GetBlackboardComponent();
      • controller 내의 Blackboard를 가져온다.
    • AActor* target = Cast<AActor>(blackboard->GetValueAsObject("Target"));
      • Blackboard의 Target를 가져다쓴다.
    • UEnvQueryItemType_Actor::SetContextHelper(ContextData, target);
      • target을 리턴할 것이기 때문에 Actor return이 되는 UEnvQueryItemType_Actor를 사용한다.

     

     

     

    Querier가 Object, Actor, Location 등이 될 수 있으니 어느것이든 다 받을수 있도록 최상위형인 UObject로 받기 위해

     QueryInstance.Owner.Get()

    으로 받았다.

     


     

     

    EQ_Range 생성

     

    인공 지능 - 인바이런먼트 쿼리 - EQ_Range 생성

     

     

     

     


     

     

    BB_Range

     

    Avoid_Location 변수 추가


     

     

    BT_Range

     

     


     

     

     

    실행화면