언리얼 5

230906 Effect_Base 구조 변경 / EffectMgr 싱글톤 / 투사체 생성

슬뷔 2023. 9. 11. 00:35

Effect_Base 구조 변경 -> DataAsset 활용 DA_Effect

1. EffectDataAsset.h / EffectDataAsset.cpp 제작

#include "../Header/global.h"

#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "EffectDataAsset.generated.h"

/**
 * 
 */
UCLASS()
class UNREAL_3TH_API UEffectDataAsset : public UDataAsset
{
	GENERATED_BODY()
	
public:
	UPROPERTY(EditDefaultsOnly, Category = "Effect", meta = (DisplayName = "Effect 와 파티클 세팅"))
	TArray<FEffectData>							EffectDataArr;
};

2. Effect_Base.h 추가 목록

#include "../Header/global.h"
#include "Particles/ParticleSystemComponent.h"
#include "NiagaraComponent.h"
#include "../System/EffectDataAsset.h"

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

UCLASS()
class UNREAL_3TH_API AEffect_Base : public AActor
{
	GENERATED_BODY()
public:	
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Component")
	USceneComponent*					m_Root;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Component")
	UParticleSystemComponent*				m_PSC;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Component")
	UNiagaraComponent*					m_NC;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Component")
	EEFFECT_TYPE						Type;

	UPROPERTY(EditAnywhere, Category = "Info")
	TSoftObjectPtr<UEffectDataAsset>			EffectSetting;


public:
	void SetEffectType(EEFFECT_TYPE _Type) { Type = _Type; }

	UFUNCTION()
	void OnFinished(UParticleSystemComponent* _PSC);



public:	
	// Sets default values for this actor's properties
	AEffect_Base();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

};

3. Effect_Base.cpp 추가 목록

#include "Effect_Base.h"


// Sets default values
AEffect_Base::AEffect_Base()
	: Type(EEFFECT_TYPE::NONE)
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	m_Root = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
	SetRootComponent(m_Root);

	m_PSC = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("ParticleSystemComponent"));	
	m_PSC->SetupAttachment(m_Root);

	m_NC = CreateDefaultSubobject<UNiagaraComponent>(TEXT("NiagaraComponent"));
	m_NC->SetupAttachment(m_Root);
}

// Called when the game starts or when spawned
void AEffect_Base::BeginPlay()
{
	Super::BeginPlay();

	UEffectDataAsset* DataAsset = EffectSetting.LoadSynchronous();

	if (IsValid(DataAsset))
	{
		for (int32 i = 0; i < DataAsset->EffectDataArr.Num(); ++i)
		{
			if (Type == DataAsset->EffectDataArr[i].Type)
			{
				if (!DataAsset->EffectDataArr[i].Particle.IsNull())
				{
					UParticleSystem* Particle = DataAsset->EffectDataArr[i].Particle.LoadSynchronous();

					m_PSC->SetTemplate(Particle);
					m_PSC->OnSystemFinished.AddDynamic(this, &AEffect_Base::OnFinished);
				}

				if (!DataAsset->EffectDataArr[i].Niagara.IsNull())
				{
					UNiagaraSystem* pNiagaraSystem = DataAsset->EffectDataArr[i].Niagara.LoadSynchronous();
					m_NC->SetAsset(pNiagaraSystem);
				}
				return;
			}
		}
	}

	

	Destroy();
}

// Called every frame
void AEffect_Base::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	// 나이아가라 컴포넌트가 재생중인 에셋(나이아가라 시스템) 이 있고, 재생이 완료되었다면
	if (m_NC->GetAsset() && m_NC->IsComplete())
	{
		Destroy();
	}
}

void AEffect_Base::OnFinished(UParticleSystemComponent* _PSC)
{
	LOG(LogTemp, Warning, TEXT("ParticleSystem Finished"));
	Destroy();
}

4. DA_Effect 제작

캐릭터 Finish Spawning 추가

 

EffectMgr 싱글톤 

1. EffectMgr.h 생성

#include "../Header/global.h"

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "EffectMgr.generated.h"


UCLASS()
class UNREAL_3TH_API UEffectMgr : public UObject
{
	GENERATED_BODY()
	
private:
	static UWorld*	g_CurWorld;

public:	
	static UEffectMgr* GetInst(UWorld* _CurWorld);

