지난 시간에 이어 활 조준을 구현해보자. 활의 BlendSpace 1D를 만든 것처럼 플레이어 애니메이션도 BlendSpace 1D로 만들어 활 조준을 자연스럽게 구현할 것이다. 

 

 

목차

     

     


     

     

     

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

     

     

     

     

     

    활 조준 Zoom & Out

     

     


     

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

    함수 추가 - 우클릭 했을 때 조준되고 때었을 때 조준이 해제되도록 하는 역할

    • virtual void Pressed() override;
    • virtual void Released() override;

     

    변수 추가

    • FAimData OriginData;
      • Aim 전의 데이터를 담아주는 변수

     

     

    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);
    }
    
    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값이 쓰인다.
    	
    }

    함수 정의

    • void UCSubAction_Bow::Pressed()
    • void UCSubAction_Bow::Released()

     

     


     

     

    실행화면

     

    void UCSubAction_Bow::onAiming(FVector Output)
    {
    CLog::Printf(Output, 1);
    }

     

    Roll과 Pitch값 변화 (90, 0) ↔ (45, 100)

     

     

    void UCSubAction_Bow::onAiming(FVector Output)
    {
    Camera->FieldOfView = Output.X;//조준 활성화와 해제에 앞뒤 ZoomIn&Out에 Output.X값이 쓰인다.
    }

     


     

     

     

     

    활 조준

     


     

     

    AR_Aim2 생성  +  애니메이션 5개의 Base Pose 애니메이션으로 설정

     

     

    AR_ShootAndDraw 복제하여 AR_Aim2 생성 - 0프레임 제외하고 제거(=프레임 1에서 프레임 38까지 제거)

     

     

    애니메이션 편집

    • AR_Aim_C, AR_Aim_D, AR_Aim_90, AR_Aim_U, AR_Aim_U90 선택
    • 애셋 액션 - 프로퍼티 매트릭스를 통한 대량 편집

     

    1. 다섯개의 애니메이션 선택
    2. Base Pose Animation
      1. 애셋 선택 - AR_Aim2 선택

     


     

     

    AO_Aim 생성

     

    애니메이션 - 에임 오프셋 1D - Skel_Mannequin - AO_Aim 생성

     

     


     

     

    CAnimInstance

     

     

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

    변수 추가

    • UPROPERTY(BlueprintReadOnly, Category = "Animation")
       bool bBow_Aiming;

     

     

     

    CAnimInstance.cpp

    더보기
    #include "Characters/CAnimInstance.h"
    #include "Global.h"
    #include "GameFramework/Character.h"
    #include "Weapons/CSubAction.h"
    
    void UCAnimInstance::NativeBeginPlay()
    {
    	Super::NativeBeginPlay();
    
    	OwnerCharacter = Cast<ACharacter>(TryGetPawnOwner());
    	CheckNull(OwnerCharacter);
    
    	Weapon = CHelpers::GetComponent<UCWeaponComponent>(OwnerCharacter);
    	if (!!Weapon)
    		Weapon->OnWeaponTypeChange.AddDynamic(this, &UCAnimInstance::OnWeaponTypeChanged);
    }
    
    void UCAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
    {
    	Super::NativeUpdateAnimation(DeltaSeconds);
    	CheckNull(OwnerCharacter);
    
    	Speed = OwnerCharacter->GetVelocity().Size2D();
    
    	FRotator rotator = OwnerCharacter->GetVelocity().ToOrientationRotator();
    	FRotator rotator2 = OwnerCharacter->GetControlRotation();
    	FRotator delta = UKismetMathLibrary::NormalizedDeltaRotator(rotator, rotator2);
    	PrevRotation = UKismetMathLibrary::RInterpTo(PrevRotation, delta, DeltaSeconds, 25);
    	Direction = PrevRotation.Yaw;
    
    	Pitch = UKismetMathLibrary::FInterpTo(Pitch, OwnerCharacter->GetBaseAimRotation().Pitch, DeltaSeconds, 25);
    
    
    	CheckNull(Weapon);//무기가 있는지 확인
    
    	if (!!Weapon->GetSubAction())
    	{
    		bBow_Aiming = true;
    		bBow_Aiming &= WeaponType == EWeaponType::Bow;
    		bBow_Aiming &= Weapon->GetSubAction()->GetInAction();		
    	}	
    }
    
    void UCAnimInstance::OnWeaponTypeChanged(EWeaponType InPrevType, EWeaponType InNewType)
    {
    	WeaponType = InNewType;
    }

    헤더 추가

    • #include "Weapons/CSubAction.h"

     

    함수 정의

    • void UCAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
      • CheckNull(Weapon);
        • 무기가 있는지 확인
      • if (!!Weapon->GetSubAction())
        {
        bBow_Aiming = true;
        bBow_Aiming &= WeaponType == EWeaponType::Bow;
        bBow_Aiming &= Weapon->GetSubAction()->GetInAction();
        }
        • SubAction이 true라면(=SubAction 실행중이라면) bBow_Aiming을 true로, WeaponType을 Bow로, GetInAction()을 true로 만들어준다.

     

     


     

     

    ABP_Player

     

    BowLayer

     

     

     


     

     

     

    CSubAction

     

     

    CSubAction.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "UObject/NoExportTypes.h"
    #include "CSubAction.generated.h"
    
    UCLASS(Abstract)//객체화하지 않는 경우, Abstract 명시
    class U2212_06_API UCSubAction : public UObject
    {
    	GENERATED_BODY()
    
    public:
    	FORCEINLINE bool GetInAction() { return bInAction; }
    
    public:
    	UCSubAction();
    
    public:
    	virtual void BeginPlay(class ACharacter* InOwner, class ACAttachment* InAttachment, class UCDoAction* InDoAction);
    
    public:
    	virtual void Pressed();
    	virtual void Released();
    
    public:
    	//NativeEvent는 가상화. 정의할테니 원하면 가져다가 써라는 의미.
    	//Implementation는 추상화. 함수 호출 해줄테니 필요하면 재정의해서 써라.
    	UFUNCTION(BlueprintNativeEvent)
    		void Begin_SubAction();
    	virtual void Begin_SubAction_Implementation() {}
    
    	UFUNCTION(BlueprintNativeEvent)
    		void End_SubAction();
    	virtual void End_SubAction_Implementation() {}
    
    	UFUNCTION(BlueprintNativeEvent)
    		void Tick(float InDeltaTime);
    	virtual void Tick_Implementation(float InDeltaTime) {}
    
    protected:
    	bool bInAction;
    
    	class ACharacter* Owner;
    	class ACAttachment* Attachment;
    	class UCDoAction* DoAction;
    
    	class UCStateComponent* State;
    	class UCMovementComponent* Movement;
    };

    변수 추가

    •  bool bInAction;

     

    함수 변형

    • virtual void Pressed();
    • virtual void Released();

     

    함수 추가

    • FORCEINLINE bool GetInAction() { return bInAction; }
      • bInAction이 true인지 false인지 리턴해주는 함수.

     

     

     

    CSubAction.cpp

    더보기
    #include "Weapons/CSubAction.h"
    #include "Global.h"
    #include "GameFramework/Character.h"
    #include "Components/CStateComponent.h"
    #include "Components/CMovementComponent.h"
    #include "Components/CapsuleComponent.h"
    
    UCSubAction::UCSubAction()
    {
    }
    
    void UCSubAction::BeginPlay(ACharacter* InOwner, ACAttachment* InAttachment, UCDoAction* InDoAction)
    {
    	Owner = InOwner;
    	Attachment = InAttachment;
    	DoAction = InDoAction;
    
    	State = CHelpers::GetComponent<UCStateComponent>(Owner);
    	Movement = CHelpers::GetComponent<UCMovementComponent>(Owner);
    }
    
    void UCSubAction::Pressed()
    {
    	bInAction = true;
    }
    
    void UCSubAction::Released()
    {
    	bInAction = false;
    }

    함수 정의

    • void UCSubAction::Pressed()  { bInAction = true; }
    • void UCSubAction::Released() { bInAction = false; }

     


     

     

     

    실행화면

     

     


     

     

     

     

     

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

    [UE] 활 시위에 손 맞추기  (0) 2023.07.10
    [UE] 활 시위 당기기  (0) 2023.07.07
    [UE] 활 구현하기  (0) 2023.07.05
    [UE] Around 스킬 구현하기  (0) 2023.07.04
    [UE] Around 공격 구현하기  (0) 2023.07.03