Behavior Tree의 UCBTTaskNode 내에 AbortTask를 추가할 것이다. Task의 성공과 실패 외에도 Abort가 걸리는 상황을 추가하여 Behavior Tree 실행 중 Task가 빨리 또는 느리게 실행되어 문제가 되는 상황을 방지할 것이다. 일종의 예외처리도 가능하여 Abort는 대부분의 경우 Behavior Tree에 필수적으로 사용된다.  

 

목차

     

     


     

     

     
    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_Action.h .cpp
    CBTTaskNode_Equip.h .cpp
    CBTTaskNode_Hitted.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.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
     

     

     

     

     

    무기 장착 Abort

     


     

     

    CEquipment

     

    CEquipment.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "UObject/NoExportTypes.h"
    #include "Weapons/CWeaponStructures.h"
    #include "CEquipment.generated.h"
    
    //직렬화하여 BP에서 사용가능하도록 DYNAMIC, 여러함수를 받을 수 있도록 MULTICAST 사용.
    DECLARE_DYNAMIC_MULTICAST_DELEGATE(FEquipmentEquip);
    DECLARE_DYNAMIC_MULTICAST_DELEGATE(FEquipmentBeginEquip);
    DECLARE_DYNAMIC_MULTICAST_DELEGATE(FEquipmentUnequip);
    
    UCLASS()
    class U2212_06_API UCEquipment : public UObject
    {
    	GENERATED_BODY()
    
    public:
    	//실시간으로 bEquipped로 가져온다. 주소로 가져온다.
    	FORCEINLINE bool GetBeginEquip() { return bBeginEquip; }
    	FORCEINLINE const bool* GetEquipped() { return &bEquipped; }
    
    public:
    	void BeginPlay(class ACharacter* InOwner, const FEquipmentData& InData);
    
    public:
    	UFUNCTION(BlueprintNativeEvent)//필요시 BP에서 재정의하기 위해 BlueprintNativeEvent사용.
    		void Equip();
    		void Equip_Implementation();
    
    	UFUNCTION(BlueprintNativeEvent)
    		void Begin_Equip();
    		void Begin_Equip_Implementation();
    
    	UFUNCTION(BlueprintNativeEvent)
    		void End_Equip();
    		void End_Equip_Implementation();
    
    	UFUNCTION(BlueprintNativeEvent)
    		void Unequip();
    		void Unequip_Implementation();
    
    public:
    	FEquipmentEquip OnEquipmentEquip;//DECLARE_DYNAMIC_MULTICAST_DELEGATE 하였다.
    	FEquipmentBeginEquip OnEquipmentBeginEquip;//DECLARE_DYNAMIC_MULTICAST_DELEGATE 하였다.
    	FEquipmentUnequip OnEquipmentUnequip;//DECLARE_DYNAMIC_MULTICAST_DELEGATE 하였다.
    
    private:
    	class ACharacter* OwnerCharacter;
    	FEquipmentData Data;
    
    private:
    	class UCMovementComponent* Movement;
    	class UCStateComponent* State;
    
    private:
    	bool bBeginEquip;//Equip이 시작되었는가 확인
    	bool bEquipped;  //Equip이 완료되었는지 확인
    };

    인라인 함수

    • FORCEINLINE bool GetBeginEquip() { return bBeginEquip; }

     

     

     

    CEquipment.cpp

    더보기
    #include "Weapons/CEquipment.h"
    #include "Global.h"
    #include "GameFramework/Character.h"
    #include "Components/CMovementComponent.h"
    #include "Components/CStateComponent.h"
    #include "CEquipment.h"
    
    void UCEquipment::BeginPlay(ACharacter* InOwner, const FEquipmentData& InData)
    {
    	OwnerCharacter = InOwner;
    	Data = InData;
    
    	Movement = CHelpers::GetComponent<UCMovementComponent>(InOwner);
    	State = CHelpers::GetComponent<UCStateComponent>(InOwner);
    }
    
    void UCEquipment::Equip_Implementation()
    {
    	State->SetEquipMode();
    
    	if (OnEquipmentEquip.IsBound())//활 장착 확인?
    		OnEquipmentEquip.Broadcast();
    
    	if (Data.bCanMove == false)
    		Movement->Stop();
    
    	if (Data.bUseControlRotation)
    		Movement->EnableControlRotation();
    
    	if (!!Data.Montage)
    	{
    		OwnerCharacter->PlayAnimMontage(Data.Montage, Data.PlayRate);
    	}
    	else
    	{
    		Begin_Equip();
    		End_Equip();
    	}
    }
    
    void UCEquipment::Begin_Equip_Implementation()
    {
    	bBeginEquip = true;
    
    	if (OnEquipmentBeginEquip.IsBound())
    		OnEquipmentBeginEquip.Broadcast();
    }
    
    void UCEquipment::End_Equip_Implementation()
    {
    	bBeginEquip = false;
    	bEquipped = true;
    
    	Movement->Move();
    	State->SetIdleMode();
    }
    
    void UCEquipment::Unequip_Implementation()
    {
    	bEquipped = false;
    	Movement->DisableControlRotation();
    
    	if (OnEquipmentUnequip.IsBound())
    		OnEquipmentUnequip.Broadcast();
    }

    변경사항 없음

     


     

     

     

     

    CBTTaskNode_Equip

     

    CBTTaskNode_Equip.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "BehaviorTree/BTTaskNode.h"
    #include "Components/CWeaponComponent.h"
    #include "CBTTaskNode_Equip.generated.h"
    
    UCLASS()
    class U2212_06_API UCBTTaskNode_Equip : public UBTTaskNode
    {
    	GENERATED_BODY()
    
    private:
    	UPROPERTY(EditAnywhere, Category = "Type")
    		EWeaponType Type;
    
    public:
    	UCBTTaskNode_Equip();
    
    protected:
    	EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
    	void TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;
    	EBTNodeResult::Type AbortTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
    };

    테스크 추가

    • EBTNodeResult::Type AbortTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;

     

     

     

    CBTTaskNode_Equip.cpp

    더보기
    #include "BehaviorTree/CBTTaskNode_Equip.h"
    #include "Global.h"
    #include "Characters/CEnemy_AI.h"
    #include "Characters/CAIController.h"
    #include "Components/CStateComponent.h"
    #include "Weapons/CEquipment.h"
    
    UCBTTaskNode_Equip::UCBTTaskNode_Equip()
    {
    	NodeName = "Equip";
    
    	bNotifyTick = true;
    }
    
    EBTNodeResult::Type UCBTTaskNode_Equip::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
    {
    	Super::ExecuteTask(OwnerComp, NodeMemory);
    
    	ACAIController* controller = Cast<ACAIController>(OwnerComp.GetOwner());
    	ACEnemy_AI* ai = Cast<ACEnemy_AI>(controller->GetPawn());
    
    	UCWeaponComponent* weapon = CHelpers::GetComponent<UCWeaponComponent>(ai);
    	CheckNullResult(weapon, EBTNodeResult::Failed);//weapon이 없다면 EBTNodeResult::Failed 리턴
    
    	if (Type == weapon->GetWeaponType())//장착될 무기 == 현재 장착된 무기
    		return EBTNodeResult::Succeeded;//새로 장착시킬 필요 없으니 바로 Succeeded를 리턴
    	
    	switch (Type)
    	{
    		case EWeaponType::Sword: weapon->SetSwordMode(); break;//Sword 장착
    	}
    
    	return EBTNodeResult::InProgress;//장착 동작이 나올 수 있도록 InProgress 리턴
    }
    
    void UCBTTaskNode_Equip::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());
    
    	UCWeaponComponent* weapon = CHelpers::GetComponent<UCWeaponComponent>(ai);//weapon을 가져온다.
    
    	const bool* bEquipped = weapon->GetEquipment()->GetEquipped();
    
    	UCStateComponent* state = CHelpers::GetComponent<UCStateComponent>(ai);
    	if(state->IsIdleMode() && *bEquipped)
    	{
    		FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
    
    		return;
    	}
    }
    
    EBTNodeResult::Type UCBTTaskNode_Equip::AbortTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
    {
    	Super::AbortTask(OwnerComp, NodeMemory);
    
    	ACAIController* controller = Cast<ACAIController>(OwnerComp.GetOwner());
    	ACEnemy_AI* ai = Cast<ACEnemy_AI>(controller->GetPawn());
    
    	UCWeaponComponent* weapon = CHelpers::GetComponent<UCWeaponComponent>(ai);
    	if (weapon == nullptr)//무기가 없다면
    	{
    		FinishLatentAbort(OwnerComp);//중단으로 끝낸다.
    
    		return EBTNodeResult::Failed;//실패 리턴
    	}
    
    	bool bBeginEquip = weapon->GetEquipment()->GetBeginEquip();//GetBeginEquip()으로 CEquipment의 bBeginEquip를 넣어준다. bBeginEquip=true면 Equip이 시작되었다는 의미다.
    	if (bBeginEquip == false)
    		weapon->GetEquipment()->Begin_Equip();
    
    	weapon->GetEquipment()->End_Equip();
    
    	return EBTNodeResult::Aborted;//Aborted는 취소 마감, 위(Root)로 올라감. Succeeded는 성공종료.
    }

    테스크 정의

    • EBTNodeResult::Type UCBTTaskNode_Equip::AbortTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
      • if (weapon == nullptr) {
        FinishLatentAbort(OwnerComp);
        return EBTNodeResult::Failed;
        }
      • bool bBeginEquip = weapon->GetEquipment()->GetBeginEquip();
        • GetBeginEquip()으로 CEquipment의 bBeginEquip를 넣어준다. bBeginEquip=true면 Equip이 시작되었다는 의미다.
      • if (bBeginEquip == false)
        weapon->GetEquipment()->Begin_Equip();
      • weapon->GetEquipment()->End_Equip();
      • return EBTNodeResult::Aborted;
        • Aborted는 취소 마감, 위(Root)로 올라감. Succeeded는 성공종료.

     


     

     

     

    실행화면

     


     

     

     

     

     

    활 조준 Zoom In 시 튕기는 오류해결

     


     

    CPlayer

     

    FPS처럼 Zoom이 일어나는 경우, 1인칭 시점 카메라를 추가해서 만들고 Zoom 시에 카메라 전환을 하여 1인칭 전용 카메라를 사용해준다.

     

    CPlayer.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "GameFramework/Character.h"
    #include "Components/CStateComponent.h"
    #include "Characters/ICharacter.h"
    #include "Parkour/CParkourComponent.h"
    #include "GenericTeamAgentInterface.h"
    #include "CPlayer.generated.h"
    
    UCLASS()
    class U2212_06_API ACPlayer
    	: public ACharacter, public IICharacter, public IGenericTeamAgentInterface //다중상속
    {
    	GENERATED_BODY()
    
    private:
    	UPROPERTY(EditDefaultsOnly, Category = "Team")
    		uint8 TeamID = 1;
    
    private:
    	UPROPERTY(VisibleAnywhere)
    		class USpringArmComponent* SpringArm;
    
    	UPROPERTY(VisibleAnywhere)
    		class UCameraComponent* Camera;
    
    private:
    	UPROPERTY(VisibleAnywhere)
    		class UCWeaponComponent* Weapon;
    
    	UPROPERTY(VisibleAnywhere)
    		class UCMontagesComponent* Montages;
    
    	UPROPERTY(VisibleAnywhere)
    		class UCMovementComponent* Movement;
    
    	UPROPERTY(VisibleAnywhere)
    		class UCStateComponent* State;
    
    /** 파쿠르 */
    private:
    	UPROPERTY(VisibleDefaultsOnly)
    		class USceneComponent* ArrowGroup;//파쿠르를 위한 ArrowGroup
    
    	UPROPERTY(VisibleDefaultsOnly)
    		class UArrowComponent* Arrows[(int32)EParkourArrowType::Max];
    
    	UPROPERTY(VisibleDefaultsOnly)
    		class UCParkourComponent* Parkour;
    /** 파쿠르 */
    
    	UPROPERTY(VisibleDefaultsOnly)
    		class UCZoomComponent* Zoom;
    
    public:
    	ACPlayer();
    
    protected:
    	virtual void BeginPlay() override;
    
    public:	
    	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
    	FGenericTeamId GetGenericTeamId() const override { return FGenericTeamId(TeamID); }
    
    private:
    	UFUNCTION()
    		void OnStateTypeChanged(EStateType InPrevType, EStateType InNewType);
    
    private:
    	void OnAvoid();
    
    private:
    	void BackStep();
    
    public:
    	void End_BackStep() override;//ICharacter의 함수 오버라이드
    
    public:
    	void OnRightButton();
    	void OffRightButton();
    
    public:
    	void Landed(const FHitResult& Hit) override;//BP의 OnLanded C++버젼.
    
    private:
    	void SetZooming(float InValue);
    };

    함수 수정 및 추가

    • 변경 전:
      • void Click_RightButton();
    • 변경 후:
      • void OnRightButton();
      • void OffRightButton();

     

     

     

    CPlayer.cpp

    더보기
    #include "Characters/CPlayer.h"
    #include "Global.h"
    #include "CAnimInstance.h"
    #include "GameFramework/SpringArmComponent.h"
    #include "GameFramework/CharacterMovementComponent.h"
    #include "Camera/CameraComponent.h"
    #include "Components/SkeletalMeshComponent.h"
    #include "Components/InputComponent.h"
    #include "Components/CMontagesComponent.h"
    #include "Components/CMovementComponent.h"
    #include "Components/CWeaponComponent.h"
    #include "Components/CZoomComponent.h"
    #include "Components/ArrowComponent.h"
    
    ACPlayer::ACPlayer()
    {
    	CHelpers::CreateComponent<USpringArmComponent>(this, &SpringArm, "SpringArm", GetMesh());
    	CHelpers::CreateComponent<UCameraComponent>(this, &Camera, "Camera", SpringArm);
    
    	CHelpers::CreateActorComponent<UCWeaponComponent>(this, &Weapon, "Weapon");
    	CHelpers::CreateActorComponent<UCMontagesComponent>(this, &Montages, "Montages");
    	CHelpers::CreateActorComponent<UCMovementComponent>(this, &Movement, "Movement");
    	CHelpers::CreateActorComponent<UCStateComponent>(this, &State, "State");
    	CHelpers::CreateActorComponent<UCParkourComponent>(this, &Parkour, "Parkour");
    	CHelpers::CreateActorComponent<UCZoomComponent>(this, &Zoom, "Zoom");
    
    	GetMesh()->SetRelativeLocation(FVector(0, 0, -90));
    	GetMesh()->SetRelativeRotation(FRotator(0, -90, 0));
    
    	USkeletalMesh* mesh;
    	CHelpers::GetAsset<USkeletalMesh>(&mesh, "SkeletalMesh'/Game/Character/Mesh/SK_Mannequin.SK_Mannequin'");
    	GetMesh()->SetSkeletalMesh(mesh);
    
    	TSubclassOf<UCAnimInstance> animInstance;
    	CHelpers::GetClass<UCAnimInstance>(&animInstance, "AnimBlueprint'/Game/ABP_Character.ABP_Character_C'");
    	GetMesh()->SetAnimClass(animInstance);
    
    	SpringArm->SetRelativeLocation(FVector(0, 0, 140));
    	SpringArm->SetRelativeRotation(FRotator(0, 90, 0));
    	SpringArm->TargetArmLength = 200;
    	SpringArm->bDoCollisionTest = false;
    	SpringArm->bUsePawnControlRotation = true;
    	SpringArm->bEnableCameraLag = true;
    
    	GetCharacterMovement()->RotationRate = FRotator(0, 720, 0);
    
    	CHelpers::CreateComponent<USceneComponent>(this, &ArrowGroup, "ArrowGroup", GetCapsuleComponent());//ArrowGroup을 생성하고 GetCapsuleComponent 아래로 붙여준다.
    	//파쿠르에 활용한 Arrows들을 생성한다. 
    	for (int32 i = 0; i < (int32)EParkourArrowType::Max; i++)
    	{
    		FString name = StaticEnum<EParkourArrowType>()->GetNameStringByIndex(i);
    		CHelpers::CreateComponent<UArrowComponent>(this, &Arrows[i], FName(name), ArrowGroup);
    
    		switch ((EParkourArrowType)i)
    		{
    		case EParkourArrowType::Center:
    			Arrows[i]->ArrowColor = FColor::Red;
    			break;
    
    		case EParkourArrowType::Ceil:
    			Arrows[i]->ArrowColor = FColor::Green;
    			Arrows[i]->SetRelativeLocation(FVector(0, 0, 100));
    			break;
    
    		case EParkourArrowType::Floor:
    			Arrows[i]->ArrowColor = FColor::Blue;
    			Arrows[i]->SetRelativeLocation(FVector(0, 0, -80));
    			break;
    
    		case EParkourArrowType::Left:
    			Arrows[i]->ArrowColor = FColor::Magenta;
    			Arrows[i]->SetRelativeLocation(FVector(0, -30, 0));
    			break;
    
    		case EParkourArrowType::Right:
    			Arrows[i]->ArrowColor = FColor::Magenta;
    			Arrows[i]->SetRelativeLocation(FVector(0, 30, 0));
    			break;
    
    		case EParkourArrowType::Land:
    			Arrows[i]->ArrowColor = FColor::Yellow;
    			Arrows[i]->SetRelativeLocation(FVector(200, 0, 100));
    			Arrows[i]->SetRelativeRotation(FRotator(-90, 0, 0));
    			break;
    		}
    	}
    
    }
    
    void ACPlayer::BeginPlay()
    {
    	Super::BeginPlay();
    
    	Movement->OnRun(); //Movement의 기본을 Run으로 설정
    	Movement->DisableControlRotation();//Movement의 기본을 DisableControlRotation으로 설정
    
    	State->OnStateTypeChanged.AddDynamic(this, &ACPlayer::OnStateTypeChanged);
    }
    
    void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
    {
    	Super::SetupPlayerInputComponent(PlayerInputComponent);
    
    	PlayerInputComponent->BindAxis("MoveForward", Movement, &UCMovementComponent::OnMoveForward);
    	PlayerInputComponent->BindAxis("MoveRight", Movement, &UCMovementComponent::OnMoveRight);
    	PlayerInputComponent->BindAxis("VerticalLook", Movement, &UCMovementComponent::OnVerticalLook);
    	PlayerInputComponent->BindAxis("HorizontalLook", Movement, &UCMovementComponent::OnHorizontalLook);
    
    	PlayerInputComponent->BindAction("Sprint", EInputEvent::IE_Pressed, Movement, &UCMovementComponent::OnSprint);
    	PlayerInputComponent->BindAction("Sprint", EInputEvent::IE_Released, Movement, &UCMovementComponent::OnRun);
    
    	PlayerInputComponent->BindAction("Avoid", EInputEvent::IE_Pressed, this, &ACPlayer::OnAvoid);
    
    	//PlayerInputComponent->BindAxis("Zoom", Zoom, &UCZoomComponent::SetZoomValue);//Value로 연동되게하면 Bow 모드 시 문제가 될 수 있다.
    	PlayerInputComponent->BindAxis("Zoom", this, &ACPlayer::SetZooming);//Bow 모드가 아닐 때만 사용하려고 SetZooming으로 설정하여 만들었다.
    
    	PlayerInputComponent->BindAction("Fist", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetFistMode);
    	PlayerInputComponent->BindAction("Sword", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetSwordMode);
    	PlayerInputComponent->BindAction("Hammer", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetHammerMode);
    	PlayerInputComponent->BindAction("Warp", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetWarpMode);
    	PlayerInputComponent->BindAction("Around", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetAroundMode);
    	PlayerInputComponent->BindAction("Bow", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetBowMode);
    
    	PlayerInputComponent->BindAction("Action", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::DoAction);
    	
    	PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Pressed, this, &ACPlayer::OnRightButton);
    	PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Released, this, &ACPlayer::OffRightButton);
    }
    
    void ACPlayer::OnStateTypeChanged(EStateType InPrevType, EStateType InNewType)
    {
    	switch (InNewType)
    	{
    		case EStateType::BackStep: BackStep(); break;
    	}
    }
    
    void ACPlayer::OnAvoid()
    {
    	CheckFalse(State->IsIdleMode());
    	CheckFalse(Movement->CanMove());
    
    	CheckTrue(InputComponent->GetAxisValue("MoveForward") >= 0.0f);//뒷방향을 입력했다면
    
    	State->SetBackStepMode();//State을 BackStepMode로 변경한다.
    }
    
    void ACPlayer::BackStep()
    {
    	Movement->EnableControlRotation();//정면을 바라본 상태로 뒤로 뛰어야하기 때문에 EnableControlRotation으로 만들어준다.
    
    	Montages->PlayBackStepMode();//PlayBackStepMode()를 통해 몽타주 재생.
    }
    
    void ACPlayer::End_BackStep()
    {
    	Movement->DisableControlRotation();//Backstep이 끝나면 원래대로 돌려준다.
    
    	State->SetIdleMode();//Idle상태로 돌려줌.
    }
    
    void ACPlayer::OnRightButton()
    {
    	if (Weapon->IsUnarmedMode())
    	{
    		Parkour->DoParkour();
    
    		return;
    	}
    
    	if (Weapon->IsBowMode())
    	{
    		//BowMode(활 장착)일 때 우클릭을 누르고 있을때 Zoom기능을 꺼준다.
    		Zoom->SetComponentTickEnabled(false);
    	}
    
    	Weapon->SubAction_Pressed();
    }
    
    void ACPlayer::OffRightButton()
    {
    	if (Weapon->IsBowMode())
    	{
    		//BowMode(활 장착)일 때 우클릭을 떼면 Zoom기능을 꺼준다.
    		Zoom->SetComponentTickEnabled(true);
    	}
    
    	Weapon->SubAction_Released();
    }
    
    void ACPlayer::Landed(const FHitResult& Hit)
    {
    	Parkour->DoParkour(true);
    }
    
    void ACPlayer::SetZooming(float InValue)
    {
    	CheckTrue(Weapon->IsBowMode());//BowMode이면 바로 리턴
    
    	Zoom->SetZoomValue(InValue);//BowMode가 아닌 경우 Zoom In&Out 가능.
    }

    함수 수정 및 추가

    • void ACPlayer::OnRightButton()
      • if (Weapon->IsBowMode())  {  Zoom->SetComponentTickEnabled(false);  }
      • Weapon->SubAction_Pressed();
    • void ACPlayer::OffRightButton()
      • if (Weapon->IsBowMode())  {  Zoom->SetComponentTickEnabled(true);  }
      • Weapon->SubAction_Released();