초보 코린이의 성장 일지

UE4 Weapon Bow 본문

언리얼

UE4 Weapon Bow

코오린이 2023. 7. 5. 16:25

Bow를 이제 만들어 볼 것이다. BP때와 동일하게 어려운 부분이 많을 것이다.

1. 파생클래스로 Attachment_Bow를 생성해준다.

#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:
	// Pitch 각 제한하기위해
	UPROPERTY(EditDefaultsOnly, Category = "View")
		FVector2D ViewPitchRange = FVector2D(-40, +30);

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;

};
#include "Weapons/Attachments/CAttachment_Bow.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"); // 활은 충돌되면 안되므로 NoCollision

}

void ACAttachment_Bow::BeginPlay()
{
	Super::BeginPlay();

	AttachTo("Holster_Bow");

	SkeletalMesh->SetVisibility(false);

	PoseableMesh->SetSkeletalMesh(SkeletalMesh->SkeletalMesh); // 숨겨놓은 SkelMesh를 넣어준다.
	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"); // 장착시켜준다.
    
}

void ACAttachment_Bow::OnUnequip_Implementation()
{
	Super::OnUnequip_Implementation();

	AttachTo("Holster_Bow");
    
}

1. 나중에 활 시위가 당겨질때 활줄이 늘어나는 효과를 주기위해, 캡처를 할 수 있도록 코드를 작성해준다.

2. 활과 충돌을 off 시켜주고, 장착, 해제를 만들어준다.


#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/CWeaponComponent.h"
#include "Components/CMontagesComponent.h"
#include "Components/CMovementComponent.h"

void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

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

1. Player로가서 Bow 장착을 위해 키 등록을 해준다.


1. 만들어 놓은 Attachment를 BP 클래스로 생성해준다.

1. Bow용 DataAsset를 생성해준다.

1. Attachment Class에 Bow를 선택해준다.

1. Player로가서 6번에 Bow를 등록해준다.

1. Equip에 사용할 몽타주에 노티파이를 넣어준다.

1. 다시 Asset로와서 Data에 Equip 몽타주를 넣어준다.

1. 활을 들고있는 모션이 나오는걸 확인할 수 있다.

1. Bow를 추가해준다.

1. 애니메이션 레이어를 하나 추가해준다.

2. 블랜드스페이스와 값들을 연결시켜준다.

1. 만들어준 레이어를 연결시켜준다.

1. 손으로만 들고있던 Bow가 아닌 제대로된 동작이 호출되는걸 확인할 수 있다.


#include "Weapons/Attachments/CAttachment_Bow.h"
#include "Global.h"
//#include "Characters/CAnimInstance_Bow.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/PoseableMeshComponent.h"

