지난 시간에는 활 시위를 구부러뜨리는것을 구현하였다. 오늘은 활 시위를 플레이어 손에 붙였다가 화살 발사 시 손에 떨어뜨리는 것을 구현할 것이다. CDo_Action_Bow를 만들어 발사 시점과 끝난 시점을 구분지어 줄 것이다. CAnimNotifyState_BowString 만들어 손에서 떨어진 활 시위를 다시 붙여주는 시점에 몽타주에 삽입할 것이다.

 

 

목차

     

     


     

     

     

     
    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
      U2212_06
        Characters
        CAnimInstance.h .cpp
    CEnemy.h .cpp 
    CPlayer.h .cpp
    ICharacter.h .cpp
        Components
        CMontagesComponent.h .cpp 
    CMovementComponent.h .cpp 
    CStateComponent.h .cpp
    CStatusComponent.h .cpp  
    CWeaponComponent.h .cpp 
        Notifies
        CAnimNotifyState_BeginAction.h .cpp
    CAnimNotifyState_BowString.h .cpp 생성 
    CAnimNotify_CameraShake.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
        Utilities
        CHelper.h
    CLog.h .cpp
        Weapons
        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
     

     

     

     

     

    활 시위에 손 맞추기

     


     

     

    CAttachment_Bow - 캡처를 삭제하고 Do_Action_Bow쪽으로 옮긴다.

     

     

    CAttachment_Bow.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "Weapons/CAttachment.h"
    #include "CAttachment_Bow.generated.h"
    UCLASS()
    class U2212_06_API ACAttachment_Bow : public ACAttachment
    {
    GENERATED_BODY()
    private:
    UPROPERTY(EditDefaultsOnly, Category = "View")
    FVector2D ViewPitchRange = FVector2D(-40, +30);//Pitch 제한각 설정
    private:
    UPROPERTY(VisibleAnywhere)
    class USkeletalMeshComponent* SkeletalMesh;
    UPROPERTY(VisibleAnywhere)
    class UPoseableMeshComponent* PoseableMesh;
    public:
    float* GetBend();
    public:
    ACAttachment_Bow();
    protected:
    virtual void BeginPlay() override;
    public:
    virtual void Tick(float DeltaTime) override;
    public:
    void OnBeginEquip_Implementation() override;
    void OnUnequip_Implementation() override;
    private:
    FVector2D OriginViewPitchRange;
    };

    변경사항 없음

     

     

     

    CAttachment_Bow.h

    더보기
    #include "Weapons/Attachments/CAttachment_Bow.h"
    #include "Global.h"
    #include "Weapons/AnimInstances/CAnimInstance_Bow.h"
    #include "Components/SkeletalMeshComponent.h"
    #include "Components/PoseableMeshComponent.h"
    ACAttachment_Bow::ACAttachment_Bow()
    {
    PrimaryActorTick.bCanEverTick = true;//실시간 적용이 되도록 넣어준다. 안 넣어주면 활 시위가 구부러지는것이 업데이트 되지 않을 수도 있다.
    CHelpers::CreateComponent<USkeletalMeshComponent>(this, &SkeletalMesh, "SkeletalMesh", Root);
    CHelpers::CreateComponent<UPoseableMeshComponent>(this, &PoseableMesh, "PoseableMesh", Root);
    USkeletalMesh* mesh;
    CHelpers::GetAsset<USkeletalMesh>(&mesh, "SkeletalMesh'/Game/Character/Weapons/ElvenBow/SK_ElvenBow.SK_ElvenBow'");
    SkeletalMesh->SetSkeletalMesh(mesh);
    SkeletalMesh->SetCollisionProfileName("NoCollision");
    TSubclassOf<UCAnimInstance_Bow> animInstance;
    CHelpers::GetClass<UCAnimInstance_Bow>(&animInstance, "AnimBlueprint'/Game/Weapons/Bow/ABP_ElvenBow.ABP_ElvenBow_C'");//ABP_ElvenBow 레퍼런스 복사하여 생성.
    SkeletalMesh->SetAnimInstanceClass(animInstance);
    }
    void ACAttachment_Bow::BeginPlay()
    {
    Super::BeginPlay();
    AttachTo("Holster_Bow");
    SkeletalMesh->SetVisibility(false);
    PoseableMesh->SetSkeletalMesh(SkeletalMesh->SkeletalMesh);//SkeletalMesh 내의 SkeletalMesh 사용.
    PoseableMesh->CopyPoseFromSkeletalComponent(SkeletalMesh);//포즈를 캡처해둔다.
    }
    void ACAttachment_Bow::Tick(float DeltaTime)
    {
    Super::Tick(DeltaTime);
    //캡처를 Do_Action_Bow쪽으로 옮긴다.
    //PoseableMesh->CopyPoseFromSkeletalComponent(SkeletalMesh);
    }
    void ACAttachment_Bow::OnBeginEquip_Implementation()
    {
    Super::OnBeginEquip_Implementation();
    AttachTo("Hand_Bow_Left");//Hand_Bow_Left 소켓에 장착.
    APlayerController* controller = OwnerCharacter->GetController<APlayerController>();
    if (!!controller)
    {
    OriginViewPitchRange.X = controller->PlayerCameraManager->ViewPitchMin;
    OriginViewPitchRange.Y = controller->PlayerCameraManager->ViewPitchMax;
    controller->PlayerCameraManager->ViewPitchMin = ViewPitchRange.X;
    controller->PlayerCameraManager->ViewPitchMax = ViewPitchRange.Y;
    }
    }
    void ACAttachment_Bow::OnUnequip_Implementation()
    {
    Super::OnUnequip_Implementation();
    AttachTo("Holster_Bow");//Holster_Bow 소켓에 장착.
    APlayerController* controller = OwnerCharacter->GetController<APlayerController>();
    if (!!controller)
    {
    controller->PlayerCameraManager->ViewPitchMin = OriginViewPitchRange.X;
    controller->PlayerCameraManager->ViewPitchMax = OriginViewPitchRange.Y;
    }
    }
    float* ACAttachment_Bow::GetBend()
    {
    return Cast<UCAnimInstance_Bow>(SkeletalMesh->GetAnimInstance())->GetBend();//UCAnimInstance_Bow 안의 GetBend() 함수로 Bend값 리턴. UCAnimInstance_Bow 안의 Bend값을 사용한다.
    }

     

    void ACAttachment_Bow::Tick(float DeltaTime)

    • PoseableMesh->CopyPoseFromSkeletalComponent(SkeletalMesh);
      • 캡처를 삭제(위의 코드 삭제)하고 Do_Action_Bow쪽으로 옮긴다.

     


     

     

    CDoAction  -  OnBegineEquip(), OnUnequip() 함수 추가

     

     

    CDoAction.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "UObject/NoExportTypes.h"
    #include "Weapons/CWeaponStructures.h"
    #include "CDoAction.generated.h"
    UCLASS(Abstract)//DoAction 그 자체로는 객체화되면 안 되기 때문에 Abstract을 붙여준다.
    class U2212_06_API UCDoAction : public UObject
    {
    GENERATED_BODY()
    public:
    UCDoAction();
    virtual void BeginPlay //재정의 할 수 있도록 virtual로 만든다.
    (
    class ACAttachment* InAttachment,
    class UCEquipment* InEquipment,
    class ACharacter* InOwner,
    const TArray<FDoActionData>& InDoActionDatas,//CWeaponStucture내의 FDoActionData
    const TArray<FHitData>& InHitDatas //CWeaponStucture내의 FHitData
    );
    virtual void Tick(float InDeltaTime) { }
    public:
    //재정의 할 수 있도록 virtual로 만든다.
    virtual void DoAction();
    virtual void Begin_DoAction();
    virtual void End_DoAction();
    public:
    //BeginEquip될 때와 Unequip될 때 충돌체를 제거해줘야 한다.
    //CDoAction_Bow에서 재정의 시키기위해 virtual로 만든다.
    UFUNCTION()
    virtual void OnBeginEquip() { }
    UFUNCTION()
    virtual void OnUnequip() { }
    public:
    UFUNCTION()
    virtual void OnAttachmentBeginCollision() {}
    UFUNCTION()
    virtual void OnAttachmentEndCollision() {}
    UFUNCTION()
    virtual void OnAttachmentBeginOverlap(class ACharacter* InAttacker, AActor* InAttackCauser, class ACharacter* InOther) { }
    UFUNCTION()
    virtual void OnAttachmentEndOverlap(class ACharacter* InAttacker, class ACharacter* InOther) { }
    protected:
    bool bInAction;
    bool bBeginAction;
    class ACharacter* OwnerCharacter;
    class UWorld* World;
    class UCMovementComponent* Movement;
    class UCStateComponent* State;
    TArray<FDoActionData> DoActionDatas;
    TArray<FHitData> HitDatas;
    };

    자식 클래스인 CDo_Action_Bow에서 재정의할 함수 추가

    • UFUNCTION()
      virtual void OnBeginEquip() { }
    • UFUNCTION()
      virtual void OnUnequip() { }

    CDoAction_Bow에서 재정의 시키기위해 virtual로 만든다. BeginEquip될 때와 Unequip될 때 충돌체를 제거해줘야 한다. 따라서 CDoAction_Bow에서 재정의할 때 OnBeginEquip()에 충돌을 꺼주고 OnUnequip() 시 충돌을 켜준다.

     

     

    CDoAction.cpp

    더보기
    #include "Weapons/CDoAction.h"
    #include "Global.h"
    #include "CAttachment.h"
    #include "CEquipment.h"
    #include "GameFramework/Character.h"
    #include "Components/CStateComponent.h"
    #include "Components/CMovementComponent.h"
    UCDoAction::UCDoAction()
    {
    }
    void UCDoAction::BeginPlay(ACAttachment* InAttachment, UCEquipment* InEquipment, ACharacter* InOwner, const TArray<FDoActionData>& InDoActionDatas, const TArray<FHitData>& InHitDatas)
    {
    OwnerCharacter = InOwner;
    World = OwnerCharacter->GetWorld();
    State = CHelpers::GetComponent<UCStateComponent>(OwnerCharacter);
    Movement = CHelpers::GetComponent<UCMovementComponent>(OwnerCharacter);
    DoActionDatas = InDoActionDatas;
    HitDatas = InHitDatas;
    }
    void UCDoAction::DoAction()
    {
    bInAction = true;
    State->SetActionMode();
    }
    void UCDoAction::Begin_DoAction()
    {
    bBeginAction = true;
    }
    void UCDoAction::End_DoAction()
    {
    bInAction = false;
    bBeginAction = false;
    State->SetIdleMode();
    Movement->Move();
    Movement->DisableFixedCamera();
    }

    변경사항 없음.

     


     

     

     

    CDoAction_Bow 생성

     

    새 C++ 클래스 - CDoAction - CDoAction_Bow 생성

     

     

    CDoAction_Bow.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "Weapons/CDoAction.h"
    #include "CDoAction_Bow.generated.h"
    UCLASS(Blueprintable)
    class U2212_06_API UCDoAction_Bow : public UCDoAction
    {
    GENERATED_BODY()
    public:
    UCDoAction_Bow();
    void BeginPlay
    (
    class ACAttachment* InAttachment,
    class UCEquipment* InEquipment,
    class ACharacter* InOwner,
    const TArray<FDoActionData>& InDoActionData,
    const TArray<FHitData>& InHitData
    ) override;
    void DoAction() override;
    void Begin_DoAction() override;
    void End_DoAction() override;
    void OnBeginEquip() override;
    void OnUnequip() override;
    void Tick(float InDeltaTime) override;
    public:
    void End_BowString();//AnimNotify_BowString의 Notify에서 콜하여 사용한다.
    private:
    class USkeletalMeshComponent* SkeletalMesh;
    class UPoseableMeshComponent* PoseableMesh;
    private:
    float* Bending;
    private:
    FVector OriginLocation;//처음 위치
    bool bAttachedString = true;//true면 활 시위가 손에 붙는다.
    private:
    const bool* bEquipped;
    };

     

     

     

    CDoAction_Bow.cpp

    더보기
    #include "Weapons/DoActions/CDoAction_Bow.h"
    #include "Global.h"
    #include "Weapons/CEquipment.h"
    #include "Weapons/Attachments/CAttachment_Bow.h"
    #include "GameFramework/Character.h"
    #include "Components/PoseableMeshComponent.h"
    #include "Components/CStateComponent.h"
    #include "Components/CMovementComponent.h"
    UCDoAction_Bow::UCDoAction_Bow()
    {
    }
    void UCDoAction_Bow::BeginPlay(ACAttachment* InAttachment, UCEquipment* InEquipment, ACharacter* InOwner, const TArray<FDoActionData>& InDoActionData, const TArray<FHitData>& InHitData)
    {
    Super::BeginPlay(InAttachment, InEquipment, InOwner, InDoActionData, InHitData);
    SkeletalMesh = CHelpers::GetComponent<USkeletalMeshComponent>(InAttachment);
    PoseableMesh = CHelpers::GetComponent<UPoseableMeshComponent>(InAttachment);
    //CAnimInstance.h의 Bend변수를 CAttachment_Bow의 GetBend()함수를 거쳐 여기로 가져와서 사용한다.
    ACAttachment_Bow* bow = Cast<ACAttachment_Bow>(InAttachment);
    Bending = bow->GetBend();
    OriginLocation = PoseableMesh->GetBoneLocationByName("bow_string_mid", EBoneSpaces::ComponentSpace);
    bEquipped = InEquipment->GetEquipped();//헤더에 만든 bEquipped변수에 장착 상태를 받아와서 넣어준다.
    }
    void UCDoAction_Bow::DoAction()
    {
    CheckFalse(State->IsIdleMode());
    CheckFalse(State->IsSubActionMode());
    Super::DoAction();
    DoActionDatas[0].DoAction(OwnerCharacter);
    }
    void UCDoAction_Bow::Begin_DoAction()//활 발사
    {
    Super::Begin_DoAction();
    bAttachedString = false;//발사하면 활 시위가 손에서 떨어지도록 false로 만들어준다.
    *Bending = 0;//활 구부림 0으로 만들어준다.
    PoseableMesh->SetBoneLocationByName("bow_string_mid", OriginLocation, EBoneSpaces::ComponentSpace);//활 시위를 처음 위치로 돌아가게 만들어준다.
    }
    void UCDoAction_Bow::End_DoAction()
    {
    Super::End_DoAction();
    }
    void UCDoAction_Bow::OnBeginEquip()
    {
    Super::OnBeginEquip();
    OwnerCharacter->GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);//충돌을 꺼준다.
    }
    void UCDoAction_Bow::OnUnequip()
    {
    Super::OnUnequip();
    *Bending = 0;//활 시위 휘어지는 Bending을 0으로 만든다.
    OwnerCharacter->GetMesh()->SetCollisionEnabled(ECollisionEnabled::QueryOnly);//충돌을 켜준다.
    PoseableMesh->SetBoneLocationByName("bow_string_mid", OriginLocation, EBoneSpaces::ComponentSpace);//활 시위를 처음 상태로 돌려준다.
    }
    void UCDoAction_Bow::Tick(float InDeltaTime)
    {
    Super::Tick(InDeltaTime);
    PoseableMesh->CopyPoseFromSkeletalComponent(SkeletalMesh);
    bool bCheck = true;
    bCheck &= (*bEquipped == true);//장착 상태여야 한다.
    bCheck &= (bBeginAction == false);//BeginAction이면(활 발사) 활 시위가 붙으면 안되므로 false여야 한다.
    bCheck &= (bAttachedString == true);//활 시위 붙는게 true여야 한다.
    CheckFalse(bCheck);
    FVector handLocation = OwnerCharacter->GetMesh()->GetSocketLocation("Hand_Bow_Right");
    PoseableMesh->SetBoneLocationByName("bow_string_mid", handLocation, EBoneSpaces::WorldSpace);
    }
    void UCDoAction_Bow::End_BowString()
    {
    *Bending = 100;//활 시위를 땡겨 다시 휘어지게 만들어진다.
    bAttachedString = true;//활 시위가 손에 붙는다.
    }

     

     

     


     

     

     

    AR_ShootAndDraw_Montage 생성

     

    AR_ShootAndDraw

     

     

    AR_ShootAndDraw_Montage

    Begin DoAction: 활 발사

    End_DoAction: 활 시위가 안 휘어지게 Bend를 0으로 만든다. 활 시위와 손이 떨어지게 만든다.

     

    End_BowString: 활 시위가 휘어지게 Bend를 100으로 만든다. 활 시위를 손에 붙인다.

     


     

     

     

    ABP_Character 

     

    기존에 만든부분을 Bose Pose로 저장한다.

     

    BowBody 슬롯을 만든다.

    • '본마다 레이어로 블랜딩합니다'으로 구분한다.

     

     


     

     

     

    DA_Bow에 DoAction Class와 DoAction Data 할당

     

     


     

     

    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 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이 완료되었는지 확인
    };

    델리게이트 추가

    • DECLARE_DYNAMIC_MULTICAST_DELEGATE(FEquipmentEquip);
      • 직렬화하여 BP에서 사용가능하도록 DYNAMIC, 여러함수를 받을 수 있도록 MULTICAST 사용.

     

    변수 추가

    • FEquipmentEquip OnEquipmentEquip;
      • 위에 추가한 DECLARE_DYNAMIC_MULTICAST_DELEGATE에 변수로 사용하였다.

     

    인라인 함수 추가

    • FORCEINLINE const bool* GetEquipped() { return &bEquipped; }
      • 실시간으로 bEquipped로 가져온다. 주소로 가져온다.

     

     

     

    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();
    }

    void UCEquipment::Equip_Implementation()

    • if (OnEquipmentEquip.IsBound())
      OnEquipmentEquip.Broadcast();
      • isBound() 함수는 delegate가 현재 bind되어 있는지 확인하는 함수이고, broadcast() 함수는 delegate를 호출하는 함수다.

     


     

     

    CWeaponAsset

     

     

    CWeaponAsset.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "Engine/DataAsset.h"
    #include "Weapons/CWeaponStructures.h"
    #include "CWeaponAsset.generated.h"
    UCLASS()
    class U2212_06_API UCWeaponAsset : public UDataAsset
    {
    GENERATED_BODY()
    private:
    UPROPERTY(EditAnywhere)
    TSubclassOf<class ACAttachment> AttachmentClass;
    UPROPERTY(EditAnywhere)
    FEquipmentData EquipmentData;
    UPROPERTY(EditAnywhere)
    TSubclassOf<class UCEquipment> EquipmentClass;
    UPROPERTY(EditAnywhere)
    TSubclassOf<class UCDoAction> DoActionClass;
    UPROPERTY(EditAnywhere)
    TArray<FDoActionData> DoActionDatas; //CWeaopnStructure내의 FDoActionData
    UPROPERTY(EditAnywhere)
    TArray<FHitData> HitDatas; //CWeaopnStructure내의 FHitData
    UPROPERTY(EditAnywhere)
    TSubclassOf<class UCSubAction> SubActionClass;
    public:
    FORCEINLINE class ACAttachment* GetAttachment() { return Attachment; }//외부에 생성된 것을 리턴해줌.
    FORCEINLINE class UCEquipment* GetEquipment() { return Equipment; }//외부에 생성된 것을 리턴해줌.
    FORCEINLINE class UCDoAction* GetDoAction() { return DoAction; }//외부에 생성된 것을 리턴해줌.
    FORCEINLINE class UCSubAction* GetSubAction() { return SubAction; }//외부에 생성된 것을 리턴해줌.
    public:
    UCWeaponAsset();
    void BeginPlay(class ACharacter* InOwner);
    private:
    //UPROPERTY를 붙여 가비지 콜렉터가 제거하기 전까지 물고 있게 만든다.
    //UWeaponAsset은 UObject로부터 상속받아 Actor의 생성주기에 영향을 받지 않아 가비지 콜렉터에 영향을 받는다.
    UPROPERTY()
    class ACAttachment* Attachment;
    UPROPERTY()
    class UCEquipment* Equipment;
    UPROPERTY()
    class UCDoAction* DoAction;
    UPROPERTY()
    class UCSubAction* SubAction;
    #if WITH_EDITOR //Editor 내에서만 수행
    void PostEditChangeChainProperty(struct FPropertyChangedChainEvent& PropertyChangedEvent) override;
    #endif
    };

    변경사항 없음

     

     

     

    CWeaponAsset.cpp

    더보기
    #include "Weapons/CWeaponAsset.h"
    #include "Global.h"
    #include "CAttachment.h"
    #include "CEquipment.h"
    #include "CDoAction.h"
    #include "CSubAction.h"
    #include "GameFramework/Character.h"
    UCWeaponAsset::UCWeaponAsset()
    {
    AttachmentClass = ACAttachment::StaticClass();//기본값
    EquipmentClass = UCEquipment::StaticClass();//기본값
    }
    void UCWeaponAsset::BeginPlay(ACharacter* InOwner)
    {
    if (!!AttachmentClass)//AttachmentClass가 선택되어 있다면
    {
    FActorSpawnParameters params;
    params.Owner = InOwner;
    Attachment = InOwner->GetWorld()->SpawnActor<ACAttachment>(AttachmentClass, params);
    }
    if (!!EquipmentClass)//EquipmentClass가 선택되어 있다면
    {
    Equipment = NewObject<UCEquipment>(this, EquipmentClass);
    Equipment->BeginPlay(InOwner, EquipmentData);
    if (!!Attachment)//Attachment가 있다면
    {
    Equipment->OnEquipmentBeginEquip.AddDynamic(Attachment, &ACAttachment::OnBeginEquip);
    Equipment->OnEquipmentUnequip.AddDynamic(Attachment, &ACAttachment::OnUnequip);
    }
    }
    if(!!DoActionClass)
    {
    DoAction = NewObject<UCDoAction>(this, DoActionClass);
    DoAction->BeginPlay(Attachment, Equipment, InOwner, DoActionDatas, HitDatas);
    if (!!Attachment)
    {
    Attachment->OnAttachmentBeginCollision.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginCollision);
    Attachment->OnAttachmentEndCollision.AddDynamic(DoAction, &UCDoAction::OnAttachmentEndCollision);
    Attachment->OnAttachmentBeginOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginOverlap);
    Attachment->OnAttachmentEndOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentEndOverlap);
    }
    if (!!Equipment)//Bow_String 작업
    {
    Equipment->OnEquipmentBeginEquip.AddDynamic(DoAction, &UCDoAction::OnBeginEquip);
    Equipment->OnEquipmentUnequip.AddDynamic(DoAction, &UCDoAction::OnUnequip);
    }
    }
    if(!!SubActionClass)
    {
    SubAction = NewObject<UCSubAction>(this, SubActionClass);
    SubAction->BeginPlay(InOwner, Attachment, DoAction);
    }
    }
    #if WITH_EDITOR //Editor 내에서만 수행
    void UCWeaponAsset::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent)
    {
    Super::PostEditChangeChainProperty(PropertyChangedEvent);
    CheckTrue(FApp::IsGame());//게임이 실행중이면 실행하면 안 되기 때문에 체크
    bool bRefresh = false;
    bRefresh |= PropertyChangedEvent.GetPropertyName().Compare("DoActionDatas") == 0;
    bRefresh |= PropertyChangedEvent.GetPropertyName().Compare("HitDatas") == 0;//수정하려는 변수명 == 0 이면 이름이 동일하다는 의미.
    if (bRefresh)
    {
    bool bCheck = false;
    bCheck |= PropertyChangedEvent.ChangeType == EPropertyChangeType::ArrayAdd;
    bCheck |= PropertyChangedEvent.ChangeType == EPropertyChangeType::ArrayRemove;
    bCheck |= PropertyChangedEvent.ChangeType == EPropertyChangeType::ArrayClear;
    bCheck |= PropertyChangedEvent.ChangeType == EPropertyChangeType::Duplicate;
    if (bCheck)
    {
    FPropertyEditorModule& prop = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");//WITH_EDITOR로 Editor 내에서 수행하기 때문에 사용 가능.
    TSharedPtr<IDetailsView> detailsView = prop.FindDetailView("WeaponAssetEditorDetailsView");//WeaponAssetEditor.cpp에서 설정한 arg.ViewIdentifier이름 WeaponAssetEditorDetailsView 사용. WeaponAssetEditorDetailsView를 찾는다.
    if (detailsView.IsValid())//detailsView 창이 그려졌다면
    detailsView->ForceRefresh();//새로고침
    }
    }
    }
    #endif

    함수 내용 추가

    void UCWeaponAsset::BeginPlay(ACharacter* InOwner)

    • if(!!DoActionClass) //DoAction 클래스가 있다면
      • if (!!Equipment) //Equipment가 true라면
        • Equipment->OnEquipmentBeginEquip.AddDynamic(DoAction, &UCDoAction::OnBeginEquip);
        • Equipment->OnEquipmentUnequip.AddDynamic(DoAction, &UCDoAction::OnUnequip);
        • OnBegineEquip과 OnUnequip함수를 델리게이트 연결처리해준다.

     


     

     

     

    CAnimNotify_BowString 생성

     

    새 C++ 클래스- AnimNotify - CAnimNotify_BowString 생성 

     

     

    CAnimNotify_BowString.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "Animation/AnimNotifies/AnimNotify.h"
    #include "CAnimNotify_BowString.generated.h"
    UCLASS()
    class U2212_06_API UCAnimNotify_BowString : public UAnimNotify
    {
    GENERATED_BODY()
    public:
    FString GetNotifyName_Implementation() const override;
    void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) override;
    };

     

     

     

     

    CAnimNotify_BowString.cpp

    더보기
    #include "Notifies/CAnimNotify_BowString.h"
    #include "Global.h"
    #include "Components/CWeaponComponent.h"
    #include "Weapons/DoActions/CDoAction_Bow.h"
    FString UCAnimNotify_BowString::GetNotifyName_Implementation() const
    {
    return "End_BowString";
    }
    void UCAnimNotify_BowString::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation)
    {
    Super::Notify(MeshComp, Animation);
    CheckNull(MeshComp);
    CheckNull(MeshComp->GetOwner());
    UCWeaponComponent* weapon = CHelpers::GetComponent<UCWeaponComponent>(MeshComp->GetOwner());
    CheckNull(weapon);
    CheckNull(weapon->GetDoAction());
    UCDoAction_Bow* bow = Cast<UCDoAction_Bow>(weapon->GetDoAction());
    CheckNull(bow);
    bow->End_BowString();//CDoAction_Bow의 End_BowString을 콜하여 활 시위를 휘게 만들고 손에 붙인다.
    }

     

     

     

     


     

     

    실행화면

     

     

     


     

     

    '⭐ Unreal Engine > UE RPG Skill' 카테고리의 다른 글

    [UE] 파쿠르 구현하기  (0) 2023.07.18
    [UE] 화살  (0) 2023.07.13
    [UE] 활 시위 당기기  (0) 2023.07.07
    [UE] 활 조준  (0) 2023.07.06
    [UE] 활 구현하기  (0) 2023.07.05