ゲーム開発
Unity
UnrealEngine
C++
ゲーム数学
ゲームAI
サウンド
アニメーション
GBDK
制作日記
3DCG
Houdini
Blender
USD
グラフィックス
テクノロジ
ツール開発
フロントエンド関連
サーバサイド関連
ソフトウェア設計
ハードウェア関連
おすすめ技術書
音楽
DTM
楽器・機材
ピアノ
その他
都会のエレキベア
ラーメン日記
四コマ漫画
おすすめアイテム
おもしろコラム
  • ゲーム開発
    • Unity
    • UnrealEngine
    • C++
    • ゲーム数学
    • ゲームAI
    • サウンド
    • アニメーション
    • GBDK
    • 制作日記
  • 3DCG
    • Houdini
    • Blender
    • USD
    • グラフィックス
  • テクノロジ
    • ツール開発
    • フロントエンド関連
    • サーバサイド関連
    • ソフトウェア設計
    • ハードウェア関連
    • おすすめ技術書
  • 音楽
    • DTM
    • 楽器・機材
    • ピアノ
  • その他
    • 都会のエレキベア
    • ラーメン日記
    • 四コマ漫画
    • おすすめアイテム
    • おもしろコラム
  1. ホーム
  2. 20240519_03_ue5_cpp_ui_effect

【UE5】第三回 ミニゲーム制作で学ぶUnrealC++ 〜UI・仕上げ実装 編〜

UnrealEngineC++制作日記ミニゲームUE5
2024-05-18

マイケル
マイケル
みなさんこんにちは! マイケルです!
エレキベア
エレキベア
こんにちクマ〜〜〜
マイケル
マイケル
「ミニゲームの制作過程を通してUnrealC++で開発する際の方法をざっくり知ろう」という趣旨で、全三回に分けてUnrealEngineでのミニゲーム制作について紹介しています。 前回はキャラクター制御とゲーム内容の実装について紹介したので、今回は仕上げとして味付けを行います!
【UE5】第一回 ミニゲーム制作で学ぶUnrealC++ 〜UnrealC++の概要 編〜
2024-05-18
【UE5】第二回 ミニゲーム制作で学ぶUnrealC++ 〜キャラクター・ゲーム実装 編〜
2024-05-18

▲前回の記事


▲制作したゲーム
エレキベア
エレキベア
猫のランゲームについて制作したのだったクマね
マイケル
マイケル
今回は仕上げとして ・UIの実装 ・タイトル画面の作成とレベル遷移 ・サウンド、エフェクト実装 について紹介していきます。 コードは下記リポジトリにあげていますので、こちらもよければ合わせてご参照ください!

▼GitHubリポジトリ
GitHub - plasmo310 / ue5-cat-runner

▼UnrealEngineバージョン
5.3.2

エレキベア
エレキベア
やったるクマ〜〜〜

参考書籍

マイケル
マイケル
今回実装・情報整理するにあたり、下記書籍を参考にさせていただきました!

C++でつくるUnreal Engineアプリ開発 for Windows & ...

Unreal Engine 5で極めるゲーム開発:サンプルデータと動画で学ぶゲー...

マイケル
マイケル
C++でつくるUnreal Engineアプリ開発は、UE4の情報にはなりますが数少ないC++について触れられた書籍です。 Unreal Engine 5で極めるゲーム開発は通称極め本と呼ばれていて、業界内では定番書籍として扱われています。 量はありますが、一度見ておいて損はないと思います!
エレキベア
エレキベア
極め本はUE4版もあったクマが、UE5になってまたボリュームが大きくなったクマね

UI制御の実装

マイケル
マイケル
まずはUIの実装から見ていきます。 UE5ではUMG (Unreal Motion Graphics) という機能を使用して実装します。

UMGの概要について

マイケル
マイケル
UMGはUnityでいうところのCanvas的なイメージで、Widgetという単位で作成します。 Widgetの中に更にWidgetを入れ子構造で持たせることもできるので、制御しやすい単位でWidgetを分けるのが重要になります。

参考:
UnrealEngineドキュメント - UMG UI デザイナのクイック スタート ガイド
UnrealEngineドキュメント - UMG UI デザイナ ユーザーガイド

