본문 바로가기

언리얼 + cpp

언리얼C++ 11일차(파티클, 사운드)

파티클 시각 효과, 사운드 추가

파티클은 게임 내에서 불꽃, 연기, 폭발, 먼지 등 다양한 시각적 효과를 구현하기 위한 시스템이다.

다수의 작은 입자들이 모여 움직이면서 특정한 모양, 색상 혹은 애니메이션 효과를 만들어낸다.

파티클 시스템에는 Cascade와 Niagara 방식이 있는데 아래와 같은 특징이 있다.

  • Cascade vs. Niagara
    • Cascade: 언리얼 엔진 3 시절부터 제공된 오래된 파티클 편집 툴입니다. 언리얼 엔진 4, 5에서도 여전히 호환되지만, 신규 기능 업데이트는 주로 Niagara 위주로 이루어지고 있습니다.
      • 초급자가 배우기에 상대적으로 간단하고 빠르게 결과를 볼 수 있음
      • 레거시 프로젝트나 기존 아티스트 툴체인에서 많이 사용
      • 복잡하거나 고급스러운 VFX 연출에는 한계
    • Niagara: 언리얼 엔진 4 후반부터 새롭게 도입된 차세대 파티클 시스템입니다. 언리얼 엔진 5에서는 Niagara가 공식적으로 권장되는 방식입니다.
      • 모듈 단위로 다양한 파티클 동작을 정교하게 제어 가능
      • 블루프린트머티리얼, 스크립팅과 유기적으로 연동되어 고급 VFX를 쉽게 만들 수 있음
      • GPU 파티클, 신규 기능 업데이트가 빠르게 적용
    • 만약 언리얼 엔진을 처음 접하거나, 파티클 효과를 빠르게 만들어봐야 한다면 Cascade부터 익히는 것도 좋은 방법입니다. 하지만, 새 프로젝트를 계획 중이고 고급 이펙트를 구현하고 싶다면 Niagara 학습을 권장합니다.

이름 앞에 P_ 또는 Niagara_ 와 같은 접두어를 붙여두면, 프로젝트 내에서 파티클 에셋을 쉽게 구분할 수 있다.

 

사운드 시스템에는 Sound Wave와 Sound Cue가 있는데 아래와 같은 특징이 있다.

  • 사운드 웨이브(Sound Wave)
    • 한 개의 오디오 파일(일반적으로 .wav)을 뜻합니다.
    • 게임에서 재생할 기본 오디오 데이터 그 자체라고 볼 수 있습니다.
    • 단일 음원(싱글 트랙) 재생용으로 주로 사용됩니다.
    • 엔진 내부적으로 Wave 탭 또는 사운드 웨이브 에셋으로 관리됩니다.
    • 재생 시 별도의 추가 효과(랜덤 재생, 믹싱, 블렌딩 등)를 넣기 어렵고, 순수히 “오디오 파일”을 재생하기만 하는 형태입니다.
    • 단일 오디오 파일을 그대로 재생하는 경우.
    • 간단한 UI 사운드, 짧은 효과음(단일 음원) 등에 적합.
    •  
  • 사운드 큐 (Sound Cue)
    • 언리얼 엔진의 오디오 편집 그래프 시스템입니다.
    • 여러 개의 사운드 웨이브를 조합하거나, 랜덤/시퀀셜 재생, 믹싱, 페이드, 모듈레이션 등 다양한 처리를 시각적 노드 그래프로 설정할 수 있습니다.
    • Sound Cue Editor라는 전용 편집 창에서 다양한 노드를 배치해 복잡한 사운드 로직을 구성할 수 있습니다.
    • 사운드 에셋이 늘어나고, 상황에 따라 실시간으로 변화하는 사운드를 만들고 싶을 때 필수적입니다.
    • 배경음악의 구간 전환(Intro-Loop-Outro)이라든가, 발걸음 소리의 무작위 재생, 총격 사운드의 재생 피치 랜덤화 같은 동적 사운드에 활용됩니다.
    • 여러 사운드 웨이브조합하거나, 랜덤/페이드/모듈레이션고급 기능을 적용해야 할 때.
    • 같은 이벤트라도 여러 가지 소리를 번갈아 재생하거나, 재생 로직노드 그래프로 구성하고 싶을 때 사용.

아이템을 획득할 때 파티클과 사운드를 적용해서 시각적, 청각적 효과를 구현한다.

