초보 코린이의 성장 일지

UE4 SubAction Fist, Ghost Trail 본문

언리얼

UE4 SubAction Fist, Ghost Trail

코오린이 2023. 6. 22. 14:52

Ghost 효과를 만들어서 Fist 스킬에 사용해 볼 것이다.

 

1. 머터리얼을 생성해준다.

1. 이미시브가 외곽선을 나타낸다. 사이드가 밝게 보이는걸 확인할 수 있다.

1. Blend Mode를 Translucent로 바꿔줘야 반투명으로 만들 수 있다. 

1. 반사, 굴절, 프레넬(Freznel) 방정식을 사용할 것이다. 구현하는 이유는 반사와 굴절을 동시에 구현할때 사용한다.

2. Fresnel와 Exponent가 곱해지면 제곱이 된다.

3. Color와 곱하게 되면 제곱된 값이 색상하고 섞이는 구조가 된다. 

4. 제곱 이상에 수치가되면 밝으로 색상이 몰리게 되는 효과가 나온다.

5. 마지막 곱할때 20을 주는 이유는 컬러는 1을 넘어가면 1로 제한이 될 것이고, 이미시브는 20 수치 그대로 들어가기 때문에 노드를 저렇게 연결시켜도 된다.

6. Exponent를 1값으로 변경하면 반투명이된다.

 

오파시티는 1넘어가는 수치는 다 1로 정해버린다.

 

1. 만든 머터리얼 인스턴스를 만들어 준다.


#pragma once

#include "CoreMinimal.h"
#include "Particles/ParticleSystem.h"
#include "NiagaraSystem.h"
#include "NiagaraFunctionLibrary.h"
#include "GameFramework/Character.h"
#include "Components/CapsuleComponent.h"
#include "Weapons/AddOns/CGhostTrail.h"

#define CheckTrue(x) { if(x == true) return; }
#define CheckTrueResult(x, y) { if(x == true) return y; }

#define CheckFalse(x) { if(x == false) return;}
#define CheckFalseResult(x, y) { if(x == false) return y;}

#define CheckNull(x) { if(x == nullptr) return;}
#define CheckNullResult(x, y) { if(x == nullptr) return y;}


#define CreateTextRender()\
{\
	CHelpers::CreateComponent<UTextRenderComponent>(this, &Text, "Tex", Root);\
	Text->SetRelativeLocation(FVector(0, 0, 100));\
	Text->SetRelativeRotation(FRotator(0, 180, 0));\
	Text->SetRelativeScale3D(FVector(2));\
	Text->TextRenderColor = FColor::Red;\
	Text->HorizontalAlignment = EHorizTextAligment::EHTA_Center;\
	Text->Text = FText::FromString(GetName().Replace(L"Default__", L""));\
}

class U2212_06_API CHelpers
{
public:

	// 생성 클래스 타입, 플레이될 객체
	static ACGhostTrail* Play_GhostTrail(TSubclassOf<ACGhostTrail>& InClass, class ACharacter* InOwner)
	{
		CheckNullResult(InClass, nullptr);
		CheckNullResult(InOwner, nullptr);

		// 충돌되었어도 반드시 스판되도록,
		FActorSpawnParameters params;
		params.Owner = InOwner;
		params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;

		// 스판될 위치
		FVector location = InOwner->GetActorLocation();
		location.Z -= InOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();

		FTransform transform;
		transform.SetTranslation(location);

		return InOwner->GetWorld()->SpawnActor<ACGhostTrail>(InClass, transform, params);
	}

};

1. 사용하기 편하게 만들기 위해 하나의 함수로 만들어 준다.

 


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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CGhostTrail.generated.h"

UCLASS()
class U2212_06_API ACGhostTrail : public AActor
{
	GENERATED_BODY()

private:
    UPROPERTY(EditDefaultsOnly, Category = "Capture")
        float StartDelay = 0;

    UPROPERTY(EditDefaultsOnly, Category = "Capture")
        float Interval = 0.25f; // 애니메이션 캡처 간격