20240519_03_ue5_cpp_ui_effect_01
▲UnityでいうCanvas的なイメージ

20240519_03_ue5_cpp_ui_effect_03
▲Widget内にWidgetを入れ子にできる

マイケル
マイケル
ちなみに今回は下記のような単位で作成しています。 Widgetとして分けておくと、ある程度まとめての表示/非表示切り替えの制御も行いやすいです。
Widgetの分割単位
Widget名
役割
RunGameWidget
以下のWidgetを含む
RunGameScoreInfoWidget
スコア情報
RunGameMessageInfoWidget
メッセージ表示
RunGameLevelUpWidget
レベルアップ表示
RunGameResultWidget
リザルト表示
エレキベア
エレキベア
UMGではWidgetの単位で考えるクマね
マイケル
マイケル
あとはUMG画面内でアニメーションが作成できたり、Imageの角を丸められたりなどといった機能も付いているのが便利です。
20240519_03_ue5_cpp_ui_effect_02
▲UMG内にアニメーションタブもある

20240519_03_ue5_cpp_ui_effect_04
▲ProceduralUIのような機能も付いている

エレキベア
エレキベア
角を丸められるのはUnityだと有料アセットでしか見ないクマからこれはありがたいクマね
【Unity】「Procedural UI Image」を使ってシンプルなUIを爆速で作成する
2022-08-22

▲UnityではProcedural UI Image という有料アセットで似たようなことができる

マイケル
マイケル
予想ではあるけど多分Unrealの機能であったからUnityでも使えるようにしたのかな?と思っています。 Unityでも標準機能にしてほしい・・・。

UI表示の動的操作について

マイケル
マイケル
そしてコードからUIをどう操作するのか?についてですが、まずUUSerWidgetクラスを継承したクラスを親クラスに指定してWidgetを作成する必要があります。
/**
 * RunGameWidget: リザルトUI
 */
UCLASS()
class URunGameResultWidget : public UUserWidget
{
	GENERATED_BODY()

protected:
	virtual void NativeConstruct() override;
	virtual void NativeOnInitialized() override;

・・・
▲UUSerWidgetを継承して作成する
20240519_03_ue5_cpp_ui_effect_05
▲Widget作成時に親クラスとして指定する

マイケル
マイケル
そして個々のUI要素を紐づける方法はいくつかありますが、今回はUPROPERTYにメタ属性として「BindWidget」「BindWidgetAnim」を指定することで紐づける方法を使用しています。 こうすることで、コンパイル時に変数名と同名のUI要素を紐づけてくれます。
protected:
	/** リザルトスコアテキスト */
	UPROPERTY(meta = (BindWidget))
	TObjectPtr<UTextBlock> ResultScoreText;

