초보 코린이의 성장 일지

UE4 HitData, Effect, Sound, HitStop 본문

언리얼

UE4 HitData, Effect, Sound, HitStop

코오린이 2023. 5. 9. 17:11

 

Enemy를 타격했을시 색이 변경되는 것과 알맞은 Hit 동작이 나오도록 만들어 볼 것이다.

더보기

 

#pragma once

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

USTRUCT()
struct FHitData // 액션 구조체
{
	GENERATED_BODY()

public:
	// 에디터에서 세팅은 해야하므로, EditAnywhere.
	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)
		// UFXSystemAsset 파티클, 나이아가라 공통 부모
		class UFXSystemAsset* Effect; // 파티클, 나이아가라 사용하기 위해.

	UPROPERTY(EditAnywhere)
		// 방향 보정치
		FVector EffectLocation = FVector::ZeroVector;

	UPROPERTY(EditAnywhere)
		// 이팩트 크기 보정.
		FVector EffectScale = FVector::OneVector;
};

USTRUCT() // 데미지의 대한 추가 정보 구조체
struct FActionDamageEvent
	: public FDamageEvent
{
	GENERATED_BODY()

public:
	FHitData* HitData;
};

UCLASS()
class U2212_06_API UCWeaponStructures : public UObject
{
	GENERATED_BODY()

};

1. HitData를 가지고 있는 구조체를 생성.

 


더보기
#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "Weapons/CWeaponStructures.h"
#include "CDoAction.generated.h"

UCLASS(Abstract) // 객체화 되면 안되므로 Abstract
class U2212_06_API UCDoAction : public UObject
{
	GENERATED_BODY()
	
public:
	UCDoAction(); // 생성자

	// 재정의 할 수 있도록, BeginPlay를 임의로 만들어놓는다
	virtual void BeginPlay
	(
		class ACAttachment* InAttachment,
		class UCEquipment* InEquipment,
		class ACharacter* InOwner,
		const TArray<FDoActionData>& InDoActionDatas,
		const TArray<FHitData>& InHitDatas // 코드 추가된 부분
	);
    
protected:
	bool bBeginAction; // 액션에 들어갔는지,

	class ACharacter* OwnerCharacter;
	class UWorld* World; // Owner에 World

	class UCMovementComponent* Movement;
	class UCStateComponent* State;

	TArray<FDoActionData> DoActionDatas; // 액션이 여러개 나올수 있으므로 배열,
	TArray<FHitData> HitDatas; // 코드 추가된 부분
};
#include "CEquipment.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Components/CMovementComponent.h"

UCDoAction::UCDoAction()
{

}

// 매개변수 끝에 InHitDatas 추가
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; // 코드 추가된 부분
}

1. 구조체를 받아와서 매개변수를 통해 BeginPlay에 받아준다.


더보기
#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) // 데이터 가져오기
		TArray<FHitData> HitDatas; 
        
public:
	UCWeaponAsset();

	// 외부에서 BeginPlay일때 콜해주기 위해 이름을 알기 쉽도록 만들어줬다.
	void BeginPlay(class ACharacter* InOwner);

};
#include "Weapons/CWeaponAsset.h"
#include "Global.h"
#include "CAttachment.h"
#include "CEquipment.h"
#include "CDoAction.h"
#include "GameFramework/Character.h"

void UCWeaponAsset::BeginPlay(ACharacter * InOwner)
{

	if (!!DoActionClass)
	{
		// DoAction 생성
		DoAction = NewObject<UCDoAction>(this, DoActionClass);
		DoAction->BeginPlay(Attachment, Equipment, InOwner, DoActionDatas, HitDatas); // 추가된 부분

		if (!!Attachment)
		{
			// null이 아니라면, Attachment에 DoAction꺼를 다 연결해준다.
			Attachment->OnAttachmentBeginCollision.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginCollision);
			Attachment->OnAttachmentEndCollision.AddDynamic(DoAction, &UCDoAction::OnAttachmentEndCollision);

			Attachment->OnAttachmentBeginOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginOverlap);
			Attachment->OnAttachmentEndOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentEndOverlap);
		}
	}
}

1. 설정들을 저장해주기 위해 구조체를 받아와서 DoAction 생성 부분에 저장해준다.


더보기
#pragma once

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

USTRUCT()
struct FHitData // 액션 구조체
{
	GENERATED_BODY()

public:
	// 에디터에서 세팅은 해야하므로, EditAnywhere.
	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)
		// UFXSystemAsset 파티클, 나이아가라 공통 부모
		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);
};

