지난 시간에는 BlendSpace1D를 사용하여 활이 구부러지는것을 구현하였다. 오늘은 활의 SkeletalMesh에 AnimInstance를 만들어 활의 시위가 당겨지는 것을 구현하겠다. CAnimInstance_Bow, CAttachment_Bow, 그리고 CSubAction_Bow는 서로 상속관계가 아니므로  활 시위가 당겨지는 float 변수(여기서는 float Bend)를 만들어 이어줘야 한다.

 

 

목차

     

     


     

     

     
    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 
    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_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
     

     

     

     

     

    활 시위 당기기

     

     


     

     

    CAnimInstance_Bow 생성  +  ABP_ElevenBow

     

    새 C++ 클래스 - AnimInstance - CAnimInstance_Bow 생성

     

     

    CAnimInstance_Bow.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Animation/AnimInstance.h"
    #include "Components/CWeaponComponent.h"
    #include "CAnimInstance.generated.h"
    
    UCLASS()
    class U2212_06_API UCAnimInstance : public UAnimInstance
    {
    	GENERATED_BODY()
    
    protected:
        UPROPERTY(BlueprintReadOnly, Category = "Animation")
            float Speed;
    
        UPROPERTY(BlueprintReadOnly, Category = "Animation")
            float Pitch;
    
        UPROPERTY(BlueprintReadOnly, Category = "Animation")
            float Direction;
    
        UPROPERTY(BlueprintReadOnly, Category = "Animation")
            bool bBow_Aiming;
    
    protected:
        UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Animation")
            EWeaponType WeaponType = EWeaponType::Max;
    
    public:
        void NativeBeginPlay() override;
        void NativeUpdateAnimation(float DeltaSeconds) override;
    
    private:
        UFUNCTION()
            void OnWeaponTypeChanged(EWeaponType InPrevType, EWeaponType InNewType);
    
    private:
        class ACharacter* OwnerCharacter;
        class UCWeaponComponent* Weapon;
    
    private:
        FRotator PrevRotation;
    };

     

     

     

    CAnimInstance_Bow.cpp

    더보기
    #include "Weapons/AnimInstances/CAnimInstance_Bow.h"
    #include "Global.h"
    
    void UCAnimInstance_Bow::NativeBeginPlay()
    {
    	Super::NativeBeginPlay();
    
    }
    
    void UCAnimInstance_Bow::NativeUpdateAnimation(float DeltaSeconds)
    {
    	Super::NativeUpdateAnimation(DeltaSeconds);
    
    }

     

     

     

     

     

    ABP_ElevenBow

    애니메이션 - 애니메이션 블루프린트 생성 - CAnimInstance_Bow, Skeletal_ElvenBow - ABP_ElevenBow 생성

    CAnimInstance_Bow에서 만든 변수 Bend 사용. Bend 변수를 활 시위의 당기는 정도로 사용한다.

     


     

     

    CAttachment_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;
    };

    함수 추가

    • float* GetBend();

     

     

     

    CAttachment_Bow.cpp

    더보기
    #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> animInstacne;
    	CHelpers::GetClass<UCAnimInstance_Bow>(&animInstacne, "AnimBlueprint'/Game/Weapons/Bow/ABP_ElvenBow.ABP_ElvenBow_C'");//ABP_ElvenBow 레퍼런스 복사하여 생성.
    	SkeletalMesh->SetAnimInstanceClass(animInstacne);
    }
    
    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);
    
    	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값을 사용한다.
    }

    헤더 추가

    • #include "Weapons/AnimInstances/CAnimInstance_Bow.h"

     

    ACAttachment_Bow::ACAttachment_Bow()

    • PrimaryActorTick.bCanEverTick = true;
      • 실시간 적용이 되도록 넣어준다. 안 넣어주면 활 시위가 구부러지는것이 업데이트 되지 않을 수도 있다.
    • TSubclassOf<UCAnimInstance_Bow> animInstacne;
    • CHelpers::GetClass<UCAnimInstance_Bow>(&animInstacne, "AnimBlueprint'/Game/Weapons/Bow/ ABP_ElvenBow.ABP_ElvenBow_C'");
      • ABP_ElvenBow 레퍼런스 복사하여 생성.
    • SkeletalMesh->SetAnimInstanceClass(animInstacne);

     

    float* ACAttachment_Bow::GetBend()

    • return Cast<UCAnimInstance_Bow>(SkeletalMesh->GetAnimInstance())->GetBend();
      • UCAnimInstance_Bow 안의 GetBend() 함수로 Bend값 리턴. UCAnimInstance_Bow 안의 Bend값을 사용한다.

     

     

     


     

     

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

    변수 추가

    • float Bend;

     

     

     

    CSubAction_Bow.cpp

    더보기
    #include "Weapons/SubActions/CSubAction_Bow.h"
    #include "Global.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());
    	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());
    	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까지 나온다.
    }

    void UCSubAction_Bow::BeginPlay(ACharacter* InOwner, ACAttachment* InAttachment, UCDoAction* InDoAction)

    • if (!!bow)
      Bend = bow->GetBend();
      • CSubAction_Bow에서 선언한 Bend 변수에 CAttachment_Bow의 Bend값을 GetBend()로 가져와서 넣어준다.

     

    void UCSubAction_Bow::onAiming(FVector Output)

    • Camera->FieldOfView = Output.X;//
      • 조준 활성화와 해제에 앞뒤 ZoomIn&Out에 Output.X값이 쓰인다.
    • if (!!Bend)
      *Bend = Output.Y;//에디터의 Curve_Aiming에서 설정한 Y값. 0~100까지 나온다.
      }

     

     


     

    실행화면

     

     

     


     

     

     

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

    [UE] 화살  (0) 2023.07.13
    [UE] 활 시위에 손 맞추기  (0) 2023.07.10
    [UE] 활 조준  (0) 2023.07.06
    [UE] 활 구현하기  (0) 2023.07.05
    [UE] Around 스킬 구현하기  (0) 2023.07.04