	/** リザルト 出現アニメーション */
	UPROPERTY(Transient, meta = (BindWidgetAnim))
	TObjectPtr<UWidgetAnimation> ResultAppearAnimation;
▲UPROPERTYでBindWidgetを設定することで紐づける
エレキベア
エレキベア
自動バインディング的な機能があるのクマね
マイケル
マイケル
ちなみにコンパイル時にエラーにしたくない場合には「BindWidgetOptional」など後ろに「Optional」と付けることで回避できます。 またコードを使用しないプロパティバインディングについては、下記の公式ドキュメントをご参照ください。

参考:
UnrealEngineドキュメント - プロパティのバインディング

エレキベア
エレキベア
絶対にUIと紐づけられてるのを保証するのであれば、Optionalは付けない方がよさそうクマね

その他Tips

まとめて操作したい場合にはBorder等でまとめる
マイケル
マイケル
アニメーション等で複数のUI要素を一括で操作したい場合、Border等でまとめると解決する場合があります。
20240519_03_ue5_cpp_ui_effect_06
▲一括で操作したい場合、Border等でまとめる

エレキベア
エレキベア
ちょっと面倒くさいクマね・・・
画面解像度に合わせてUI要素をスケーリングする設定
マイケル
マイケル
また、Unityのように画面解像度に合わせてUI要素をスケーリングしたい場合、 caleBox、SizeBox、CanvasPanelの順で格納するといい感じに調整できました。
20240519_03_ue5_cpp_ui_effect_07
▲画面解像度に合わせてスケーリングする場合

参考:
ウィジェットの大きさを画面に合わせる その2 - 妹でもわかるUnrealEngine4

エレキベア
エレキベア
これで画面解像度が変わっても比率を守って調整してくれるクマね
マイケル
マイケル
お手軽で調整できますが、パフォーマンス面を考慮する場合には他の方法を検討する必要もあるかもしれません。

レベル遷移の実装

マイケル
マイケル
次にレベル遷移処理を把握しておきたかったこともあり、簡易的なタイトル画面を作成してみました。 こちらを使用してレベル遷移を実装してみます。
20240519_03_ue5_cpp_ui_effect_08
▲とりあえず作成したタイトル画面

レベル遷移処理
マイケル
マイケル
とはいえレベル遷移させるの自体は簡単で、用意されているUGameplayStatics::OpenLevel関数を呼び出すだけで遷移することができます。
	TitleLevelUiData->SetOnPushStartButtonEvent([this]()
	{
		// RunGameレベルへ遷移する
		UGameplayStatics::OpenLevel(GetWorld(), "RunGame");;
	});
▲レベル遷移処理
エレキベア
エレキベア
まあこんなもんクマね
GameInstanceを使用したデータ保持
マイケル
マイケル
課題となるのはこのレベル間でデータを共有するのをどうするか?になります。 こちらはレベル遷移しても保持されるGameInstanceクラスを生成してプロパティを保持することで対処しました。

参考:
Qiita - UE4 GameInstance、Singletonへc++からアクセスする
UnrealEngineドキュメント - ゲーム フローの概要

// Copyright (c) 2024, CatRunner All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Audio/AudioService.h"
#include "Engine/GameInstance.h"
#include "CatRunnerGameInstance.generated.h"

/**
 * CatRunnerGameInstance
 * シーンをまたいで永続的に扱うオブジェクトを定義する
 */
UCLASS()
class CATRUNNER_API UCatRunnerGameInstance : public UGameInstance
{
	GENERATED_BODY()