USTRUCT() // 데미지의 대한 추가 정보 구조체
struct FActionDamageEvent
	: public FDamageEvent
{
	GENERATED_BODY()

public:
	FHitData* HitData;
};

UCLASS()
class U2212_06_API UCWeaponStructures : public UObject
{
	GENERATED_BODY()

};
#include "Weapons/DoActions/CDoAction_Combo.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"

void UCDoAction_Combo::OnAttachmentBeginOverlap(ACharacter* InAttacker, AActor* InAttackCauser, ACharacter* InOther)
{
	Super::OnAttachmentBeginOverlap(InAttacker, InAttackCauser, InOther);
	CheckNull(InOther);

	////CLog::Log(InOther->GetName());

	//FActionDamageEvent e;
	//e.HitData = &HitDatas[0];

	//InOther->TakeDamage(e.HitData->Power, e, FDamageEvent(), InAttacker->GetController(), InAttackCauser);
	HitDatas[Index].SendDamage(InAttacker, InAttackCauser, InOther);
}

1. 데미지를 줄 수 있게끔 SendDamage를 호출해서 처리해준다.


1. HitDatas에서 설정하고 싶은 데이터들을 넣어준다.


더보기
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Characters/ICharacter.h"
#include "CEnemy.generated.h"

UCLASS()
class U2212_06_API ACEnemy
	: public ACharacter
	, public IICharacter
{
	GENERATED_BODY()

private:
	UFUNCTION()
		void OnStateTypeChanged(EStateType InPrevType, EStateType InNewType);

private:
	void Hitted();
    
private:
	UFUNCTION()
		void RestoreColor();


private:
	struct FDamageData
	{
		float Power;
		class ACharacter* Character;
		class AActor* Causer;

		struct FActionDamageEvent* Event;  // 포인터로 사용하므로 전방선언
	} Damage;
    
private:
	FTimerHandle RestoreColor_TimerHandle;
};
#include "Characters/CEnemy.h"
#include "Global.h"
#include "CAnimInstance.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/CWeaponComponent.h"
#include "Components/CMontagesComponent.h"
#include "Components/CMovementComponent.h"
#include "Weapons/CWeaponStructures.h"

ACEnemy::ACEnemy()
{
	// 아래부분은 Player과 동일하게 가지고 있다.
	// 생성
	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);

	GetCharacterMovement()->RotationRate = FRotator(0, 720, 0);
}

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

	Movement->OnWalk();

	// 색을 세팅해주면서, 시작하면 자신이 설정한 색이 적용된다.
	Create_DynamicMaterial(this);
	Change_Color(this, OriginColor);

	State->OnStateTypeChanged.AddDynamic(this, &ACEnemy::OnStateTypeChanged);
}

void ACEnemy::OnStateTypeChanged(EStateType InPrevType, EStateType InNewType)
{
	switch (InNewType)
	{
	case EStateType::Hitted: Hitted(); break;
	}
}

void ACEnemy::Hitted()
{
	//TODO: 데미지 처리
	//TODO: 사망 처리

	// 맞으면 색 변경
	Change_Color(this, FLinearColor::Red);

	// 데미지 저장
	FTimerDelegate timerDelegate;
	timerDelegate.BindUFunction(this, "RestoreColor");

	GetWorld()->GetTimerManager().SetTimer(RestoreColor_TimerHandle, timerDelegate, 0.2f, false);
}

void ACEnemy::RestoreColor()
{
	// 색 다시 돌려주기
	Change_Color(this, OriginColor);

	// 사용했으면 Clear 해주는게 펜딩킬 안나는 방법
	GetWorld()->GetTimerManager().ClearTimer(RestoreColor_TimerHandle);
}

float ACEnemy::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
	// 부모 콜을 해주고, 부모에서 처리된 데미지를 가지고와서 처리해줘야한다. (서버가 다 부모에 있기 때문)
	float damage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);

	Damage.Power = damage; // 처리된 데미지
	Damage.Character = Cast<ACharacter>(EventInstigator->GetPawn());
	Damage.Causer = DamageCauser;
	Damage.Event = (FActionDamageEvent*)&DamageEvent; // 캐스팅

	State->SetHittedMode();

	return damage;
}

1. Hit되는 대상에 Hit관련된 이벤트를 받아서 처리해줘야한다.

2. 또한 Hit되면 데이터들을 기록해놓고 처리되는 곳에서 처리하게끔 만들것이다. 그래서 내부적으로 구조체를 하나 더 만들어 줄 것이다