모든 아이템은 상호작용 시 BaseItem의 ActivateItem 함수를 실행하도록 설계했으니 이 함수에 파티클과 사운드를 붙이면 모든 아이템에 파티클과 사운드를 설정할 수 있다.

// BaseItem.h
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item|Effects")
	UParticleSystem* PickupParticle;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item|Effects")
	USoundBase* PickupSound;
// BaseItem.cpp
void ABaseItem::ActivateItem(AActor* Activator)
{
	UParticleSystemComponent* Particle = nullptr;
	
	if (PickupParticle)
	{
		Particle = UGameplayStatics::SpawnEmitterAtLocation(
			GetWorld(),
			PickupParticle,
			GetActorLocation(),
			GetActorRotation(),
			true
		);
	}
    
	if (PickupSound)
	{
		UGameplayStatics::PlaySoundAtLocation(
			GetWorld(),
			PickupSound,
			GetActorLocation()
		);
	}
	
	if (Particle)
	{
		FTimerHandle DestroyParticleTimerHandle;

		GetWorld()->GetTimerManager().SetTimer(
			DestroyParticleTimerHandle,
			[Particle]()
			{
				Particle->DestroyComponent();
			},
			4.0f,
			false
		);
	}
}

Particle을 소환하고 타이머핸들을 이용해서 4초 후에 파티클이 Destroy되도록 구현한것이다.

파티클을 붙여줄 아이템 블루프린트에서 파티클 이펙트를 설정해준다.

Coin은 Sound만 설정함
포션
지뢰

지뢰 아이템의 경우 ActivateItem 함수가 Explode 함수를 호출해서 ExplosionDelay초 후에 폭발하도록 구현을 해서 폭발할 때의 사운드와 파티클 또한 추가해줘야한다.

 

C++ MineItem.h에서 파티클시스템과 사운드베이스를 하나씩 추가하고 현재 MineItem에 겹쳐질 때마다 ActivateItem이 계속 호출이 되는 문제가 있는데 이를 한번 호출되면 그 이후는 호출이 안되도록 bool 변수를 추가한다.

// MineItem.h
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item|Effects")
	UParticleSystem* ExplosionParticle;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item|Effects")
	USoundBase* ExplosionSound;
    
	bool bIsExploded;

Explode 함수에서 폭발시 파티클과 사운드를 재생하는 로직을 구현한다.

// MineItem.cpp
	// 생성자
	bIsExploded = false;
    
void AMineItem::ActivateItem(AActor* Activator)
{
	if (bIsExploded) return; // bIsExploded가 true면 바로 함수종료

	Super::ActivateItem(Activator);

	GetWorld()->GetTimerManager().SetTimer(
		ExplosionTimerHandle,
		this,
		&AMineItem::Explode,
		ExplosionDelay,
		false);
	bIsExploded = true; // 한번 호출되면 true로 변경
}

void AMineItem::Explode()
{
	UParticleSystemComponent* Particle = nullptr;
	
	if (ExplosionParticle)
	{
		Particle = UGameplayStatics::SpawnEmitterAtLocation(
			GetWorld(),
			ExplosionParticle,
			GetActorLocation(),
			GetActorRotation(),
			false
		);
	}
    
    if (ExplosionSound)
	{
		UGameplayStatics::PlaySoundAtLocation(
			GetWorld(),
			ExplosionSound,
			GetActorLocation()
		);
	}
    
    if (Particle)
	{
		FTimerHandle DestroyParticleTimerHandle;

		GetWorld()->GetTimerManager().SetTimer(
			DestroyParticleTimerHandle,
			[Particle]()
			{
				Particle->DestroyComponent();
			},
			2.0f,
			false
		);
	}

에디터의 MineItem 블루프린트에서 폭발시 파티클과 사운드를 설정해준다.

  • 이 외 파티클 활용 시 팁
    • 성능 고려
      • 파티클은 반복 생성 시 성능 부하가 커질 수 있습니다.
      • 불필요하게 많은 파티클이 생성되지 않도록 주의합니다.
    • 파티클 라이프타임 (Lifetime) 조정
      • 폭발 파티클 등은 보통 짧은 시간에 끝나도록 Lifetime 설정이 되어 있습니다.
      • 필요에 따라 “Looping” 옵션을 끄거나 켜서 조절할 수 있습니다.
    • 부착(Attach)
      • 아이템이 이동/회전하는 동안 파티클도 함께 움직여야 한다면 SpawnEmitterAttached()를 사용해 부착 대상 컴포넌트를 지정해줘야 합니다.