    UPROPERTY(EditDefaultsOnly, Category = "Capture")
        FLinearColor Color = FLinearColor(1, 1, 1, 1);

    UPROPERTY(EditDefaultsOnly, Category = "Capture")
        float Exponent = 1; // 밀도

    UPROPERTY(EditDefaultsOnly, Category = "Capture")
        FVector Scale = FVector::OneVector;

    UPROPERTY(EditDefaultsOnly, Category = "Capture")
        FVector ScaleAmount = FVector::ZeroVector;

private:
    // 캡처
    UPROPERTY(VisibleDefaultsOnly)
        class UPoseableMeshComponent* Mesh;

public:	
	ACGhostTrail();

protected:
	virtual void BeginPlay() override;
    virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

private:
    class ACharacter* Owner;
    class UMaterialInstanceDynamic* Material;

    FTimerHandle TimerHandle;

};
#include "Weapons/AddOns/CGhostTrail.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/PoseableMeshComponent.h"
#include "Components/CapsuleComponent.h"
#include "Materials/MaterialInstanceConstant.h"
#include "Materials/MaterialInstanceDynamic.h"

ACGhostTrail::ACGhostTrail()
{
	// 생성
	CHelpers::CreateComponent<UPoseableMeshComponent>(this, &Mesh, "Mesh");

}

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

	UMaterialInstanceConstant* material;
	CHelpers::GetAssetDynamic<UMaterialInstanceConstant>(&material, "MaterialInstanceConstant'/Game/Materials/M_GhostTrail_Inst.M_GhostTrail_Inst'");

	Material = UMaterialInstanceDynamic::Create(material, this);
	Material->SetVectorParameterValue("Color", Color);
	Material->SetScalarParameterValue("Exponent", Exponent);

	Owner = Cast<ACharacter>(GetOwner());

	Mesh->SetVisibility(false); // 기본적으로 숨기고 플레이할때만 보여주기
	Mesh->SetSkeletalMesh(Owner->GetMesh()->SkeletalMesh); // Mesh를 기준으로 캡처
	Mesh->CopyPoseFromSkeletalComponent(Owner->GetMesh());
	Mesh->SetRelativeScale3D(Scale);

	// Materials는 2개가 나올 것이다 기본 Skel에 있는 머터리얼.
	for (int32 i = 0; i < Owner->GetMesh()->SkeletalMesh->Materials.Num(); i++)
		Mesh->SetMaterial(i, Material);

	FTimerDelegate timerDelegate;
	timerDelegate.BindLambda([=]()
	{
		// 숨겨져 있었다면 toggle로 뒤집어서 켜준다.
		if (Mesh->IsVisible() == false)
			Mesh->ToggleVisibility();

		Mesh->CopyPoseFromSkeletalComponent(Owner->GetMesh());
	});

	// 타이머 활용
	GetWorld()->GetTimerManager().SetTimer(TimerHandle, timerDelegate, Interval, true, StartDelay);

	
}

void ACGhostTrail::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason);

	// 종료됐다면 타이머 끝.
	GetWorld()->GetTimerManager().ClearTimer(TimerHandle);
}

1. 타이머를 사용하여 Ghost 효과가 나오도록 만들어 준다.


#pragma once

#include "CoreMinimal.h"
#include "Weapons/CSubAction.h"
#include "Weapons/CWeaponStructures.h"
#include "CSubAction_Fist.generated.h"

UCLASS(Blueprintable) // BP가 될 수 있도록, 
class U2212_06_API UCSubAction_Fist : public UCSubAction
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, Category = "Add-On")
		TSubclassOf<class ACGhostTrail> GhostTrailClass;

private:
	// 객체 만들면 return 저장하기위해
	class ACGhostTrail* GhostTrail;

};
#include "Weapons/SubActions/CSubAction_Fist.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Components/CMovementComponent.h"
#include "Weapons/CAttachment.h"
#include "Weapons/CDoAction.h"
#include "Weapons/AddOns/CGhostTrail.h"

void UCSubAction_Fist::Pressed()
{
	GhostTrail = CHelpers::Play_GhostTrail(GhostTrailClass, Owner); // 지정한 시간뒤에 플레이 될 것이다.

}