3. 데미지 저장을 해준 상태로 이벤트 처리를 하여 색을 변경해줌과 동시에 사용 후 Clear해줌으로써 펜딩킬을 방지한다.


이제 Hit시 몽타주 모션이 나오도록 만들것이다. 그래서 HitData안에 넣어두고 필요할때만 호출해줄 것이다.

더보기
#pragma once

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

public:
	// 데미지에 관련
	void SendDamage(class ACharacter* InAttacker, AActor* InAttackCauser, class ACharacter* InOther);
	void PlayMontage(class ACharacter* InOwner);
	
};

UCLASS()
class U2212_06_API UCWeaponStructures : public UObject
{
	GENERATED_BODY()

};
#include "Weapons/CWeaponStructures.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Components/CMovementComponent.h"
#include "Animation/AnimMontage.h"

void FHitData::SendDamage(ACharacter* InAttacker, AActor* InAttackCauser, ACharacter* InOther)
{
	FActionDamageEvent e;
	e.HitData = this; // HitData 구조체 안에서 선언하므로 자기 자신.

	InOther->TakeDamage(Power, e, InAttacker->GetController(), InAttackCauser);
}

void FHitData::PlayMontage(ACharacter* InOwner)
{
	if (!!Montage)
		InOwner->PlayAnimMontage(Montage, PlayRate);
}

1. Hit시 모션이 나오도록 몽타주를 추가해준다.


더보기
#include "Characters/CEnemy.h"
#include "Global.h"
#include "CAnimInstance.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/CWeaponComponent.h"
#include "Components/CMontagesComponent.h"
#include "Components/CMovementComponent.h"
#include "Weapons/CWeaponStructures.h"

void ACEnemy::Hitted()
{
	//TODO: 데미지 처리
	//TODO: 사망 처리

	// 맞으면 색 변경
	Change_Color(this, FLinearColor::Red);

	// 데미지 저장
	FTimerDelegate timerDelegate;
	timerDelegate.BindUFunction(this, "RestoreColor");

	GetWorld()->GetTimerManager().SetTimer(RestoreColor_TimerHandle, timerDelegate, 0.2f, false);


	if (!!Damage.Event && !!Damage.Event->HitData)
	{
		FHitData* data = Damage.Event->HitData;

		data->PlayMontage(this);
	}
}

1. 몽타주를 Hitted에서 동작 나오도록 호출.

2. 이제 Hit시 몽타주가 나오게된다.


더보기
#pragma once

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

public:
	// 데미지에 관련
	void SendDamage(class ACharacter* InAttacker, AActor* InAttackCauser, class ACharacter* InOther);
	void PlayMontage(class ACharacter* InOwner);
	void PlayHitStop(UWorld* InWorld);
};

UCLASS()
class U2212_06_API UCWeaponStructures : public UObject
{
	GENERATED_BODY()

};
#include "Weapons/CWeaponStructures.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Components/CMovementComponent.h"
#include "Animation/AnimMontage.h"

void FHitData::SendDamage(ACharacter* InAttacker, AActor* InAttackCauser, ACharacter* InOther)
{
	FActionDamageEvent e;
	e.HitData = this; // HitData 구조체 안에서 선언하므로 자기 자신.

	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; // 1로 다시 돌려준다.
		});

	FTimerHandle timerHandle;
	// 사용했으면 다시 제거해준다.
	InWorld->GetTimerManager().SetTimer(timerHandle, timerDelegate, StopTime, false);
}

1. 이제 HIt시 잠시 멈추게 보이는 효과를 만들어 볼 것이다.

더보기
#include "Characters/CEnemy.h"
#include "Global.h"
#include "CAnimInstance.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/CWeaponComponent.h"
#include "Components/CMontagesComponent.h"
#include "Components/CMovementComponent.h"
#include "Weapons/CWeaponStructures.h"

void ACEnemy::Hitted()
{
	//TODO: 데미지 처리
	//TODO: 사망 처리

	// 맞으면 색 변경
	Change_Color(this, FLinearColor::Red);

	// 데미지 저장
	FTimerDelegate timerDelegate;
	timerDelegate.BindUFunction(this, "RestoreColor");

	GetWorld()->GetTimerManager().SetTimer(RestoreColor_TimerHandle, timerDelegate, 0.2f, false);


	if (!!Damage.Event && !!Damage.Event->HitData)
	{
		FHitData* data = Damage.Event->HitData;

		data->PlayMontage(this);
		data->PlayHitStop(GetWorld());
	}
}

1. Enemy로와서 Hit안에 HitStop을 넣어준다.