	UFUNCTION(BlueprintCallable)
	static UEffectMgr* GetInst(AGameModeBase* _GameMode);

	UFUNCTION(BlueprintCallable)
	void CreateEffect(EEFFECT_TYPE _Type, ULevel* _Level, FVector _Location);
	
};

2. EffectMgr.cpp 생성

#include "EffectMgr.h"

#include "../Unreal_3thGameModeBase.h"

#include "Effect_Base.h"

UWorld* UEffectMgr::g_CurWorld = nullptr;

UEffectMgr* UEffectMgr::GetInst(UWorld* _CurWorld)
{
	AUnreal_3thGameModeBase* pGameMode = Cast<AUnreal_3thGameModeBase>(UGameplayStatics::GetGameMode(_CurWorld));

	if (nullptr == pGameMode)
		return nullptr;

	if (IsValid(pGameMode->m_EffectMgr))
	{
		return pGameMode->m_EffectMgr;
	}

	g_CurWorld = _CurWorld;

	pGameMode->m_EffectMgr = NewObject<UEffectMgr>();
	pGameMode->m_EffectMgr->AddToRoot();

	return pGameMode->m_EffectMgr;
}

UEffectMgr* UEffectMgr::GetInst(AGameModeBase* _GameMode)
{
	return GetInst(_GameMode->GetWorld());
}

void UEffectMgr::CreateEffect(EEFFECT_TYPE _Type, ULevel* _Level, FVector _Location)
{
	FActorSpawnParameters param = {};
	param.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
	param.OverrideLevel = _Level;
	param.bDeferConstruction = true;	// 지연생성(BeginPlay 호출 X)
		
	FTransform trans;
	trans.SetLocation(_Location);

	AEffect_Base* pEffect = g_CurWorld->SpawnActor<AEffect_Base>(AEffect_Base::StaticClass(), trans, param);
	pEffect->SetEffectType(_Type);
	pEffect->FinishSpawning(pEffect->GetTransform());
}

투사체 생성 

1. Character_Base 에 CreateProjectile 함수 생성

void ACharacter_Base::CreateProjectile()
{
	FActorSpawnParameters param = {};
	param.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
	param.OverrideLevel = GetLevel();
	param.bDeferConstruction = false;	// 지연생성(BeginPlay 호출 X)

	FTransform trans;	
	trans.SetLocation(GetActorLocation() + GetActorForwardVector() * 100.f);

	AProjectile* pProjectile = GetWorld()->SpawnActor<AProjectile>(m_Projectile, trans, param);
	pProjectile->m_ProjtileMovement->Velocity = GetActorForwardVector() * 500.f;
}

2. Projectile.h 생성

#include "../Header/global.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "NiagaraComponent.h"

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

UCLASS()
class UNREAL_3TH_API AProjectile : public AActor
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Comopnent")
	USphereComponent*				m_Sphere;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Comopnent")
	UProjectileMovementComponent*			m_ProjtileMovement;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Component")
	UParticleSystemComponent*			m_PSC;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Component")
	UNiagaraComponent*				m_NC;

public:	
	// Sets default values for this actor's properties
	AProjectile();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

};

3. Projectile.cpp 생성

#include "Projectile.h"

// Sets default values
AProjectile::AProjectile()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	// SceneComponent 종류인 스피어 컴포넌트, 파티클 시스템 컴포넌트, 나이아가라 컴포넌트 생성 및 액터에 추가
	m_Sphere = CreateDefaultSubobject<USphereComponent>(TEXT("Sphere"));	
	m_PSC = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("ParticleSystem"));
	m_NC = CreateDefaultSubobject<UNiagaraComponent>(TEXT("Niagara"));

	// 액터 컴포넌트인 투사체 무브 컴포넌트 추가
	m_ProjtileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileMovement"));

	// SceneComponent 간의 계층관계구조 설정
	// 구 충돌체 컴포넌트가 최상위 루트, 그 밑에 자식으로 PSC, Niagara 추가
	SetRootComponent(m_Sphere);		
	m_PSC->SetupAttachment(m_Sphere);
	m_NC->SetupAttachment(m_Sphere);
}

// Called when the game starts or when spawned
void AProjectile::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AProjectile::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

4. BPC_Bullet 생성

(1) PSC ( Particle System Component )

(2) NC ( Niagara Component )

결과물