310.5K Views
October 06, 21
スライド概要
2021年10月2日に行われた「出張ヒストリア! ゲーム開発勉強会2021」にて発表させていただいたスライドです。
イベント詳細
https://historia.co.jp/archives/22783/
講演動画
https://youtu.be/2L1Dor22Kjs
スライド内記事
[UE4] Subsystem, GameplayAbilityに関する講演で使用したC++コードについて
https://qiita.com/EGJ-Kaz_Okada/items/0ae2e8d8ba901c6a978d?fbclid=IwAR2_ygPhJFNGqJ79kFbFmey_k-K3uf00m7fSZc2K_KGOLJeUzN2WixYmd3o
講演者:
エピック ゲームズ ジャパン 岡田 和也 (Developer Relations, Software Engineer)
講演内容:
UE4が持つ様々な凄い機能やグラフィック表現について語られることは多いですが、日々の開発で使用すると少し便利になる地味な機能・フローについては少なめです。
これはプロジェクトの内容・人員など様々な要素により最適なワークフローが変わるため、「話しても参考になるか不安…」「そもそも今のやり方があってるか不安…」
ということで話しづらいのが原因かと思います(僕もそうです)。
とはいえ、こういった部分も開発では非常に重要です!
そこでこういった議論がもっと活発になるように人柱になって、最近自主開発で便利さ・手応えを感じた
DataAsset, Subsystem, GameplayAbilityの使い方についてお話します。
(初心者向けなので比較的簡単な内容です。プロ向けではありませんのでご注意を!)
株式会社ヒストリアは、Unreal Engine専門のソフトウェア開発会社です。ゲーム事業とエンタープライズ事業、2 つの軸でソフトウェアの企画、開発を行っています。また、Unreal Engine の学習を目的とした作品制作コンテスト『UE5ぷちコン』や、『出張ヒストリア! ゲーム開発勉強会』を主催、技術ブログを毎週更新など、Unreal Engine コミュニティを盛り上げる活動も行っております。
目指せ脱UE4初心者!? 知ってると開発が楽になる便利機能を紹介 – DataAsset, Subsystem, GameplayAbility編 – 出張ヒストリア! ゲーム開発勉強会2021 Epic Games Japan 岡田 和也
自己紹介 Epic Games Japan 岡田 和也 Twitter:おかず ( @pafuhana1213 ) Unreal Engineを使っている企業の技術サポートや 勉強会などでの講演が主なお仕事 No Twitter, No Life
本講演の趣旨 知らなくてもUE4を使ったコンテンツ制作はできるけど… 知ってると実装が楽になったり、 より効率的なワークフローを組める(かもしれない)機能を紹介 ● Data Asset ● Subsystem ● Gameplay Ability System ( GAS )
本講演の対象者 ● UE4を使った開発の超基本的な流れが 何となく分かってきた初心者の方 ● DataAsset, Subsystem, GASを 聞いたことはあるけど、 使い方のイメージが分からなかったりで断念した方 可能な限り C++は使わない方向で話します 追記:本スライドにおけるC++コードを コピペ用に記事にしました
メインテーマ 処理・作業を分散・分担しよう!
Data Asset
どんな機能? 様々なパラメータ・アセットを 管理・編集・取得するためのアセット ● ● ● ● ● 武器名 攻撃力 価格 3Dモデル アイコン などなど ● ● ● ● ● ● 名前 体力 防御力 移動速度 ジャンプ力 3Dモデル などなど
BPのプロパティで設定すればいいんじゃないの? Data Tableってやつを使うんじゃないの?
バリエーションが増えると… パラメータだけ違うほぼ同じBPが 大量に並ぶことに! 管理 大変!
バリエーションが増えると… 少しパラメータ弄るたびに BPエディタを開くのは面倒! 誤って 違うパラメータ変えそうで怖い! 調整 大変!
パラメータ調整も少しめんどう… 実行中はBPエディタ上での パラメータ調整はできない F8で抜けてのパラメータ変更は ちょっと面倒。反映忘れも 調整 大変!
Data Tableについて その名の通り、 テーブル形式でデータを管理する機能 大量のデータ、パラメータの管理に便利 CSVファイルと連携できるので Excelを使った調整も可能 実行中のパラメータ変更も可能 ヒストリアブログより
Data Tableの微妙なところ パラメータの取得が少し面倒くさい…
Data Tableの微妙なところ パラメータの取得が少し面倒くさい… 編集エディタの使い勝手が少し悪い… エディタを拡張しづらい… 毎回Excelを開くのもめんどう…
Data Tableの微妙なところ パラメータの取得が少し面倒くさい… 編集エディタの使い勝手が少し悪い… エディタを拡張しづらい… 毎回Excelを開くのもめんどう… 複数人での同時編集ができない 分業しづらい
この辺りの問題・課題を 解決するのが Data Asset!
Data Asset のいいところ ① パラメータ編集に専念できる! 関係のないデータ・処理を誤って編集することがない
Data Asset のいいところ ② 実行しながらパラメータ変更可能! 細かいパラメータ調整が 必要な部分で超便利 ちなみに DataTableでも同じことできます
Data Asset のいいところ ③ パラメータの取得がかんたん! プロパティに設定したData Asset から直接取得できる。Cast不要
Data Asset のいいところ ④ DataAssetのベースはBPなので 変数だけでなく関数も利用可能 例えば 各パラメータに計算式を 適用した結果を取得できたり
Data Asset のいいところ ⑤ プロパティからData Assetを設定できる! 差し替えが簡単!量産もラクラク!
プリセット的なつかいかたも
プロパティなので、様々な箇所で利用可能 パラメータ調整のためだけに 各編集エディタを開く必要が なくなるのは便利!
Data Asset のいいところ ⑥ 作業分担もしやすい! アニメーション編集と パラメータ調整を並行可能! ゲーム デザイナ猫 アニメータ犬
Data Asset のいいところ ⑦ BP, C++で実装した処理を 実行できるボタンを追加可能! 編集・チェック処理を 走らせることで作業を効率化!
ざっくりまとめると データドリブン型の開発ができる! 内部実装を理解・編集しなくても、 データだけで表示・挙動などの追加・変更が可能 作業分担・複数人作業がしやすい! 実装・データを分離できるので、編集を同時にできる ロック解除待ちしなくていい 編集作業を支援・自動化する仕組みを追加できる! 作業効率を上げるだけでなく ヒューマンエラーを回避できる!
Data Asset は いいぞ
Data Asset の つくりかた
Data Asset の つくりかた ① Data Asset のテンプレートとなる BP または C++クラス を作成 UPrimaryDataAsset か UDataAsset (C++のみ) をベースにすること UCLASS(Abstract, BlueprintType) class ACTIONRPG_API URPGItem : public UPrimaryDataAsset { GENERATED_BODY() ... UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Item) FText ItemName; ... } ActionRPGサンプル の RPGItem.h より
Data Asset の つくりかた ② 作成したBP または C++ クラスを元に Data Asset を作成 前ページで作成したものを選択
Data Asset の つかいかた
Data Asset の つかいかた ① BP, C++クラスのプロパティ が Data Assetのプロパティに!
Data Asset の つかいかた ② Call in Editor が有効になっている イベント・関数がボタンに!
Data Asset の つかいかた ③ プロパティの型は 元になったBP, C++クラスを指定
Data Asset の つかいかた ④ Data Asset プロパティから Get / Set ノードを呼び出し可能 Setできるのは Data Tableとの大きな違い!
かんたん! …だけど少し注意点も
アセットのハード参照にはご注意を BPと同じく、アセットを直接参照すると 参照関係の連鎖によるロード・メモリの問題が発生する可能性が! 可能な限り、ソフト参照にすることを推奨
ハード・ソフト参照に関する資料 公式ドキュメント アセットの参照 おかわりのアンリアルなメモ ハード参照とソフト参照 CC2 技術ブログ 第007回UE4のアセットの参照方法について、そのロードの違い HEXA BLOG BPの参照連鎖を断つ手法 参照連鎖によるロード時間が問題になった例 Nintendo Switch『OCTOPATH TRAVELER』はこうして作られた (p79より)
Data Assetを丸ごと(事前)ロードする手も Asset Manager と連携することで Data Asset 単位でロード管理 ↓ 詳しくはこちら! ↓ [UE4] Asset Managerのアセットの 非同期ロード機能について その1 ( 非同期ロードの解説 & レベルの裏読み編 ) Action RPG サンプル も BP_GameInstance の InitializeStoreItems イベント もぜひ
大量のデータを扱うのは少し苦手
Data Table と Data Asset の連携 Data Table ( CSV ) から Data Asset を自動生成・反映する方法 ヒストリア技術ブログ [UE4] 独自に用意したデータアセットを より便利に活用する方法 カリギュラオーバードーズにおける UE4へのデータ移植の手引き 中国語の記事 DataTableからDataAssetを生成する EditorUtiltiyWidgetの解決
Data Asset 用編集エディタ Editor Utility Widget を使って 管理・編集用のエディタを自作するのも手! [UE4]エディタ上で動作する ツール・エディタ拡張をUMGで簡単に作れる Editor Utility Widget について 株式会社アンナプルナ ブログ 【UE4】Editor Utility Widgetについてのあれこれ
Data Asset の まとめ Data Asset を活用することで 作業の分担 と データドリブン型の開発を実現できる! パラメータ調整を頻繁に行う箇所や 複数人が作業する部分に関してはData Asset化すると便利! Data Assetを使うのは非常に簡単! BPのみでも利用可能! 大量のデータを扱う際は注意 プロジェクトにあった編集・管理フローを要検討!
Data Asset に関連する資料 UE4公式 Asset Manager Explained | Inside Unreal Data-Driven Sound Design | Unreal Fest Europe 2019 | キンアジのブログ 【UE4】手軽に独自のデータアセットを作成する 【UE4】4.23でなくなった「Blutility」の拡張ウィンドウを使いたい場合 @unknown_ds さんのQiita記事 UE4 PrimaryDataAssetを使ってみる Unreal Engineのすすめ リアルタイム3DCG入門 データアセットでギャラリーを作る
Subsystem
ネットワーク対応で使う Online Subsystem とは 関係ありません!
どんな機能? エンジンによって自動的に管理(生成・保持・破棄)される インスタンス( UObject ) Engine, Editor, Game Instance, World, Local Playerと 同じライフサイクルで管理可能
○○○ Manager, Systemを作りたい気持ち プロジェクトに要素が増えていくと それらを個別に管理 & どこからでもアクセスできる仕組みが欲しくなります スコア Manager サウンド Manager バトル Manager レベル Manager エフェクト Manager ● ● ●
Actorで ○○○ Manager を作る場合 実装かんたん! レベルに配置、または動的に生成する必要がある レベルを追加した際に忘れがち…
Actorで ○○○ Manager を作る場合 アクセスするのが面倒… プロパティ公開して設定するのは面倒。忘れがち Get All Actors…は処理が重いので避けたい
Game Mode , Game Instance の場合 どこからでもアクセスできる! ただし、Cast または BP インターフェイスが必要 Cast は 負荷・参照関係の問題があり、 BPインターフェイス は BPノードの候補を汚す
Game Mode , Game Instance の場合 Game Mode, Game Instance は 1つしか存在できないので 実装・データが集中して大変なことになりがち。複数人での作業もしづらい 参照関係が複雑になり、ロード・メモリ問題が発生しやすい問題など スコア Manager バトル Manager エフェクト Manager
Singleton の場合 GameInstance のように永続的なオブジェクトを作成・使用する方法 複数のクラスを用意できるので、役割ごとに実装を分担できる C++側での実装がメインになり、 BP上での作業、BPとの連携がしづらい [UE4]GameInstance以外で永続的なオブジェクトを扱う UE4 GameInstance、Singletonへc++からアクセスする UE4/C++: C++er が UE4型のシングルトンを作る際に気をつける事
この辺りの問題・課題を 解決するのが Subsystem!
Subsystem のいいところ ① どこからでも BP, C++で簡単にアクセスすることができる! Cast、BPインターフェイスは不要! GameInstance->GetSubsystem <UScoreSubsystem>();
Subsystem のいいところ ② エンジン側で自動で生成・破棄してくれるので プロジェクト設定の編集、Spawn、Destroy などは不要!
Engine Editor GameInstance Subsystem 各システムに対して Subsystemがぶら下がる形 (Componentようなイメージ) Game Instance World Score Gimmick Subsystem Subsystem Local Player World Subsystem 各システムと同じタイミングで 生成・破棄される (ライフサイクルが同じ)
Game Instance Subsystemの場合 Score Subsystem ● ● ● Score Subsystem
World Subsystemの場合 Gimmick Subsystem
World Subsystemの場合 Gimmick Subsystem Gimmick Subsystem
判断基準の例 レベルに紐づく 要素を管理 ゲーム全般に 関わる要素を管理 World Subsystem Game Instance Subsystem プレイヤー毎の 要素を管理 監視系や ツール寄りの機能 Local Player Subsystem Engine / Editor Subsystem
Subsystem のいいところ ③ プロジェクトの独自BP から 実装を切り離せる! 実装の管理や複数人での作業が楽に! プロジェクト本体への依存度が減るので、参照関係の整理もしやすい! Score Subsystem Game Instance Battle Subsystem Game State Subsystem
Subsystem のいいところ ④ エンジン改造しなくても エディタ上での作業を(ある程度)カスタム・自動化できる! (エディタ機能が使っているSubsystemにアクセス・干渉可能)
UE4.27 が持つSubsystem一覧 - UGameInstanceSubsystem - UEditorSubsystem - UWorldSubsystem - UReplaySubsystem - UAssetEditorSubsystem - UColorCorrectRegionsSubsystem - ULocalPlayerSubsystem - UBrushEditingSubsystem - UGPULightmassSubsystem - UEnhancedInputLocalPlayerSubsystem - UClassTemplateEditorSubsystem - UNetworkPredictionWorldManager - UDynamicSubsystem - UContentBrowserDataSubsystem - UObjectTraceWorldSubsystem - UEngineSubsystem - UDisplayClusterConfiguratorEditorSubsystem - UViewportStatsSubsystem - UAssetTagsSubsystem - UEditorUtilitySubsystem - UTickableWorldSubsystem - UDMXPixelMappingSubsystem - UEditorValidatorSubsystem - UWaterSubsystem - UDMXSubsystem - UImportSubsystem - UQuartzSubsystem - UEnhancedInputEngineSubsystem - UStylusInputSubsystem - ULandscapeSubsystem - UGerstnerWaterWaveSubsystem - ULayersSubsystem - UAutoDestroySubsystem - UHLODEngineSubsystem - UMoviePipelineQueueSubsystem - UConversationRegistry - UMoviePipelineQueueEngineSubsystem - UPanelExtensionSubsystem - UDisplayClusterWorldSubsystem - UText3DEngineSubsystem - UVPScoutingSubsystem - UNetworkPhysicsManager - UTimedDataMonitorSubsystem - UWaterEditorSubsystem - UBlueprintContextBase - UVCamInputSubsystem - UVirtualCameraSubsystem - UWindowsMixedRealityInputSimulationEngineSubsystem - UDataDrivenCVarEngineSubsystem - UCommonUISubsystemBase - URCPropertyContainerRegistry - UCameraCalibrationSubsystem
ざっくりまとめると アクセスが簡単なので、 使い勝手のいい ◯◯◯ Manager を作れる! 自動で管理してくれるので実装も楽に! 複数人作業や参照関係の整理でもメリットあり! エンジン改造しなくても内部処理をカスタム可能! ヒューマンエラーを回避するための チェック処理にぴったし!
Subsystem の つくりかた と つかいかた
GameInstance Subsystemの場合 - 準備 UCLASS() class ○○○_API UMyGameInstanceSubsystem : public UGameInstanceSubsystem { GENERATED_BODY() public: UFUNCTION(BlueprintCallable) int32 GetScore(){ return Score; } private: int32 Score; };
GameInstance Subsystemの場合 - 取得 - GameInstance->GetSubsystem <UMyGameInstanceSubsystem>();
え、C++必須なの!? BPでプロパティや処理作れないの!?
下準備で C++ が少し必要ですが BP側でプロパティ・処理を追加する方法をご紹介
① Subsystem を BP化する方法 (自己責任コース) ② Subsystem に 拡張用BP を持たせる方法 (Epic 推奨はこちら)
Subsystemを継承した新規C++クラスを作成
// Copyright Epic Games, Inc. All Rights
Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/WorldSubsystem.h"
#include "MyWorldSubsystem.generated.h"
/**
*
*/
UCLASS()
class ACTIONRPG_API UMyWorldSubsystem :
public UWorldSubsystem
{
GENERATED_BODY()
};
BPから作成可能に(要コンパイル)
// Copyright Epic Games, Inc. All Rights
Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/WorldSubsystem.h"
#include "MyWorldSubsystem.generated.h"
/**
*
*/
UCLASS( Blueprintable, Abstract)
class ACTIONRPG_API UMyWorldSubsystem :
public UWorldSubsystem
{
GENERATED_BODY()
};
問題点 ① C++側 の Subsystem クラスのGetノードが候補に並んでしまう 中身(インスタンス)は同じなので 複数のSubsystemが生成されている問題はないが… 混乱を招く可能性がある
問題点 ② GameInstance ( Local Player ) Subsystem場合、 GameInstnace の 初期化時 などの早いタイミングで その Subsystem を 同期ロードしないとパッケージで正常に動作しない
問題点 ③ Engine Subsystem の BP は 生成されず、正常に動作しない! 検証不足で実は可能かもしれませんが ハック的な方法になる可能性大
SubsystemのBP化はサポートされていません 自己責任でお願いいたします!
① Subsystem を BP化する方法 (自己責任コース) ② Subsystem に 拡張用BP を持たせる方法 (Epic 推奨はこちら)
どういうこと? Subsystem に特定のBPプロパティを追加し Subsystemではなく、そのBPに対して実装・パラメータの追加を行う方法 MyGameInstance Game Instance Subsystem(C++) BP_MyGameInstanceSubsystemHelper
なにがうれしいの? Subsystemの利点を維持しつつ、BP側での拡張を安全に行える! SubsystemのBP化における問題点を全て回避できる!嬉しい!
拡張用BPのプロパティを持たせるには // 拡張用BPのベースとなるクラス UCLASS(Abstract, Blueprintable, MinimalAPI, meta = (ShowWorldContextPin)) class UMyGameInstanceSubsystemHelperBase : public UObject { GENERATED_BODY() }; UCLASS() class SUBSYSTEMBP_API UMyGameInstanceSubsystem : public UGameInstanceSubsystem { GENERATED_BODY() public: // 拡張用BPのプロパティ UPROPERTY(Transient, BlueprintReadWrite) UMyGameInstanceSubsystemHelperBase* SubsystemHelper; };
拡張用BPの作成 と Subsystem への設定
C++側で生成と設定をする手も ( .h側 )
UCLASS()
class SUBSYSTEMBP_API UMyGameInstanceSubsystem : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
UMyGameInstanceSubsystem();
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
UPROPERTY(Transient, BlueprintReadOnly)
UMyGameInstanceSubsystemHelperBase* SubsystemHelper;
private:
TSubclassOf< class UMyGameInstanceSubsystemHelperBase > SubsystemHelperClass;
};
C++側で生成と設定をする手も ( .cpp側 )
#include "MyGameInstanceSubsystem.h"
#include "Runtime/CoreUObject/Public/UObject/ConstructorHelpers.h"
UMyGameInstanceSubsystem::UMyGameInstanceSubsystem()
{
// 拡張用BPのクラス情報を検索・取得。パスの指定には注意
// .ini や プロジェクト設定でBPアセットのパスを設定できるようにしておくと親切
static ConstructorHelpers::FClassFinder<UMyGameInstanceSubsystemHelperBase>
BluePrintFile(TEXT("/Game/Subsystem/BP_MyGameInstanceSubsystemHelper"));
if (BluePrintFile.Class)
{
SubsystemHelperClass = (UClass*)BluePrintFile.Class;
}
}
C++側で生成と設定をする手も ( .cpp側 )
void UMyGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
SubsystemHelper = nullptr;
if (SubsystemHelperClass)
{
// 拡張用BPを生成・設定
SubsystemHelper =
NewObject<UMyGameInstanceSubsystemHelperBase>(GetTransientPackage(),
SubsystemHelperClass);
}
}
void UMyGameInstanceSubsystem::Deinitialize()
{
SubsystemHelper = nullptr;
}
注意点 プロパティの型 は C++側の Base クラスなので BP側で新規追加したプロパティや関数を直接呼ぶことは出来ません Cast を使って型変換をするか、 C++側で関数の準備をする必要があります
C++側で関数の準備をする場合 UCLASS(Abstract, Blueprintable, MinimalAPI, meta = (ShowWorldContextPin)) class UMyGameInstanceSubsystemHelperBase : public UObject { GENERATED_BODY() public: // 処理の中身はBP側で書くことを宣言 UFUNCTION(BlueprintCallable, BlueprintImplementableEvent) void TestFunc(); };
Subsystemのメリットを振り返り アクセスが簡単なので、 使い勝手のいい ◯◯◯ Manager を作れる! 自動で管理してくれるので実装も楽に! 複数人作業や参照関係の整理でもメリットあり! エンジン改造しなくても内部処理をカスタム可能! ヒューマンエラーを回避するための チェック処理にぴったし! C++をほんの少しがんばる価値は あると思います!
補足 とか 注意点とか
Subsystem で Tick を使いたい! FTickableGameObject か FTickableEditorObject も 継承させればOK! UE4 プログラミングサブシステムを試してみる#Tick処理を実装する (@unknown_dsさん) Subsystem に Tick処理を実装する際の注意点について UE4.27 で Tick 付きの WorldSubsystem が追加されました! UTickableWorldSubsystem
LocalPlayer Subsystem が動かないんだけど? LocalPlayer Subsystem は Player Controller 内でしか使えません! UCLASS(Abstract, Within = LocalPlayer) class ENGINE_API ULocalPlayerSubsystem : public USubsystem
Subsystemの初期化順を設定したい!
同系統のSubsystem同士なら可能です!
void UMySubsystem1::Initialize(FSubsystemCollectionBase& Collection)
{
// UMySubsystem2が未初期化ならば先に初期化する
Collection.InitializeDependency(UMySubsystem2::StaticClass());
auto _MySubsystem2 = GetGameInstance()->GetSubsystem<UMySubsystem2>();
if(_MySubsystem2){
// UMySubsystem2に対する処理
}
}
UE4 プログラミングサブシステムを試してみる#同系統のサブシステム同士の初期化順序について
(@unknown_dsさん)
こちらの資料・記事も是非 公式ドキュメント プログラミング サブシステム 猫 猫でも分かるUE4.22から入ったSubsystem UE4.23から入った「Editor Validator Subsystem」を使って、アセット保存時などで走るチェック処理 (Validate Assets)を拡張しよう! キンアジのブログ 【UE4】ImportSubsystemについて Boys Be Unreal! Engine Subsystemを使ってEditor Utility Widgetへの入力を反映する @koorinonaka さんのQiita記事 [UE] 足跡、足音エフェクトを再生する
アセットのハード参照にはご注意を Subsystem に ハード参照されているアセットは ゲーム起動時やレベル遷移時に強制ロード 起動直後の暗転やローディング画面が長くなる ユーザのストレスが貯まるだけでなく 普段の開発効率も下がる! やばい!!!
◯◯◯ Manager あるある問題 Subsystemの影響範囲は良くも悪くも広いので 作ろうとしている実装・設計をよく考えることも大事 ● ◯◯◯ Manager がそもそも必要なのか? ● ● 超限定的なレベルでしか使わない機能なら Actorで十分なのでは? ◯◯◯ Manager Manager とかになっていないか? ● イベントドリブンの設計にすることで Manager間の依存度を下げられないか?
ここまでのまとめ Subsystemを活用することで 使いやすい ◯◯◯ Manager を 効率良く作成できます! 更に複数人での作業 や 参照関係の整理にも有用です ただし、下準備で C++ が少し必要です (個人的には Unreal C++ を触る / 勉強するいいキッカケになる気がします) 万能な機能ではなく、注意するべき部分もあります とはいえ、非常に強力な機能なので 特に中規模・大規模プロジェクトでは是非導入をご検討ください!
Gameplay Ability System ( GAS )
よくあるトラブル 1つのBPに実装が集中してしまった! 管理が大変だし作業分担もできない! Actor, Component, Level で実装を分割したが アセット間の参照関係が複雑になってしまった! ● 不要な処理・ロードが発生 ● 要素の ON / OFFが気軽にできない
そんな時に役立つのがGAS! ジャンプ、攻撃、回復など単発の行動を アビリティという単位で実装・アセットを管理するための機能 Fortnite や UE5のデモ(古代の谷) でも活用されているシステム 近接攻撃用のスキルを使用可能に
GASのいいところ ① すこし下準備は必要ですが BPによる実装をAsset単位で分けることが可能! 仕組み上、実装のつけ外しも簡単!
GASのいいところ ② アビリティの実行が簡単な上に 実行の可否判定、キャンセルなどの管理をタグだけで可能! 大量のフラグ、判定処理からの開放 攻撃中? ダメージ中? NO YES リクエストを拒否 攻撃アビリティの実行をリクエスト
GASのいいところ ③ いろいろと下準備は必要ですが Data Asset のように データドリブンで機能を追加・拡張可能! 要素の量産や複数人作業で便利!
データだけで何ができるのか? の例 ● ● ● ● 再生するモーション、エフェクト サウンドなどの指定 スキル発動時に生成するActorの指定 キャラクターのパラメータ管理 スキル発動時の 攻撃力・回復・バフ・デバフなどで 使用する計算式の設定 ● ● レベルに応じたダメージの増加度合いなど スキル発動の可否判定に使用する タグ・パラメータなどの設定 ● ● クールタイム ダメージ中は攻撃不可 などなどなどなど
GASのいいところ ④,⑤ キャラクタ側 から GAS側にアクセス・干渉しづらい仕様なので 参照関係を一方通行にしやすい( GAS側からアクセス・干渉する流れ ) ネットワーク対応を考慮したフレームワーク!
なんとなく凄そうだけど むずかしそう…?
GASのわるいところ 色んなことができるシステムである反面 様々な機能が絡み合うので覚えることが多く、比較的難しいシステム C++もある程度必要に… ● ● ● ● ● ● ● GamePlay Ability Ability System Component GamePlay Tag Gameplay Effect Gameplay Attribute Gameplay Task Gameplay Event 今日もGASの気持ちが分からなかった猫の 様子
いきなり全部やろうとするのはオススメしません! GASの全機能を活用することは必須ではありません! 基本機能を使うだけでも非常に便利! ● ● ● ● ● ● ● GamePlay Ability Ability System Component GamePlay Tag Gameplay Effect Gameplay Attribute Gameplay Task Gameplay Event ● ● ● ● 実装をAsset単位で分離 データドリブン 処理の実行可否の判定 の自動化 処理の実行状況の管理 (開始・実行中・終了・ キャンセル) などなど
実際にどう便利なのかを 実装例を交えて解説!
攻撃やスキル系の例は多くあるので… 攻撃処理をリクエスト ヒストリア技術ブログ [UE4]GameplayAbilitySystemでコンボ攻撃を作る
ギミック管理でGASを使う方法を紹介!
ギミック管理で GASを使うメリットは?
Gameplay Tagを使ったやり取りができる 左:Ability.Gimmick.Run を持つ Ability を持っているなら実行して下さい 右:手持ちの Ability は その Tagを持っているの実行します!
Gameplay Tag について 階層的にタグを構築できる機能で、エディタ上で簡単に設定・追加可能 GAS専用機能ではなく様々な箇所で使用可能。フィルタリング機能が神
Gameplay Tag で リクエストするメリット 安全に使えるだけでなく、拡張性が高い! 列挙型も便利ですが、頻繁に項目が追加・変更される場合は不向き 特にBPとC++が混在するプロジェクト
Gameplay Tag & GAS を使うメリット 処理の実行可否・分岐を全てGASに任せられる!
GASのいいところ ② (振り返り) アビリティの実行が簡単な上に 実行の可否判定、キャンセルなどの管理をタグだけで可能! 大量のフラグ、判定処理からの開放 攻撃中? ダメージ中? NO YES リクエストを拒否 攻撃アビリティの実行をリクエスト
G GA_Open tag : Gimmick.Run GA_Close tag : Gimmick.Stop GAS - Man
そのTagを持つAbilityを 見つけたから実行するわ! GA_Open G Gimmick.Run でリクエスト tag : Gimmick.Run GA_Close tag : Gimmick.Stop
「Run用のAbilityを実行中」 用のタグを追加したで! GA_Open G tag : Gimmick.Run State.Running GA_Close tag : Gimmick.Stop
今は実行中やから リクエストしてもアカンで! G GA_Open tag : Gimmick.Run State.Running Gimmick.Run でリクエスト GA_Close tag : Gimmick.Stop
Run用のAbilityが終わったから タグを外すで! GA_Open G tag : Gimmick.Run GA_Close tag : Gimmick.Stop
GAS と Gameplay Tag の 設定を調整するだけで これができちゃう!
そのTagを持つAbilityを 見つけたから実行するわ! G Gimmick.Run でリクエスト GA_Explode tag : Gimmick.Run GA_Close tag : Gimmick.Stop
\ /
処理の差し替えも簡単! データドリブン最高!
GAS の つかいかた
下準備: Gameplay Abilities プラグインを有効に
下準備(…ここだけC++使います!) 新規のBlueprint Function Library ( C++ ) を追加 ( 既に作成済みならそれを使えばOK )
.h 側
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "AbilitySystemComponent.h"
#include "MyBlueprintFunctionLibrary.generated.h"
UCLASS()
class ACTIONRPG_API UMyBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
UFUNCTION(BlueprintCallable, meta = (DefaultToSelf = "Target"))
static void GiveAbilityToComponent(AActor* Target, UAbilitySystemComponent* AbilitySystem,
TArray<TSubclassOf<class UGameplayAbility>> AbilityList);
};
.cpp 側
#include "MyBlueprintFunctionLibrary.h"
void UMyBlueprintFunctionLibrary::GiveAbilityToComponent(AActor* Target, UAbilitySystemComponent* AbilitySystem,
TArray<TSubclassOf<class UGameplayAbility>> AbilityList)
{
if (AbilitySystem && Target)
{
int32 inputID(0);
if (AbilityList.Num() > 0)
{
for (auto Ability : AbilityList)
{
if (Ability)
{
AbilitySystem->GiveAbility(FGameplayAbilitySpec(Ability.GetDefaultObject(), 1,
inputID++));
}
}
}
AbilitySystem->InitAbilityActorInfo(Target, Target);
}
}
プロジェクト側の .Build.cs PrivateDependencyModuleNames に "GameplayAbilities" を追加 例: PrivateDependencyModuleNames.AddRange( new string[] { "GameplayAbilities" } );
ギミック制御・管理用のTagを追加 Gameplay Tagの追加方法は3通り ● ● ● Project Settings .ini ファイル Data Table アセット 公式ドキュメント:Gameplay Tag
実行するアビリティ用BPの作成
Ability Tags どのGameplay Tagで リクエストされたら実行するかを ここで設定 GA_Open tag : Ability.Gimmick.Run ここのUIからTagを新規追加することも可能
Activation Owned Tags Ability実行中に ギミック側のBPが持つ AbilitySystemComponent( ASC ) に 付与するGameplay Tagを設定 GA_Open tag : Ability.Gimmick.Run Gimmick.State.Running
Activation Blocked Tags ギミック側のBPが持つ ASC に付与されているTagのチェック用 ここで設定したTagが付与されていたら このAbilityの実行リクエストを拒否 G GA_Open tag : Ability.Gimmick.Run Gimmick.State.Running
ギミックが行う挙動(ドアの開閉)の実装に関しては割愛 EndAbilityは必ず呼ぶこと! (この例だと、Cast失敗時にも呼ぶべき)
ギミック側のBP AbilitySystem Component (ASC) を追加 GASに関する様々な処理は このComponentを介して実行される
ギミック側のBP 作成した Ability の Class を ASC に 登録 下準備で作った C++製 BPノード Gameply Ability の Class Reference の配列
ASC に Ability を登録しなかった場合 そのTagを持つ Abilityは持ってないで? G Gimmick.Run でリクエスト
ギミックへのリクエストをするBP ギミック側のBPが持つ ASC に対して Try Activate Abilities by Tag を使って リクエストを発行 ↑ 変数化可能
TagではなくClass直指定でリクエストも可能 Try Activate Ability by Class ノード より明確にリクエストしたい場合はこちらを使う ASC に 登録していない Ability は実行されない仕様は Tag 版と同じ
ここまでのまとめ GAS と Gameplay Tag の設定を調整するだけで ギミック や キャラクタ などの挙動・処理を変えることが可能に 取り扱うデータ・条件が多いプロジェクトでは特に強力! リクエストを送信・受信側の両方の実装がシンプルに
実装の分離・分担目的でも Ability側に実装を移すことで 1つのBPに実装・データが集中することを回避 複数人での作業分担、参照関係の整理などのメリット GA_Jump GA_Step GA_Damage GA_Attack_00 GA_Attack_01 ● ● ●
まだまだ序の口… GAS には他にも沢山の便利機能があります! 基本的な使い方に慣れてきたら是非挑戦してみてください! ● ● ● ● ● ● ● ● GamePlay Ability Ability System Component GamePlay Tag Gameplay Effect Gameplay Attribute Gameplay Task Gameplay Event ビヘイビアツリーとの連携
こちらの資料・記事も是非 公式ドキュメント・動画 ゲームプレイ アビリティ システム Action RPG のゲームプレイ アビリティ Using the Gameplay Ability System | Unreal Fest Europe 2019 Hero AI – Gameplay Abilities Meet Behavior Trees | Unreal Fest Europe 2019 Action RPG: Gameplay Abilities System | Inside Unreal A Guided Tour of Gameplay Abilities | Inside Unreal 非公式ドキュメント GASDocumentation ( 日本語訳 ) おかわりのアンリアルなメモ GameplayAbilitiesの使い方(セットアップ編) @O_Y_G さんによる GAS関連資料まとめ UE4 BPプロジェクトに Gameplay Ability System を導入する方法
本日のまとめ Data Asset を活用することで 作業の分担 と データドリブン型の開発を実現できる! Subsystem を活用することで 使いやすい ◯◯◯ Manager を 効率良く作成できる! 複数人での作業 や 参照関係の整理にも有用 Gameplay Ability System を活用することで データのみで挙動の制御 や 実行の可否を設定できる! 複数人での作業 や 参照関係の整理にも有用
メインテーマ 処理・作業を分散・分担しよう!
今回紹介した各機能を使わなくても UE4を使ったコンテンツ開発は十分できます しかし、複数人で作業する際や 一定以上の開発規模になってくると 作業分担・データドリブンを考慮することは必須です 今回話した内容以外にも、もっと色んな使い方があるはず! 面白い・有用な使い方を見つけたら共有し合いましょう!
CEDEC2021 講演アーカイブ公開! https://youtube.com/playlist?list=PLr_Cbd4sUDTzOM_Kv8WNeKjswrXjLRih5
Part 2の講演では、今日話した内容と関連する機能について話してます
UE4 Cinematic Dive Online (10/16(土) 14:00~17:30) https://www.unrealengine.com/ja/blog/epicgamesjapan-onlinelearning-14
UNREAL FEST EXTREME 2021 WINTER https://unrealengine.jp/unrealfest/extreme2021winter/