2. 구조체안에 StopTime 시간을 조율해주면 더 느리게 보이는 효과를 줄 수 있다.


더보기
#pragma once

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

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);
};

UCLASS()
class U2212_06_API UCWeaponStructures : public UObject
{
	GENERATED_BODY()

};
#include "Weapons/CWeaponStructures.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Components/CMovementComponent.h"
#include "Animation/AnimMontage.h"

void FHitData::PlaySoundWave(ACharacter* InOwner)
{
	CheckNull(Sound);

	UWorld* world = InOwner->GetWorld();
	FVector location = InOwner->GetActorLocation();

	UGameplayStatics::SpawnSoundAtLocation(world, Sound, location);
}

1. 사운드도 넣어준다.

더보기
#include "Characters/CEnemy.h"
#include "Global.h"
#include "CAnimInstance.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/CWeaponComponent.h"
#include "Components/CMontagesComponent.h"
#include "Components/CMovementComponent.h"
#include "Weapons/CWeaponStructures.h"

void ACEnemy::Hitted()
{
	//TODO: 데미지 처리
	//TODO: 사망 처리

	// 맞으면 색 변경
	Change_Color(this, FLinearColor::Red);

	// 데미지 저장
	FTimerDelegate timerDelegate;
	timerDelegate.BindUFunction(this, "RestoreColor");

	GetWorld()->GetTimerManager().SetTimer(RestoreColor_TimerHandle, timerDelegate, 0.2f, false);


	if (!!Damage.Event && !!Damage.Event->HitData)
	{
		FHitData* data = Damage.Event->HitData;

		data->PlayMontage(this);
		data->PlayHitStop(GetWorld());
		data->PlaySoundWave(this);
	}

	Damage.Character = nullptr;
	Damage.Causer = nullptr;
	Damage.Event = nullptr;
}

1. Hit시 사운드가 나오도록 처리해주고, 데미지에 필요하여 사용했던 매개변수들을 다시 비워준다.

2. 이제 Hit시 사운드가 나오는걸 알 수 있다.


이제 파티클 및 나이아가라 이펙트가 나오도록 만들어 볼 것이다. 

우선 기본적인 틀부터 만들어 보겠다.

더보기
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");

    }
}

1. Build.cs로가서 Niagara를 넣어준다.

더보기
#pragma once

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

// 파티클과 나이아가라 이펙트 관련하여 모든곳에서 사용할 수 있게끔 선언
	static void PlayEffect(UWorld* InWorld, UFXSystemAsset* InAsset, const FTransform& InTransform, USkeletalMeshComponent* InMesh = nullptr, FName InSocketName = NAME_None)
	{
		// 파티클 or 나이아가라 캐스팅 확인
		UParticleSystem* particle = Cast<UParticleSystem>(InAsset);
		UNiagaraSystem* niagara = Cast<UNiagaraSystem>(InAsset);

		FVector location = InTransform.GetLocation();
		FRotator rotation = FRotator(InTransform.GetRotation());
		FVector scale = InTransform.GetScale3D();

		// Mesh가 있다는건 어딘가 소켓에 붙여서 실행되는 것.
		if (!!InMesh)
		{
			if (!!particle)
			{
				UGameplayStatics::SpawnEmitterAttached(particle, InMesh, InSocketName, location, rotation, scale);

				return;
			}

			if (!!niagara)
			{
				UNiagaraFunctionLibrary::SpawnSystemAttached(niagara, InMesh, InSocketName, location, rotation, scale, EAttachLocation::KeepRelativeOffset, true, ENCPoolMethod::None);

				return;
			}
		}

		// Mesh에 붙는게 아니라면 어떠한 위치에서 생성된다는 것
		if (!!particle)
		{
			UGameplayStatics::SpawnEmitterAtLocation(InWorld, particle, InTransform);

			return;
		}

		if (!!niagara)
		{
			UNiagaraFunctionLibrary::SpawnSystemAtLocation(InWorld, niagara, location, rotation, scale);

			return;
		}
	}

1. 소켓에 붙여서 생성할 것인지, 아니면 어떠한 위치에서 생성할 것인지 체크.

2. 이제 이펙트를 생성시켜주는 코드를 작성하게 될 것이다.

 

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

 

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

UE4 Fist, Camera Shake  (0) 2023.05.11
UE4 Hit Effect, Status Component, Hammer  (2) 2023.05.10
UE4 AnimNotify, ComboState, TakeDamage  (0) 2023.05.08
UE4 Equip, DoAction  (2) 2023.05.04
UE4 Weapon Attach, Sword Equip  (0) 2023.05.01
Comments