목차

     

     


     

     

     

     
    Source
        Characters
        CAnimInstance.h .cpp
    CEnemy.h .cpp 

    CPlayer.h .cpp
    ICharacter.h .cpp
        Components
        CMontagesComponent.h .cpp 
    CMovementComponent.h .cpp 
    CStateComponent.h .cpp 
    CWeaponComponent.h .cpp 
        Notifies
        CAnimNotifyState_BeginAction.h .cpp 
    CAnimNotifyState_EndAction.h .cpp
    CAnimNotify_EndState.h .cpp

    CAnimNotifyState_Collision.h .cpp 
    CAnimNotifyState_Combo.h .cpp
    CAnimNotifyState_Equip.h .cpp
        Utilities
        CHelper.h
    CLog.h .cpp
        Weapons
        CDoAction_Combo.h .cpp

    CAttachment.h .cpp
    CDoAction.h .cpp

    CEquipment.h .cpp
    CWeaponAsset.h .cpp

    CWeaponStructures.h .cpp
        Global.h
    CGameMode.h .cpp
    U2212_06.Build.cs
        U2212_06.uproject
     

     

     

     

     

    Hit Data 활용하기

     


     

     

    CWeaponStructure  -  Hit Data 추가하기

     

    CWeaponStructure.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "UObject/NoExportTypes.h"
    #include "CWeaponStructures.generated.h"
    
    USTRUCT()
    struct FEquipmentData
    {
    	GENERATED_BODY()
    
    public:
    	UPROPERTY(EditAnywhere)
    		class UAnimMontage* Montage;
    
    	UPROPERTY(EditAnywhere)
    		float PlayRate = 1;
    
    	UPROPERTY(EditAnywhere)
    		bool bCanMove = true;
    
    	UPROPERTY(EditAnywhere)
    		bool bUseControlRotation = true;
    };
    
    USTRUCT()
    struct FDoActionData
    {
    	GENERATED_BODY()
    
    public:
    	UPROPERTY(EditAnywhere)
    		class UAnimMontage* Montage;
    
    	UPROPERTY(EditAnywhere)
    		float PlayRate = 1;
    
    	UPROPERTY(EditAnywhere)
    		bool bCanMove = true;
    
    	UPROPERTY(EditAnywhere)
    		bool bFixedCamera;
    
    	UPROPERTY(EditAnywhere)
    		class UFXSystemAsset* Effect; //사용할 Effect 변수
    
    	UPROPERTY(EditAnywhere)
    		FVector EffectLocation = FVector::ZeroVector;//(Effect)지정 방향의 보정치.
    
    	UPROPERTY(EditAnywhere)
    		FVector EffectScale = FVector::OneVector;//Effect 크기 기본값 1 설정.
    
    public:
    	void DoAction(class ACharacter* InOwner);
    };
    
    USTRUCT()
    struct FHitData
    {
    	GENERATED_BODY()
    
    	UPROPERTY(EditAnywhere)
    		class UAnimMontage* Montage;
    
    	UPROPERTY(EditAnywhere)
    		float PlayRate = 1;
    
    	UPROPERTY(EditAnywhere)
    		float Power;
    
    	UPROPERTY(EditAnywhere)
    		float Launch = 100;
    
    	UPROPERTY(EditAnywhere)
    		float StopTime;
    
    	UPROPERTY(EditAnywhere)
    		class USoundWave* Sound;
    
    	UPROPERTY(EditAnywhere)
    		class UFXSystemAsset* Effect;
    
    	UPROPERTY(EditAnywhere)
    		FVector EffectLocation = FVector::ZeroVector;
    
    	UPROPERTY(EditAnywhere)
    		FVector EffectScale = FVector::OneVector;
    
    public:
    	void SendDamage(class ACharacter* InAttacker, AActor* InAttackCauser, class ACharacter* InOther);
    	void PlayMontage(class ACharacter* InOwner);
    	void PlayHitStop(UWorld* InWorld);
    	void PlaySoundWave(class ACharacter* InOwner);
    };
    
    USTRUCT()
    struct FActionDamageEvent : public FDamageEvent
    {
    	GENERATED_BODY()
    
    public:
    	FHitData* HitData;
    };
    
    
    UCLASS()
    class U2212_06_API UCWeaponStructures : public UObject
    {
    	GENERATED_BODY()
    	
    };

    FHitData 구조체 추가

    • 구조체 내에 변수 추가
      • class UAnimMontage* Montage;
      • float PlayRate = 1;
      • float Power;
      • float Launch = 100;
      • float StopTime;
      • class USoundWave* Sound;
      • class UFXSystemAsset* Effect;
      • FVector EffectLocation = FVector::ZeroVector;
      • FVector EffectScale = FVector::OneVector;
    • 함수 추가
      • void SendDamage(class ACharacter* InAttacker, AActor* InAttackCauser, class ACharacter* InOther);
      • void PlayMontage(class ACharacter* InOwner);
      • void PlayHitStop(UWorld* InWorld);
      • void PlaySoundWave(class ACharacter* InOwner);

     

     

     

    CWeaponStructure.cpp

    더보기
    #include "Weapons/CWeaponStructures.h"
    #include "Global.h"
    #include "GameFramework/Character.h"
    #include "Components/CStateComponent.h"
    #include "Components/CMovementComponent.h"
    #include "Animation/AnimMontage.h"
    
    void FDoActionData::DoAction(ACharacter* InOwner)
    {
    	UCMovementComponent* movement = CHelpers::GetComponent<UCMovementComponent>(InOwner);
    
    	if (!!movement)
    	{
    		if (bFixedCamera)
    			movement->EnableFixedCamera();
    
    		if (bCanMove == false)
    			movement->Stop();
    	}
    
    	if (!!Montage)
    		InOwner->PlayAnimMontage(Montage, PlayRate);
    }
    
    void FHitData::SendDamage(ACharacter* InAttacker, AActor* InAttackCauser, ACharacter* InOther)
    {
    	FActionDamageEvent e;
    	e.HitData = this;
    
    	InOther->TakeDamage(Power, e, InAttacker->GetController(), InAttackCauser);
    
    }
    
    void FHitData::PlayMontage(ACharacter* InOwner)
    {
    	if (!!Montage)
    		InOwner->PlayAnimMontage(Montage, PlayRate);
    }
    
    void FHitData::PlayHitStop(UWorld* InWorld)
    {
    	CheckTrue(FMath::IsNearlyZero(StopTime));
    
    	TArray<ACharacter*> characters;
    	for(AActor* actor : InWorld->GetCurrentLevel()->Actors)
    	{
    		ACharacter* character = Cast<ACharacter>(actor);
    
    		if(!!character)
    		{
    			character->CustomTimeDilation = 1e-3f;
    
    			characters.Add(character);
    		}
    	}
    
    	//익명 메소드 //람다 클로저
    	//람다는 외부에서 닫힌 상태로 실행되는 객체
    	FTimerDelegate timerDelegate;
    	timerDelegate.BindLambda([=]()
    		{
    			for (ACharacter* character : characters)
    				character->CustomTimeDilation = 1;
    		});
    
    	FTimerHandle timerHandle;
    	InWorld->GetTimerManager().SetTimer(timerHandle, timerDelegate, StopTime, false);
    }
    
    void FHitData::PlaySoundWave(ACharacter* InOwner)
    {
    	CheckNull(Sound);
    
    	UWorld* world = InOwner->GetWorld();
    	FVector location = InOwner->GetActorLocation();
    
    	UGameplayStatics::SpawnSoundAtLocation(world, Sound, location);
    }

    FHitData 구조체

    • 함수 정의
      • void FHitData::SendDamage(ACharacter* InAttacker, AActor* InAttackCauser, ACharacter* InOther)
      • void FHitData::PlayMontage(ACharacter* InOwner)
      • void FHitData::PlayHitStop(UWorld* InWorld)
      • void FHitData::PlaySoundWave(ACharacter* InOwner)

     

     

     


     

    CWeaponAsset

     

    CWeaponAsset.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Engine/DataAsset.h"
    #include "Weapons/CWeaponStructures.h"
    #include "CWeaponAsset.generated.h"
    
    UCLASS()
    class U2212_06_API UCWeaponAsset : public UDataAsset
    {
    	GENERATED_BODY()
    
    private:
    	UPROPERTY(EditAnywhere)
    		TSubclassOf<class ACAttachment> AttachmentClass;
    
    	UPROPERTY(EditAnywhere)
    		FEquipmentData EquipmentData;
    
    	UPROPERTY(EditAnywhere)
    		TSubclassOf<class UCEquipment> EquipmentClass;
    
    	UPROPERTY(EditAnywhere)
    		TSubclassOf<class UCDoAction> DoActionClass;
    
    	UPROPERTY(EditAnywhere)
    		TArray<FDoActionData> DoActionDatas; //CWeaopnStructure내의 FDoActionData
    
    	UPROPERTY(EditAnywhere)
    		TArray<FHitData> HitDatas; //CWeaopnStructure내의 FHitData
    
    public:
    	FORCEINLINE class ACAttachment* GetAttachment() { return Attachment; }//외부에 생성된 것을 리턴해줌. 
    	FORCEINLINE class UCEquipment* GetEquipment() { return Equipment; }//외부에 생성된 것을 리턴해줌.
    	FORCEINLINE class UCDoAction* GetDoAction() { return DoAction; }//외부에 생성된 것을 리턴해줌.
    
    public:
    	UCWeaponAsset();
    
    	void BeginPlay(class ACharacter* InOwner);
    
    private:
    	//UPROPERTY를 붙여 가비지 콜렉터가 제거하기 전까지 물고 있게 만든다.
    	//UWeaponAsset은 UObject로부터 상속받아 Actor의 생성주기에 영향을 받지 않아 가비지 콜렉터에 영향을 받는다.
    	UPROPERTY() 
    		class ACAttachment* Attachment;
    
    	UPROPERTY()
    		class UCEquipment* Equipment;
    
    	UPROPERTY()
    		class UCDoAction* DoAction;
    };

    변수 추가

    • TArray<FHitData> HitDatas

     

     

     

    CWeaponAsset.cpp

    더보기
    #include "Weapons/CWeaponAsset.h"
    #include "Global.h"
    #include "CAttachment.h"
    #include "CEquipment.h"
    #include "CDoAction.h"
    #include "GameFramework/Character.h"
    
    UCWeaponAsset::UCWeaponAsset()
    {
    	AttachmentClass = ACAttachment::StaticClass();//기본값
    	EquipmentClass = UCEquipment::StaticClass();//기본값
    	DoActionClass = UCDoAction::StaticClass();//기본값
    }
    
    void UCWeaponAsset::BeginPlay(ACharacter* InOwner)
    {
    	if (!!AttachmentClass)//AttachmentClass가 선택되어 있다면
    	{
    		FActorSpawnParameters params;
    		params.Owner = InOwner;
    
    		Attachment = InOwner->GetWorld()->SpawnActor<ACAttachment>(AttachmentClass, params);
    	}
    
    	if (!!EquipmentClass)//EquipmentClass가 선택되어 있다면
    	{
    		Equipment = NewObject<UCEquipment>(this, EquipmentClass);
    		Equipment->BeginPlay(InOwner, EquipmentData);
    
    		if (!!Attachment)//Attachment가 있다면
    		{
    			Equipment->OnEquipmentBeginEquip.AddDynamic(Attachment, &ACAttachment::OnBeginEquip);
    			Equipment->OnEquipmentUnequip.AddDynamic(Attachment, &ACAttachment::OnUnequip);
    		}
    	}
    	 
    	if(!!DoActionClass)
    	{
    		DoAction = NewObject<UCDoAction>(this, DoActionClass);
    		DoAction->BeginPlay(Attachment, Equipment, InOwner, DoActionDatas, HitDatas);
    
    		if (!!Attachment)
    		{
    			Attachment->OnAttachmentBeginCollision.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginCollision);
    			Attachment->OnAttachmentEndCollision.AddDynamic(DoAction, &UCDoAction::OnAttachmentEndCollision);
    
    			Attachment->OnAttachmentBeginOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginOverlap);
    			Attachment->OnAttachmentEndOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentEndOverlap);
    		}
    	}
    }

    DoAction->BeginPlay 호출 시 HitDatas도 같이 넘겨준다. 

    • if ( !!DoActionClass )  {
      DoAction = NewObject<UCDoAction>(this, DoActionClass);
      DoAction->BeginPlay(Attachment, Equipment, InOwner, DoActionDatas, HitDatas); }

     

     


     

     

    CDoAction

     

    CDoAction.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "UObject/NoExportTypes.h"
    #include "Weapons/CWeaponStructures.h"
    #include "CDoAction.generated.h"
    
    UCLASS(Abstract)//DoAction 그 자체로는 객체화되면 안 되기 때문에 Abstract을 붙여준다.
    class U2212_06_API UCDoAction : public UObject
    {
    	GENERATED_BODY()
    
    public:
    	UCDoAction();
    
    	virtual void BeginPlay //재정의 할 수 있도록 virtual로 만든다.
    	(
    		class ACAttachment* InAttachment,
    		class UCEquipment* InEquipment,
    		class ACharacter* InOwner,
    		const TArray<FDoActionData>& InDoActionDatas,//CWeaponStucture내의 FDoActionData 
    		const TArray<FHitData>& InHitDatas //CWeaponStucture내의 FHitData
    	);
    
    public:
    	//재정의 할 수 있도록 virtual로 만든다.
    	virtual void DoAction();
    	virtual void Begin_DoAction();
    	virtual void End_DoAction();
    
    public:
    	UFUNCTION()
    		virtual void OnAttachmentBeginCollision() {}
    
    	UFUNCTION()
    		virtual void OnAttachmentEndCollision() {}
    
    	UFUNCTION()
    		virtual void OnAttachmentBeginOverlap(class ACharacter* InAttacker, AActor* InAttackCauser, class ACharacter* InOther) { }
    
    	UFUNCTION()
    		virtual void OnAttachmentEndOverlap(class ACharacter* InAttacker, class ACharacter* InOther) { }
    
    protected:
    	bool bBeginAction;
    
    	class ACharacter* OwnerCharacter;
    	class UWorld* World;
    
    	class UCMovementComponent* Movement;
    	class UCStateComponent* State;
    
    	TArray<FDoActionData> DoActionDatas;
    	TArray<FHitData> HitDatas;
    };

     

     

     

    CDoAction.cpp

    더보기
    #include "Weapons/CDoAction.h"
    #include "Global.h"
    #include "CAttachment.h"
    #include "CEquipment.h"
    #include "GameFramework/Character.h"
    #include "Components/CStateComponent.h"
    #include "Components/CMovementComponent.h"
    
    UCDoAction::UCDoAction()
    {
    }
    
    void UCDoAction::BeginPlay(ACAttachment* InAttachment, UCEquipment* InEquipment, ACharacter* InOwner, const TArray<FDoActionData>& InDoActionDatas, const TArray<FHitData>& InHitDatas)
    {
    	OwnerCharacter = InOwner;
    	World = OwnerCharacter->GetWorld();
    
    	State = CHelpers::GetComponent<UCStateComponent>(OwnerCharacter);
    	Movement = CHelpers::GetComponent<UCMovementComponent>(OwnerCharacter);
    
    	DoActionDatas = InDoActionDatas;
    	HitDatas = InHitDatas;
    }
    
    void UCDoAction::DoAction()
    {
    	State->SetActionMode();
    }
    
    void UCDoAction::Begin_DoAction()
    {
    	bBeginAction = true;
    }
    
    void UCDoAction::End_DoAction()
    {
    	bBeginAction = false;
    
    	State->SetIdleMode();
    
    	Movement->Move();
    	Movement->DisableFixedCamera();
    }

     


     

    CDoAction_Combo

     

    CDoAction_Combo.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Weapons/CDoAction.h"
    #include "CDoAction_Combo.generated.h"
    
    UCLASS()
    class U2212_06_API UCDoAction_Combo : public UCDoAction
    {
    	GENERATED_BODY()
    
    public:
    	FORCEINLINE void EnableCombo() { bEnable = true; }
    	FORCEINLINE void DisableCombo() { bEnable = false; }
    
    public:
    	void DoAction() override;
    	void Begin_DoAction() override;
    	void End_DoAction() override;
    
    public:
    	void OnAttachmentBeginOverlap(class ACharacter* InAttacker, AActor* InAttackCauser, class ACharacter* InOther) override;
    
    private:
    	int32 Index;
    
    	bool bEnable;
    	bool bExist;
    };

    변경사항 없음

     

     

     

    CDoAction_Combo.cpp

    더보기
    #include "Weapons/DoActions/CDoAction_Combo.h"
    #include "Global.h"
    #include "GameFramework/Character.h"
    #include "Components/CStateComponent.h"
    
    void UCDoAction_Combo::DoAction()
    {
    	CheckTrue(DoActionDatas.Num() < 1);
    
    	if (bEnable) //bEnable이라면 Combo 구간
    	{
    		bEnable = false;
    		bExist = true;
    
    		return;
    	}
    
    	CheckFalse(State->IsIdleMode());
    
    	Super::DoAction(); //첫 타격이 들어간 후에 Combo의 bEnable이 호출되어야 한다. 그래서 맨 위가 아닌 여기에 위치한다.//첫 타격 시 IsIdleMode()를 체크 통과한 후 부모의 DoAction으로 들어가 State->ActionMode()로 변경한다.
    	DoActionDatas[Index].DoAction(OwnerCharacter);
    }
    
    void UCDoAction_Combo::Begin_DoAction()
    {
    	Super::Begin_DoAction();
    	CheckFalse(bExist);//다음 Combo가 없으면 바로 End_DoAction으로 이동.
    
    	bExist = false;
    	DoActionDatas[++Index].DoAction(OwnerCharacter);
    }
    
    void UCDoAction_Combo::End_DoAction()
    {
    	Super::End_DoAction();
    
    	Index = 0;
    }
    
    void UCDoAction_Combo::OnAttachmentBeginOverlap(ACharacter* InAttacker, AActor* InAttackCauser, ACharacter* InOther)
    {
    	Super::OnAttachmentBeginOverlap(InAttacker, InAttackCauser, InOther);//CDoAction.h의 OnAttachmentBeginOverlap
    	CheckNull(InOther);
    
    	FActionDamageEvent e;
    	e.HitData = &HitDatas[0];
    
    	//TakeDamage 체크용 디버그
    	//CLog::Log(InOther->GetName());
    	//InOther->TakeDamage(20, FDamageEvent(), InAttacker->GetController(), InAttackCauser);//데미지 적용.
    	//InOther->TakeDamage(e.HitData->Power, e, InAttacker->GetController(), InAttackCauser);//업캐스팅. 업캐스팅은 항상 성립한다.
    	HitDatas[Index].SendDamage(InAttacker, InAttackCauser, InOther);
    }

    OnAttachment BeginOverlap 수정

     


     

     

     

    실행화면

     

     


     

     

     

     

    Effect 추가하기

     

     


     

    U2212_06.Build.cs

     

    U2212_06.Build.cs

    더보기
    using UnrealBuildTool;
    
    public class U2212_06 : ModuleRules
    {
    	public U2212_06(ReadOnlyTargetRules Target) : base(Target)
    	{
            PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
    
    		PublicIncludePaths.Add(ModuleDirectory);
    
    
            PublicDependencyModuleNames.Add("Core");
    
            PrivateDependencyModuleNames.Add("CoreUObject");
            PrivateDependencyModuleNames.Add("Engine");
            PrivateDependencyModuleNames.Add("InputCore");
            PrivateDependencyModuleNames.Add("Niagara");
        }
    }

    PrivateDependencyModuleNames 추가

    • PrivateDependencyModuleNames.Add("Niagara");
      • Niagara 파티클을 사용하기 위해 추가하였다.

     

     

    CHelpers.h

     

    CHelpers.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Particles/ParticleSystem.h"
    #include "NiagaraSystem.h"
    #include "NiagaraFunctionLibrary.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:
    	template<typename T>
    	static void CreateComponent(AActor* InActor, T** OutComponent, FName InName, USceneComponent* InParent = nullptr, FName InSocketName = NAME_None)
    	{
    		*OutComponent = InActor->CreateDefaultSubobject<T>(InName);
    
    		if (!!InParent)
    		{
    			(*OutComponent)->SetupAttachment(InParent, InSocketName); //이렇게 사용하면 Socket Name에 _를 사용하면 안 된다.
    
    			return;
    		}
    
    		InActor->SetRootComponent(*OutComponent);
    	}
    
    	//CreateActorComponent 추가
    	template<typename T>
    	static void CreateActorComponent(AActor* InActor, T** OutComponent, FName InName)
    	{
    		*OutComponent = InActor->CreateDefaultSubobject<T>(InName);
    	}
    
    	template<typename T>
    	static void GetAsset(T** OutObject, FString InPath)
    	{
    		ConstructorHelpers::FObjectFinder<T> asset(*InPath);
    		*OutObject = asset.Object;
    	}
    
    	template<typename T>
    	static void GetAssetDynamic(T** OutObject, FString InPath)
    	{
    		*OutObject = Cast<T>(StaticLoadObject(T::StaticClass(), nullptr, *InPath));
    	}
    
    	template<typename T>
    	static void GetClass(TSubclassOf<T>* OutClass, FString InPath)
    	{
    		ConstructorHelpers::FClassFinder<T> asset(*InPath);
    		*OutClass = asset.Class;
    	}
    
    	template<typename T>
    	static T* FindActor(UWorld* InWorld)
    	{
    		for (AActor* actor : InWorld->GetCurrentLevel()->Actors)
    		{
    			if (!!actor && actor->IsA<T>())
    				return Cast<T>(actor);
    		}
    
    		return nullptr;
    	}
    
    	template<typename T>
    	static void FindActors(UWorld* InWorld, TArray<T*>& OutActors)
    	{
    		for (AActor* actor : InWorld->GetCurrentLevel()->Actors)
    		{
    			if (!!actor && actor->IsA<T>())
    				OutActors.Add(Cast<T>(actor));
    		}
    	}
    
    	template<typename T>
    	static T* GetComponent(AActor* InActor)
    	{
    		return Cast<T>(InActor->GetComponentByClass(T::StaticClass()));
    	}
    
    	template<typename T>
    	static T* GetComponent(AActor* InActor, const FString& InName)
    	{
    		TArray<T*> components;
    		InActor->GetComponents<T>(components);
    
    		for (T* component : components)
    		{
    			if (component->GetName() == InName)
    				return component;
    		}
    
    		return nullptr;
    	}
    
    	static void AttachTo(AActor* InActor, USceneComponent* InParent, FName InSocketName)
    	{
    		InActor->AttachToComponent(InParent, FAttachmentTransformRules(EAttachmentRule::KeepRelative, true), InSocketName);
    	}
    
    	static void PlayEffect(UWorld* InWorld, UFXSystemAsset* InAsset, const FTransform& InTransform, USkeletalMeshComponent* InMesh = nullptr, FName InSocketName = NAME_None)
    	{
    		UParticleSystem* particle = Cast<UParticleSystem>(InAsset);
    		UNiagaraSystem* niagara = Cast<UNiagaraSystem>(InAsset);
    
    		FVector location = InTransform.GetLocation();
    		FRotator rotation = FRotator(InTransform.GetRotation());
    		FVector scale = InTransform.GetScale3D();
    
    		if(!!InMesh) //InMesh에 붙어있다면
    		{
    			if(!!particle) //particle이라면
    			{
    				UGameplayStatics::SpawnEmitterAttached(particle, InMesh, InSocketName, location, rotation, scale);
    				return;
    			}
    
    			if(!!niagara) //niagara라면
    			{
    				UNiagaraFunctionLibrary::SpawnSystemAttached(niagara, InMesh, InSocketName, location, rotation, scale, EAttachLocation::KeepRelativeOffset, true, ENCPoolMethod::None);//Pooling풀링 사용.
    				return;
    			}
    		}
    
    		if(!!particle) //어디에 붙어있지 않고 particle이면
    		{
    			UGameplayStatics::SpawnEmitterAtLocation(InWorld, particle, InTransform);//해당 위치에서 실행
    
    			return;
    		}
    
    		if (!!niagara) //어디에 붙어있지 않고 niagara면
    		{
    			UNiagaraFunctionLibrary::SpawnSystemAtLocation(InWorld, niagara, location, rotation, scale);//해당 위치에서 실행
    
    			return;
    		}
    	}
    };

    헤더 추가

    • #include "Particles/ParticleSystem.h"
    • #include "NiagaraSystem.h"
    • #include "NiagaraFunctionLibrary.h"

    Effect 추가

    • static void PlayEffect(UWorld* InWorld, UFXSystemAsset* InAsset, const FTransform& InTransform, USkeletalMeshComponent* InMesh = nullptr, FName InSocketName = NAME_None)

     

     


     

    오브젝트 풀링 (Object Pooling)

     

    필요한만큼 미리 생성해서 필요할 때 꺼내 사용한다. 배열보다 vector를 사용하는게 좋다. vector가 수정하기도 체크하기도 더 낫다. 속도 차이는 없다고봐도 무방하다.

     

    장점: 메모리 단편화를 방지할 수 있다.

    단점: 처음에 메모리 구간이 많이 소요될 수 있다.