이전에 만든 Attachment을 구조를 활용하여 활 무기를 추가해보자. CAttachment_Bow를 생성하여 활용하여 활은 만든다. BlendSpace와 Curve를 활용하여 활이 구부러지는 것을 구현한다. 

 

목차

     

     


     

     

     
    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
     

     

     

     

    활 구현하기

     


     

    CPlayer.cpp  -  키 맵핑 (Bow)

     

    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"
    
    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");
    
    	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);
    
    }
    
    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->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, Weapon, &UCWeaponComponent::SubAction_Pressed);
    	PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Released, Weapon, &UCWeaponComponent::SubAction_Released);
    }
    
    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::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)

    • PlayerInputComponent->BindAction("Bow", EInputEvent::IE_Pressed, Weapon,  &UCWeaponComponent::SetBowMode);

     

     

    CAttachment

     

    CAttachment.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "GameFramework/Actor.h"
    #include "CAttachment.generated.h"
    
    DECLARE_DYNAMIC_MULTICAST_DELEGATE(FAttachmentBeginCollision);
    DECLARE_DYNAMIC_MULTICAST_DELEGATE(FAttachmentEndCollision);
    
    DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FAttachmentBeginOverlap, class ACharacter*, InAttacker, AActor*, InAttackCauser, class ACharacter*, InOther);
    DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FAttachmentEndOverlap, class ACharacter*, InAttacker, class ACharacter*, InOther);
    
    UCLASS()
    class U2212_06_API ACAttachment : public AActor
    {
    	GENERATED_BODY()
    
    protected:
    	UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
    		class USceneComponent* Root;
    	
    public:	
    	ACAttachment();
    
    protected:
    	virtual void BeginPlay() override;
    
    public:
    	UFUNCTION(BlueprintNativeEvent)
    		void OnBeginEquip();
    	virtual void OnBeginEquip_Implementation() {}
    
    	UFUNCTION(BlueprintNativeEvent)
    		void OnUnequip();
    	virtual void OnUnequip_Implementation() {}
    
    	//위에걸로 수정하였다.
    	/*UFUNCTION(BlueprintImplementableEvent)
    		void OnBeginEquip();
    
    	UFUNCTION(BlueprintImplementableEvent)
    		void OnUnequip();*/
    
    public:
    	void OnCollisions(); //Collision 켜기
    	void OffCollisions();//Collision 끄기
    
    private:
    	UFUNCTION()
    		void OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
    
    	UFUNCTION()
    		void OnComponentEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
    
    protected:
    	UFUNCTION(BlueprintCallable, Category = "Attach")
    		void AttachTo(FName InSocketName);
    
    	UFUNCTION(BlueprintCallable, Category = "Attach")
    		void AttachToCollision(FName InCollisionName);
    
    public:
    	FAttachmentBeginCollision OnAttachmentBeginCollision;
    	FAttachmentEndCollision OnAttachmentEndCollision;
    
    	FAttachmentBeginOverlap OnAttachmentBeginOverlap;
    	FAttachmentEndOverlap OnAttachmentEndOverlap;
    
    protected:
    	UPROPERTY(BlueprintReadOnly, Category = "Game")
    		class ACharacter* OwnerCharacter;
    
    	//UShapeComponent는 UBox,Capsule,SphereComponent의 상위클래스
    	UPROPERTY(BlueprintReadOnly, Category = "Game")
    		TArray<class UShapeComponent*> Collisions;
    };

    수정 전

    • UFUNCTION(BlueprintImplementableEvent)
      void OnBeginEquip();

    • UFUNCTION(BlueprintImplementableEvent)
      void OnUnequip()

     

     

    수정 후

    • UFUNCTION(BlueprintNativeEvent)
      void OnBeginEquip();
      virtual void OnBeginEquip_Implementation() {}

    • UFUNCTION(BlueprintNativeEvent)
      void OnUnequip();
      virtual void OnUnequip_Implementation() {}

     

     

    CAttachment_Bow 생성

     

    새 C++ 클래스 생성 - CAttachment - 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:
        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.cpp

    더보기
    #include "Weapons/Attachments/CAttachment_Bow.h"
    #include "Global.h"
    #include "Global.h"
    //#include "Characters/CAnimInstance_Bow.h"
    #include "Components/SkeletalMeshComponent.h"
    #include "Components/PoseableMeshComponent.h"
    
    ACAttachment_Bow::ACAttachment_Bow()
    {
    	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");
    }
    
    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;
    	}
    }

     

     

     

    BP_CAttachment_Bow 생성

     


     

     

     

    ABP_Character  -  Bow 동작 추가하기

     

    새 애니메이션 레이어 - BowLayer 생성

     

     

    AnimGraph

    블랜드 포즈 (EWeaponType)에 Bow 포즈 추가

    • 링크된 애님 레이어 생성 - 방금 전에 만든 BowLayer 설정하고 이어준다.

     


     

     

    CSubAction_Bow 생성

     

    새 C++ 클래스 생성 - CSubAction - 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으로 작업한다.

     

     

     

    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::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");
    
    	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)
    {
    }

     

     

     

     

     

    ※참고: TimelineComponent.h

     


     

     

    BS_Aiming 생성

     

    애니메이션 - 블래드 스페이스 1D - Skeleton_ElvenBow 선택 - BS_Aiming 생성

     

    Axis Settings

    • 가로 축
      • Name: Blend
      • Minimum Axis Value: 0.0
      • Maximum Axis Value: 100.0
      • Number of Grid Divisions: 1

     


     

     

     

    Curve_Aiming 생성

     

    기타 - 커브 - Curve_Aiming 생성

     

    Y는 활의 휘는 정도를 조절하는 값이다.

     

     

     


     

     

     

    DA_Bow 생성

     

     


     

     

    실행화면

     

     

     


     

     

     

     

    클래스 지정자

     

     


     

    Minimal API

     

    private vs Minimal

    • private은 컴파일러 자체에서 숨겨버린다.
    • Minimal은 직렬화만 못하게 막아준다. 외부 노출을 최소화하여 속도를 높인다.
      • 형 변환이 가능하지만, (inline 함수를 제외하고) 호출할 수 없다.
      • .cpp 다 무시. .h에서 컴파일되는 inline 함수는 컴파일된다.

     

     

    Minimal API 사용

     

    class A : Character

    {

      void Add() { }

      inline void Add() { }

     

     

    A* ob = new A();

    ob->Add(); 가능

     

    Character* a = Cast<ACharacter>(ob);

    ob->Add(); 사용 불가능.

    단, inline함수로 선언된 경우 사용 가능하다. inline은 헤더 기준으로 컴파일 된다고 봐도 무방하다.

     

     

     

    https://docs.unrealengine.com/4.27/ko/ProgrammingAndScripting/GameplayArchitecture/Classes/Specifiers/

     

    클래스 지정자

    클래스가 엔진과 에디터의 다양한 부분과 어떻게 작동하는지를 지정하기 위해 UClass 선언시 사용되는 키워드입니다.

    docs.unrealengine.com

     

    Transient

     

     


     

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

    [UE] 활 시위 당기기  (0) 2023.07.07
    [UE] 활 조준  (0) 2023.07.06
    [UE] Around 스킬 구현하기  (0) 2023.07.04
    [UE] Around 공격 구현하기  (0) 2023.07.03
    [UE] 워프 Top View 만들기  (0) 2023.06.30