	UCatRunnerGameInstance(const FObjectInitializer& ObjectInitializer);

public:
	static UCatRunnerGameInstance* GetInstance();
	static TObjectPtr<UAudioService> GetAudioService() { return GetInstance()->AudioService; }

private:
	UPROPERTY()
	TObjectPtr<UAudioService> AudioService;

};

// Copyright (c) 2024, CatRunner All Rights Reserved.


#include "GameInstance/CatRunnerGameInstance.h"

#include "Audio/AudioService.h"

UCatRunnerGameInstance::UCatRunnerGameInstance(const FObjectInitializer& ObjectInitializer)
	:AudioService(nullptr)
{
	AudioService = NewObject<UAudioService>();
}

UCatRunnerGameInstance* UCatRunnerGameInstance::GetInstance()
{
	UCatRunnerGameInstance* Instance = nullptr;

	if (GEngine != nullptr)
	{
		const FWorldContext* CurrentWorldContext = GEngine->GetWorldContextFromGameViewport(GEngine->GameViewport);
		Instance = Cast<UCatRunnerGameInstance>(CurrentWorldContext->World()->GetGameInstance());
	}
	return Instance;
}
マイケル
マイケル
今回の規模だと基本的に保持するデータはないのですが、オーディオ再生を管理するクラス(AudioService)のみ保持することにしました。 注意点として、UPROPERTYを付与しておかないとGC対象となってしまうことがあることです。 自分はこれのせいでMacだけデータが保持されずしばらく調査に悩むといった事象にあたりました...。
エレキベア
エレキベア
UPROPERTYの付け忘れは恐ろしいクマ・・・

サウンド・エフェクトの実装

マイケル
マイケル
最後に味付けでサウンドとエフェクトを実装します。

サウンド再生の実装

マイケル
マイケル
サウンド再生もそこまで難しいことはなく、音源をUSoundBaseクラスとして取得し、UGameplayStatics::PlaySoundXXX関数を使用することで再生できます。
void UAudioService::PlaySe2d(USoundBase* PlaySe)
{
	if (PlaySe == nullptr)
	{
		return;
	}
	const UWorld* CurrentWorld = GEngine->GetWorldContextFromGameViewport(GEngine->GameViewport)->World();
	UGameplayStatics::PlaySound2D(CurrentWorld, PlaySe);
}

void UAudioService::PlaySe3d(USoundBase* PlaySe, const FVector& PlayLocation)
{
	if (PlaySe == nullptr)
	{
		return;
	}
	const UWorld* CurrentWorld = GEngine->GetWorldContextFromGameViewport(GEngine->GameViewport)->World();
	UGameplayStatics::PlaySoundAtLocation(CurrentWorld, PlaySe, PlayLocation);
}
▲基本の2D/3D再生
エレキベア
エレキベア
位置も渡すことで3D再生できるのクマね
マイケル
マイケル
もう一つの方法として、UAudioComponentを作成して操作する方法があります。 こちらはUnityでいうAudioSource的なもので、再生・停止といった操作も柔軟に行うことができます。
	/** BGM再生用AudioComponent */
	UPROPERTY()
	TObjectPtr<UAudioComponent> BgmAudioComponent;
▲AudioComponentの定義
void UAudioService::PlayBgm(USoundBase* PlayBgm)
{
	if (PlayBgm == nullptr)
	{
		return;
	}

	// 初回orシーン遷移後はAudioComponentを生成する
	if (BgmAudioComponent == nullptr || !IsValid(BgmAudioComponent))
	{
		const UWorld* CurrentWorld = GEngine->GetWorldContextFromGameViewport(GEngine->GameViewport)->World();
		BgmAudioComponent = UGameplayStatics::SpawnSound2D(CurrentWorld, PlayBgm);
		return;
	}

	// 再生する音源を差し替える
	BgmAudioComponent->Stop();
	BgmAudioComponent->SetSound(PlayBgm);
	BgmAudioComponent->Play();
}

void UAudioService::StopBgm() const
{
	if (BgmAudioComponent == nullptr)
	{
		return;
	}
	BgmAudioComponent->Stop();
}
▲AudioComponentによる再生
マイケル
マイケル
今回はこのような簡潔な処理をAudioServiceクラスとして抜き出して作成しています。 ボリューム調整など、サウンド周りはもう少し作り込む余地がありそうですね。
エレキベア
エレキベア
Unityで頑張って実装したオーディオクラスは下記を参照してくれクマ〜〜
【Unity】サウンドミドルウェアに依存しない設計を考える【CRI ADX・Wwise】
2024-03-27

エフェクト再生の実装

マイケル
マイケル
エフェクト再生については、Niagaraという機能を使用して作成しています。 こちらはUnityでいうShurikenのようなもので、高機能なパーティクルシステムとなっています。

UnrealEngineドキュメント - Niagara のクイックスタートガイド

エレキベア
エレキベア
Niagaraという名前はよく聞くクマ
マイケル
マイケル
GPUSimulationという機能を使用してComputeShaderの代わりにも使えたりと、中々奥が深い機能なんだ。 こちらも別途別の記事で紹介しようかなと思っています!
Niagaraの構成要素
エフェクトの構成
マイケル
マイケル
Niagaraは大きく「システム」「エミッタ」で構成されています。 システムはレベルに配置できる単位で、その中に放出源であるエミッタを複数持たせることができます。
20240519_03_ue5_cpp_ui_effect_15

  • システム
    • レベルに配置することのできる単位
    • エミッタを複数持つことができる
  • エミッタ
    • パーティクルの放出源
    • 他のシステムからも使用することができる
エミッタの構成
マイケル
マイケル
そしてエミッタはモジュールという機能を持たせることで実装します。 数や放出する形状、速度などを設定した後、レンダラーにスプライトやメッシュ等を指定することで描画することができます。
20240519_03_ue5_cpp_ui_effect_16