void ACAttachment_Bow::OnBeginEquip_Implementation()
{
	Super::OnBeginEquip_Implementation();

	AttachTo("Hand_Bow_Left"); // 장착시켜준다.

	APlayerController* controller = OwnerCharacter->GetController<APlayerController>();
	if (!!controller)
	{
		// Bow 착용시 상하 움직임 제한 걸어준다.
		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");

	APlayerController* controller = OwnerCharacter->GetController<APlayerController>();
	if (!!controller)
	{
		// 제한을 다시 풀어준다.
		controller->PlayerCameraManager->ViewPitchMin = OriginViewPitchRange.X;
		controller->PlayerCameraManager->ViewPitchMax = OriginViewPitchRange.Y;

	}
}

1. 활 착용시 상하 움직임에 제한을줘서 자연스럽게 만들어준다.

1. 제한걸린 수치. 그 이상 올라가지 않는다.


1. 클래스를 하나 생성해준다.


1. Curve를 생성해서, 사용해 볼 것이다.

1. 우선 X축 작업을 먼저 진행할 것이므로, 나머지 축들은 오른쪽 마크를 눌러서 잠시 숨겨둔다.

1. 아무곳이나 클릭 후 엔터를 눌러서 키를 등록해준다.  20초로 설정, 45도까지 떨어지도록 값을 넣어준다.

1. 커브를 클릭 후 부드럽게 커브 보정처리를 해준다.

1. 이제 다시 Y축도 커브를 줄 것이다.

1. 20 ~ 100으로 값을 넣어준다.

1. Y축도 보정처리를 해주면, X와 Y에 커브가 이런 모양이 완성된다.

1. Bow를 당길때 움직임을 주기 위해 Bow Skeleton을 선택 후 블렌드를 만들어준다.

1. 커브값을 조금 높게 잡았으므로, 0 ~ 100으로 설정. 나중에 그 값들을 내가 원하는 만큼 나눠서 사용할 것.

2. 동작이 2개뿐이므로, 칸은 1개로 만들어준다. 

3. 왼쪽에 Idle, 오른쪽 끝에 당겨지는 애니메이션을 넣어서 활줄이 당겨지는 효과가 나오는걸 볼 수 있다.


 

1. 타임라인을 사용할 것인데, 그냥 타임라인이 있고 타임라인 컴포넌트가있다.

2. SubAction은 Actor로 만든게 아니기 때문에 컴포넌트를 가질수 없기 때문에 그냥 타임라인을 사용하는 것이다.

3. 굳이 컴포넌트로 사용하려면, Actor로 만들어서 사용하면 동일하게 된다.

4. 사용할 타임라인 부모로 따라서 들어가보면 UCLASS(MinimalAPI)를 보게된다.

5. 타임라인 컴포넌트를 사용하려면, 내부적으로 소유하고 쓸 뿐, 내부로 접근해서 쓸 수 없다는 의미를 말한다.

6. 또 한 위에 언급했듯이 Actor이 현재는 아니므로 사용할 순 없다. 그래서 우리는 FTimeline를 사용할 것이다.

7. 그 기능을 가져다가 좀 더 편하게 사용할 수 있게끔 정의되어있다.

8. 또 한 ReplicatedUsing를 이용해서 서버와 통신해서 타이밍을 맞출 수 있도록 정의까지 되어있다.


#pragma once

#include "CoreMinimal.h"
#include "Components/TimelineComponent.h"
#include "Weapons/CSubAction.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;

    // 커브에 20초를 줬으므로, 200으로 나누면 0.1초가 될 것이다.
    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;

};
#include "Weapons/SubActions/CSubAction_Bow.h"
#include "Components/TimelineComponent.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'");

}

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을 콜해준다.

	// 커브 Vector 사용, 매개변수 2번째에는 델리게이션이 들어간다.
	Timeline.AddInterpVector(Curve, timeline);
	Timeline.SetPlayRate(AimingSpeed); // 속도

}

void UCSubAction_Bow::Tick_Implementation(float InDeltaTime)
{
	Super::Tick_Implementation(InDeltaTime);

	// 타임라인을 동작시켜주기, 컴포넌트였다면 자기자신에 Tick이 존재하고있어 자신의 Tick 콜을 이미하고있으므로 서용 안해도된다.
	Timeline.TickTimeline(InDeltaTime);
}

void UCSubAction_Bow::OnAiming(FVector Output)
{
	// 이안에서 타임라인을 콜해주는게 아닌, 이 곳에 설정을 해주고 Tick에서 순간마다 콜을 해줘야한다.

}

1. 타임라인과 타임라인 컴포넌트에 차이와 사용법이 위에 써져있다.


https://www.youtube.com/watch?v=27O-6qitdd0 

 

'언리얼' 카테고리의 다른 글

UE4 Bow Aim (2)  (0) 2023.07.07
UE4 Bow Aim  (0) 2023.07.06
UE4 SubAction Around Skill  (0) 2023.07.04
UE4 SubAction Around Skill  (0) 2023.07.03
UE4 SubAction Warp, Top View  (0) 2023.06.30
Comments