C++ ときどき ごはん、わりとてぃーぶれいく☆

USAGI.NETWORKのなかのひとのブログ。主にC++。

UE4/C++: USoundWave と USoundCue または何れにせよ USoundBase でいいやのメモ

UE4 プロジェクト内のアセット化された「なにか」を C++ コードの ctor で拾いたい場合には以下のようにする、するのだが…:

#include "Runtime/CoreUObject/Public/UObject/ConstructorHelpers.h"
// どこかの UObject 系の ctor でプロジェクト内のアセットを引っ張り出す(間違い探しアリ😋)
static ConstructorHelpers::FObjectFinder< USoundCue > my_sound ( TEXT( "SoundWave'/Game/BGMs/game_maoudamashii_3_theme01.game_maoudamashii_3_theme01'" ) );

この実装はコンパイル可能で my_sound に対して特に何も実装を加えていなければうっかり見過ごしてしまうかもしれない。しかし、 UE4 のビルドシステムのログにはしっかりとエラーが報告されている。(少なくとも UE4Editor では reload に失敗するのでほぼ確実に気付くと思う。)

Error: CDO Constructor (MyExperimentalActor): Failed to find SoundWave'/Game/BGMs/game_maoudamashii_3_theme01.game_maoudamashii_3_theme01'

game_maoudamashii_3_theme01 はゲーム系フリー音楽素材の配信元としておなじみの 魔王魂 で入手できる。今回はこの .wav/Game/BGMs に入っていなかった落ちではない。

今回の「間違い」は USoundCue として .wav アセットを探すコードになっている事。 .wav アセットは UE4 的には USoundWave なので:

// .wav を放り込んだだけの USoundWave アセットに対する正しい実装例
static ConstructorHelpers::FObjectFinder< USoundWave > my_sound ( TEXT( "SoundWave'/Game/BGMs/game_maoudamashii_3_theme01.game_maoudamashii_3_theme01'" ) );

と、しなければ期待動作しない。これが UE4Editor で放り込んだ .wavコンテキストメニューから Create Cue するなどして USoundCue 化されたアセットを作ってあるのなら:

// USoundCue に対する正しい実装例
static ConstructorHelpers::FObjectFinder< USoundCue> my_sound ( TEXT( "SoundCue'/Game/BGMs/game_maoudamashii_3_theme01_Cue.game_maoudamashii_3_theme01_Cue'" ) );

となる。

なるのだが、実際問題この段階で USoundCueUSoundWave か何れであるかが問題になる事はたぶん無い。面倒だ・w・

そこで、とりあえず区別する必要の無い段階では USoundBase を使っておけばよい。 USoundBaseUSoundCueUSoundWave の何れの基底型でもある:

// USoundCue でも USoundWave でも USoundBase にしておけばどっちでもいいのです
static ConstructorHelpers::FObjectFinder< USoundBase > my_sound_a ( TEXT( "SoundWave'/Game/BGMs/game_maoudamashii_3_theme01.game_maoudamashii_3_theme01'" ) );
static ConstructorHelpers::FObjectFinder< USoundBase > my_sound_b ( TEXT( "SoundCue'/Game/BGMs/game_maoudamashii_3_theme01_Cue.game_maoudamashii_3_theme01_Cue'" ) );

こうして作った USoundBase は「どちらでもいいや」のまま UAudioComponent::SetSound のパラメーターとして与えられる。(そもそも SetSound の第1引数は USoundBase 型。)

// どこかに適当な UAudioComponent が居るとして
auto c = NewObject< UAudioComponent >( this );
c->SetSound( my_sound_a.Object );

USoundCueUSoundWave 、こやつらの違いは必要な事があれば Cast すればいいし、トリアエズナラスダケ!くらいな程度では USoundBase で取り回していても不便ないしね☺

References