void UCSubAction_Fist::End_SubAction_Implementation()
{
	Super::End_SubAction_Implementation();

	GhostTrail->Destroy();
}

1. Ghost 효과를 지정한 시간에 의해 실행되도록 만들어 준다.


1.  만들어 놓은 Ghost를 클래스로 만들어준다.

1. 색상과 수치를 조절해준다.

1. 만들어 놓은 Ghost를 선택해준다.

1. 머터리얼로 다시 가서 Skeletal Mesh를 체크해준다. Skeletal Mesh애 붙게 만들어준 머터리얼을 쓰겠다는 의미이다.


#include "Weapons/AddOns/CGhostTrail.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/PoseableMeshComponent.h"
#include "Components/CapsuleComponent.h"
#include "Materials/MaterialInstanceConstant.h"
#include "Materials/MaterialInstanceDynamic.h"

ACGhostTrail::ACGhostTrail()
{
	// 생성
	CHelpers::CreateComponent<UPoseableMeshComponent>(this, &Mesh, "Mesh");

}

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

	UMaterialInstanceConstant* material;
	CHelpers::GetAssetDynamic<UMaterialInstanceConstant>(&material, "MaterialInstanceConstant'/Game/Materials/M_GhostTrail_Inst.M_GhostTrail_Inst'");

	Material = UMaterialInstanceDynamic::Create(material, this);
	Material->SetVectorParameterValue("Color", Color);
	Material->SetScalarParameterValue("Exponent", Exponent);

	Owner = Cast<ACharacter>(GetOwner());

	Mesh->SetVisibility(false); // 기본적으로 숨기고 플레이할때만 보여주기
	Mesh->SetSkeletalMesh(Owner->GetMesh()->SkeletalMesh); // Mesh를 기준으로 캡처
	Mesh->CopyPoseFromSkeletalComponent(Owner->GetMesh());
	Mesh->SetRelativeScale3D(Scale);

	// Materials는 2개가 나올 것이다 기본 Skel에 있는 머터리얼.
	for (int32 i = 0; i < Owner->GetMesh()->SkeletalMesh->Materials.Num(); i++)
		Mesh->SetMaterial(i, Material);

	FTimerDelegate timerDelegate;
	timerDelegate.BindLambda([=]()
	{
		// 숨겨져 있었다면 toggle로 뒤집어서 켜준다.
		if (Mesh->IsVisible() == false)
			Mesh->ToggleVisibility();

		// 위치 보정 및 앞을 보도록 만들어주기.
		float height = Owner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
		SetActorLocation(Owner->GetActorLocation() - FVector(ScaleAmount.X, ScaleAmount.Y, height - ScaleAmount.Z));
		SetActorRotation(Owner->GetActorRotation() + FRotator(0, -90, 0));

		Mesh->CopyPoseFromSkeletalComponent(Owner->GetMesh());
	});

	// 타이머 활용
	GetWorld()->GetTimerManager().SetTimer(TimerHandle, timerDelegate, Interval, true, StartDelay);

	
}

void ACGhostTrail::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason);

	// 종료됐다면 타이머 끝.
	GetWorld()->GetTimerManager().ClearTimer(TimerHandle);
}

1. 트레일러가 실행될때, 버그가 하나 생긴다 앞이 아닌 다른곳을 바라보게 되는데 이를 해결할 것이다.

2. 45 ~ 48번째 줄 코드에 보면, 위치 보정값을 정해줘서 자연스럽게 플레이어가 보는 방향으로 나가도록 만들어준다.


https://www.youtube.com/watch?v=PrSHRANC9eI 

 

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

UE4 SubAction Sword Skill Collision, Hammer Init  (0) 2023.06.26
UE4 SubAction Fist, Sword Skill  (0) 2023.06.23
UE4 SubAction Fist, Camera Move  (0) 2023.06.21
UE4 SubAction Fist  (0) 2023.06.20
UE4 SubAction Fist  (0) 2023.06.20
Comments