  • モジュール
    • 上から下に向かうように1つずつ順番に実行され、更新モジュールは毎フレーム繰り返し実行される
    • エミッタのスポーン、更新など、ラックの一つ一つがモジュールに該当する
  • レンダラー
    • 処理した粒子の位置等の情報を拾い、実際に画面に表示させる
    • スプライト、メッシュなどの種類がある
エレキベア
エレキベア
大体イメージは分かったクマ モジュールについてはまたいろいろ勉強する必要はありそうクマね
星のエフェクト
マイケル
マイケル
今回は星のテクスチャを使ったエフェクトを複数用意していて、打ち出す数と形状を変えることで印象を変化させています。
20240519_03_ue5_cpp_ui_effect_09
▲アイテム取得時などのエフェクト

20240519_01_ue5_cpp_run_game_09

20240519_03_ue5_cpp_ui_effect_10
▲一つを真上に打ち出す

20240519_03_ue5_cpp_ui_effect_11
▲三つを真上にCone状で打ち出す

20240519_03_ue5_cpp_ui_effect_12
▲多量を球状に打ち出す

エレキベア
エレキベア
同じテクスチャでもモジュールを変えることでいろんなエフェクトが作れるのクマね
煙のエフェクト
マイケル
マイケル
そしてプレイヤー死亡時の煙(爆発?)は、下記のようなもわっとしたテクスチャを用意して球状に打ち出すことで表現しました。
20240519_01_ue5_cpp_run_game_10

20240519_03_ue5_cpp_ui_effect_14
▲煙を球状に打ち出す

エレキベア
エレキベア
簡単なエフェクトクマね
マイケル
マイケル
作成したエフェクトは以上になります! 今回実装したのは本当に簡単なものだけど、作り込めば商用レベルのエフェクトを作ることも可能なので、興味がある方はいろいろ試してみてください!

おわりに

マイケル
マイケル
以上でゲームは完成です! 三回分に分けて紹介してみましたが、どうだったかな?
エレキベア
エレキベア
やっぱゲーム制作は楽しいクマ〜〜〜 こういう小規模なゲームでも一通り作ると開発の感触が掴みやすいクマね
マイケル
マイケル
UnrealEngineだとどうしても大規模なゲーム開発がメインになるから、ミニゲーム規模で理解しやすいプロジェクトが中々ないんだよね・・・ 今回の記事が誰かの役に立てば幸いです!
エレキベア
エレキベア
まあ個人開発規模のゲームなら正直Unityの方が向いてそうクマからね・・・
マイケル
マイケル
今後はもちろんUnityも触っていきますが、UnrealEngine関連の記事も増えるかもしれないのでお楽しみに! アデューー!!
エレキベア
エレキベア
おつかれクマ〜〜〜〜

【UE5】第三回 ミニゲーム制作で学ぶUnrealC++ 〜UI・仕上げ実装 編〜 〜完〜

【UE5】第一回 ミニゲーム制作で学ぶUnrealC++ 〜UnrealC++の概要 編〜
2024-05-18
【UE5】第二回 ミニゲーム制作で学ぶUnrealC++ 〜キャラクター・ゲーム実装 編〜
2024-05-18
【UE5】第三回 ミニゲーム制作で学ぶUnrealC++ 〜UI・仕上げ実装 編〜
2024-05-18

UnrealEngineC++制作日記ミニゲームUE5
2024-05-18
記事をSNSで共有する
X
Facebook
LINE
はてなブックマーク
Pocket
LinkedIn
Reddit

著者の各種アカウント
フォローいただけると大変励みになります!
X
GitHub

関連記事
【UE5.5】Nanite、Lumen、VSMの概要についてまとめる
2025-05-12
【UE5】Niagara SimulationStageによるシミュレーション環境構築
2024-05-30
【UE5】第二回 ミニゲーム制作で学ぶUnrealC++ 〜キャラクター・ゲーム実装 編〜
2024-05-18
【UE5】第一回 ミニゲーム制作で学ぶUnrealC++ 〜UnrealC++の概要 編〜
2024-05-18
【JUCE】DTMプラグインを作ってみる 〜ディストーション編〜【VST/AU】
2024-03-22
【Unity】「怪盗チョコレート」をリリース!工夫点や反省点をざっと振り返る【バレンタイン】
2023-02-12
【DirextX12】第四回 DirextX12を使ったゲーム開発 〜FBX SDKを使用した3Dモデル描画〜
2022-12-07
【DirextX12】第三回 DirextX12を使ったゲーム開発 〜座標変換と3Dオブジェクト表示〜
2022-11-27