PaperSloth’s diary

主にゲーム開発関連についての記事を書きます。

UE4 個人開発メモ

最終更新日:2017/12/03

概要

 個人開発でのUE4のEditor Preference, Project Settings等のメモ
 随時更新していきます。
 基本はWindowsPC向けの内容。
 家庭用ゲーム機、アーケードゲーム、モバイル、XR(AR / VR)でも役立つ内容も含みます。
 各項目には確認時のバージョンを記載しています。
 バージョンが古かったり新しかったりすると
 項目がなくなったり、場所や名前が変わったりしている可能性があります。

環境

・Platform : Windows
・Unreal Engine4.17.2~
Visual Studio Community 2015


Project Settings

Windowタイトルの変更方法(UE4.17.2)

 WindowタイトルとはPC向けに作成した際のWidnowの左上に出るタイトルです。
f:id:PaperSloth:20171130003303p:plain

 何も指定していない場合はProject名が表示されます。

 設定は下図のProject - Description - Displayed
 「Project Displayed Title」から変更できます。
f:id:PaperSloth:20171130004532p:plain

 試しに"Example Window Name"と入れてみました。
f:id:PaperSloth:20171130004635p:plain

Application名の変更方法(UE4.17.2)

 上記Windowsタイトルとよく間違えやすいのがこれです。
 設定は下図のProject - Description - About
 「Project Name」から変更できます。
 デフォルトではUE4Gameと入っています。
f:id:PaperSloth:20171130005438p:plain

 よくWindowタイトルを変更しようとしますが、ここを変えても上手くいきません。
 この名前はタスクマネージャー等で表示されるアプリの名前です。
f:id:PaperSloth:20171130005618p:plain

 ちょっと図がわかりにくいのですがProject Nameがあって、その下にWindowTitleがくるようになっています。
 編集をしていない場合だと、UE4Gameの下にProject名がくるようになっています。
f:id:PaperSloth:20171130010129p:plain

シェーダーモデルの制限によるメモリ容量削減(UE4.17.2)

 設定は下図のPlatforms - Windows
 「Targeted RHIs」から変更できます。

 UE4Windows向けに作成している場合
 デフォルトのRHI(Rendering Hardward Interface)はDX10, DX11が有効になっています。
f:id:PaperSloth:20171130220108p:plain
 これをDX11(ShaderModel5)のみにすることで不要なシェーダーが減り、パッケージ容量を削減できます。
 ThirdPersonTemplate等で試してみてもほぼ全く変わらないのですが
 規模が大きく、マテリアルが増えるほど効果が現れやすい部分です。

 試しに自分のゲームで比較してみた結果
 DX10, 11だと242KBのシェーダー
f:id:PaperSloth:20171130221048p:plain
 DX11のみだと124KBと約半分の容量になりました。
f:id:PaperSloth:20171130221057p:plain

 このように数百KB程度だと微々たる差ですが、これが数百、数千のマテリアルとなると話が変わってきます。
 また、シェーダーも1つで数百MBだと半分ほどの容量になるのは大きな変化ですね。

パッケージング関連

 項目が多いので、細かく分けます。
 設定箇所はProject - Packaging以下のものになります。

PakFileの使用(UE4.17.2)

 「Use Pak File」にチェックを入れると有効になります。
 説明の前に図で見てもらうと分かりやすいと思います。
 Pak Fileを使用した場合
f:id:PaperSloth:20171130222234p:plain
 中には.pakの形式でContent以下のAssetが1つのデータに圧縮されています。

 Pak Fileを使用しない場合
f:id:PaperSloth:20171130222333p:plain

 Pakファイルの使用は容量の削減になり
 転送ファイル数が減るので配布時のダウンロードも早くなり
 ロードも早くなるため使用することを推奨します。
 容量の参考までに自分のプロジェクトで使用した場合の容量を載せておきます。
 使用した場合  :532MB
 使用しない場合 :786MB

パッケージの圧縮(4.17.2)

 「Create compressed cooked packages」にチェックを入れると有効になります。
 f:id:PaperSloth:20171203220605p:plain
 なお、このオプションの効果を有効にするにはUse Pak Fileにチェックを入れておく必要があります。
 容量の参考までに自分のプロジェクトで使用した場合の容量を載せておきます。
 使用した場合  :547MB
 使用しない場合 :950MB

 さて、パッケージの圧縮はDLで配信するPC向け等にはオススメですが、
 一部プラットフォームは注意が必要です。
 PlayStation 4の場合
  PlayStation 4 の圧縮と重複し、ファイル サイズは減らずにロード時間が長くなってしまいます。
 Nintendo Switchの場合
  ロード時間が早くなる場合と遅くなる場合があります。
 詳しくは下部の参考資料のリンクを見てください。


Editor Preference

Blutilityの有効化(UE4.17.2)

 BlutilitはBlueprintをEditor上で呼び出すことでお手軽にEditor拡張が出来る機能です。
 UE4.17.2現在は実験的な機能として提供されています。
 この機能に関しては不安定というよりは、機能がまだ足りないため実験的な機能なのだと思います。

 設定は下図のEditor Preference - General - Experimental - Tools
 「Editor Utility Blueprints(Blutility)」から有効に出来ます。
 有効にした際のEditorの再起動は不要です。
f:id:PaperSloth:20171130011354p:plain

EQS(Environment Querying System)の有効化(UE4.17.2)

 EQSはAIが目的に応じた位置を探す時に使われる機能です。
 この位置は動的に生成され、その中から最もスコアの高い位置を選択します。

 こちらも実験的な機能として提供されていますが
 EpicGamesの開発タイトルである「Robo Recall」でも採用されており、信頼性は高いです。

 設定は下図のEditor Preference - General - Experimental - AI
 「Environment Querying System」から有効に出来ます。
 有効にした際のEditorの再起動は不要です。
f:id:PaperSloth:20171130012353p:plain

参考資料

シェーダーモデルの制限によるメモリ容量削減
バイキング様のスライド63ページ付近に該当箇所の説明があります。
マジシャンズデッド ポストモーテム ~マテリアル編~ (株式会社Byking: 鈴木孝司様、成相真治様) #UE4DD

パッケージング関連
パッケージの圧縮によるプラットフォームごとの注意点等詳しくはドキュメントに載っています。
Unreal Engine | プロジェクトのパッケージ化

日記 第4回UE4何でも勉強会のLT に登壇してきました

イベントページはこちら
ue4allstudy.connpass.com


登壇内容は「Blueprint Tips 30選」です
資料はslidesharegithubにアップしました。

www.slideshare.net

GitHub - PaperSloth/Presentation: 登壇資料


公開した資料はslideshareでは標準でgifが動作しないため、githubにgif版をアップしました。
gif版の方がより正確に内容が伝わりやすくなっていると思います。


色々と登壇内容を考えたのですが、初心者向けにBlueprintの操作についてまとめた資料を目標に作成しました。
登壇時間が5分しかないということがすっぽり抜けており、当日は10個も紹介できませんでしたが。

登壇の0-5分前にgithubslideshareに公開できると勉強会が終わってからの作業もスムーズだと感じました。
また機会があればどこかで何かを話そうと思います。

UE4 外部ライブラリの使用方法について

この記事はUnreal Engine 4(UE4) Advent Calendar 2019の22日目の投稿記事です。
Unreal Engine 4 (UE4) Advent Calendar 2019 - Qiita


目次

環境

UE4.23.1
Visual Studio 2017 Community

結論

最初に結論だけを書きます。
Static Library, Dynamic-link Libraryどちらの場合も編集するのは .Build.cs です。
・共通(Static Libraryはこれで設定完了)

// インクルードファイルへのpath 情報を追加
// .h/.hpp ファイルを配置したディレクトリへのpathを記述
PublicSystemIncludePaths.Add(Path.Combine(LibraryPath, "include"));
// ライブラリへのpath 情報を追加
// .lib ファイルを格納したディレクトリへのpath を記述
PublicLibraryPaths.Add(Path.Combine(LibraryPath, "lib", "x64"));
// ライブラリをプロジェクトに追加
// .lib ファイルの名前を記述
PublicAdditionalLibraries.Add("LirbraryName.lib");


・Dynamic-link Library

// ライブラリをプロジェクトに追加
// .dll ファイルの名前を記述
 PublicDelayLoadDLLs.Add("LibraryName.dll");
// プロジェクトのパッケージジング情報に.dll の情報を追加し、ファイルコピー
// .dll ファイルを格納したディレクトリへのpath を記述
 RuntimeDependencies.Add(Path.Combine(LibraryPath, "lib", "x64");

概要

今回はUE4で外部のライブラリ(Static Library, Dynamic-link library)の使用方法について書きます。
使用するライブラリは自作した簡単なライブラリを使用します。
Static Libraryはint の足し算を行うだけのもの : ExampleLib
Dynamic-link Libraryはint の引き算を行うだけのもの : ExampleDll
この2つを用意しました。
わざわざライブラリ化する意味は全くありませんが、使用方法の参考例として用意しました。

ライブラリの作成方法についてはUE4の話から逸れるため、作成方法などについては省略します。
下記ドキュメントを参考にしてください。
チュートリアル: 作成と使用のスタティック ライブラリ (C++) | Microsoft Docs
Visual Studio でC++の C/dll の作成 | Microsoft Docs

Static Libraryの作成

設定等は大幅に省いてざっくりとコードだけ載せます。

こちらも設定等は省いてコードだけ。

UE4でのLibraryの使用方法

ようやくUE4の話に戻ります。
まずは新規にUE4プロジェクトを作成します。
f:id:PaperSloth:20191209003621p:plain


続いて使用するライブラリをそれぞれプロジェクトに紐付けるために適切なディレクトリに移します。
(ProjectRoot)\ThirdParty\ 以下にファイルを置くのが一般的でしょう。
ThirdPartyというフォルダは存在しないため、新規作成します。

例 :
(ProjectRoot)\ThirdParty\(LibraryName)\include\
(ProjectRoot)\ThirdParty\(LibraryName)\lib\(PlatformName)\

今回は以下のように配置しました。
・ Static Library
(ProjectRoot)\ThirdParty\ExampleLib\include\
(ProjectRoot)\ThirdParty\ExampleLib\lib\x64\

・Dynamic-link Library
(ProjectRoot)\ThirdParty\ExampleDll\include\
(ProjectRoot)\ThirdParty\ExampleDll\lib\x64

ライブラリに更新が入った時には
Generate Visual Studio project filesでプロジェクトを再生成しています。
これが正しいフローなのかどうかは疑問が残りますが、これでライブラリの更新は反映されます。

ライブラリのリンクについて編集するのは基本的に下記のファイルのみです。
(ProjectRoot)\Source\(ProjectName)\(ProjectName).Build.cs
今回の場合だと (ProjectRoot)\Source\LibrarySandbox\LibrarySandbox.Build.cs
コメント等を削除して、初期の記述状態は下記になります。

using UnrealBuildTool;

public class LibrarySandbox : ModuleRules
{
    public LibrarySandbox(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });

        PrivateDependencyModuleNames.AddRange(new string[] { });
    }
}

ライブラリの使用準備にあたってThirdPartyへのFullPath取得のPropertyを追加します。

// Path使用のため追加
using System.IO;

public class LibrarySandbox : ModuleRules
{
    // 追加
    private string ThirdPartyPath
    {
        get { return Path.GetFullPath(Path.Combine(ModuleDirectory, "../../ThirdParty/")); }
    }
...
}

Static Libraryの使用方法

Static Libraryを使用するにあたっては下記へのファイル追加が必要です
・PublicSystemIncludePaths
・PublicLibraryPaths
・PublicAdditionalLibraries

includeファイルのディレクトリの追加、ライブラリへのpath の追加、ライブラリの追加です
今回の例では下記のようになります。

public class LibrarySandbox : ModuleRules
{
    ...
    public LibrarySandbox(ReadOnlyTargetRules Target) : base(Target)
    {
        ...
        PrivateDependencyModuleNames.AddRange(new string[] { });

        // 下記を追加
        string ExampleLibPath = Path.Combine(ThirdPartyPath, "ExampleLib");
        PublicSystemIncludePaths.Add(Path.Combine(ExampleLibPath, "include"));

        PublicLibraryPaths.Add(Path.Combine(ExampleLibPath, "lib", "x64"));
        PublicAdditionalLibraries.Add("ExampleLib.lib");
...
}

では実際に使用できるかコードを書いて確かめてみます。
GameModeのctorから呼び出してみます。

#include "LibrarySandboxGameModeBase.h"
#if PLATFORM_WINDOWS
#include "ExampleLib.h"
#include <memory>
#endif

ALibrarySandboxGameModeBase::ALibrarySandboxGameModeBase()
{
#if PLATFORM_WINDOWS
    const auto helloLib(std::make_shared<ExampleLib::HelloLib>());
    UE_LOG(LogTemp, Log, TEXT("Hello Static Library World : 1 + 2 = %d"), helloLib->Add(1, 2));
#endif
}

実行してみると無事に動作することが確認できました。

LogInit: FAudioDevice initialized.
LogLoad: Game class is 'LibrarySandboxGameModeBase'
LogTemp: Hello Static Library World : 1 + 2 = 3

手順としてはPublicSystemIncludePaths, PublicLibraryPaths, PublicAdditionalLibrariesに設定を記述するだけでプロジェクトから使用できるため比較的お手軽です。

Dynamic-link Libraryを使用するにあたっては下記へのファイル追加が必要です
・PublicSystemIncludePaths
・PublicLibraryPaths
・PublicAdditionalLibraries
・PublicDelayLoadDLLs
・RuntimeDependencies

includeファイルのディレクトリの追加、ライブラリへのpath の追加、ライブラリの追加、ライブラリのパッケージング時のコピー

今回の例では下記のようになります。

public class LibrarySandbox : ModuleRules
{
    ...
    public LibrarySandbox(ReadOnlyTargetRules Target) : base(Target)
    {
        ...
        PrivateDependencyModuleNames.AddRange(new string[] { });

        // 下記を追加
        string exampleDllRootPath = Path.Combine(ThirdPartyPath, "ExampleDll");
        PublicSystemIncludePaths.Add(Path.Combine(exampleDllRootPath, "include"));

        string exampleDllPath = Path.Combine(exampleDllRootPath, "lib", "x64");
        PublicLibraryPaths.Add(exampleDllPath);
        PublicAdditionalLibraries.Add("ExampleDll.lib");

        string exampleDllName = "ExampleDll.dll";
        string exampleDllFullPath = Path.Combine(exampleDllPath, exampleDllName);
        PublicDelayLoadDLLs.Add(exampleDllName);
        RuntimeDependencies.Add(exampleDllFullPath);
...
}

実際に使用できるかコードを書いて確かめてみます。
GameModeのctorから呼び出してみます。

#include "LibrarySandboxGameModeBase.h"
#if PLATFORM_WINDOWS
#include "ExampleDll.h"
#include <memory>
#endif

ALibrarySandboxGameModeBase::ALibrarySandboxGameModeBase()
{
#if PLATFORM_WINDOWS
    const auto helloDll(std::make_shared<ExampleDll::HelloDll>());
    UE_LOG(LogTemp, Log, TEXT("Hello Dynamic-link Library World : 2 - 1 = %d"), helloDll->Sub(2, 1));
#endif
}

実行してみるとエラーが出ます。
delayhlp.cpp の中でKernelBase.dllで例外が発生したと表示されます。
これはBinaries/Win64/ 以下にdll が存在せずEditorから実行できません。
ですのでdll をBinaries/(Platforms)/以下にコピーするコードを追加します。

using System;
using System.IO;

public class LibrarySandbox : ModuleRules
{
    ...
    public LibrarySandbox(ReadOnlyTargetRules Target) : base(Target)
    {
        ...
        string exampleDllName = "ExampleDll.dll";
        string exampleDllFullPath = Path.Combine(exampleDllPath, exampleDllName);
        PublicDelayLoadDLLs.Add(exampleDllName);
        RuntimeDependencies.Add(exampleDllFullPath);
        CopyDll(exampleDllName, exampleDllFullPath);
    }

    // Binaries以下にdll をコピーする
    private void CopyDll(string dllName, string dllFullPath)
    {
        if (!File.Exists(dllFullPath))
        {
            Console.WriteLine("file {0} does not exist", dllName);
            return;
        }
        string binariesDir = Path.Combine(ModuleDirectory, "../../Binaries/Win64/");
        if (!Directory.Exists(binariesDir))
        {
            Directory.CreateDirectory(binariesDir);
        }
        string binariesDllFullPath = Path.Combine(binariesDir, dllName);
        if (File.Exists(binariesDllFullPath))
        {
            File.SetAttributes(binariesDllFullPath, File.GetAttributes(binariesDllFullPath) & ~FileAttributes.ReadOnly);
        }
        // try catchでくくっていないとパッケージ作成時にこけます
        try
        {
            File.Copy(dllFullPath, binariesDllFullPath, true);
        }
        catch (Exception ex)
        {
            Console.WriteLine("failed to copy file: {0}", dllName);
        }
    }
}


これで無事に動作することが確認できました。

LogInit: FAudioDevice initialized.
LogLoad: Game class is 'LibrarySandboxGameModeBase'
LogTemp: Hello Dynamic-link Library : 2 - 1 = 1

手順としてはPublicSystemIncludePaths, PublicLibraryPaths, PublicAdditionalLibraries, に設定を記述することに加えて
PublicDelayLoadDLLs, RuntimeDependenciesが追加されました。
RuntimeDependenciesは記述がなくとも動作しますが
これを設定していないとプロジェクトのパッケージング時にそのフォルダにDLLがコピーされないため
DLLがなくて動作しないという問題を避けることができます。

パッケージング後のディレクトリはWindows PC向けパッケージでは下記のようになります。
WindowsNoEditor\LibraySandbox.exe
WindowsNoEditor\LibrarySandbox\ThirdParty\ExampleDll\lib\x64\ExampleDll.dll


最後にbuild.cs と使用例を全文載せておきます。


UE4 C++のバージョンを変更する方法

環境

UE4.23.1
Visual Studio Comuunity 2019

UE4Unreal C++環境について

リリース時のUE4Unreal C++C++11をベースに一部C++14で開発されていました
jp docだとC++11, us docだとC++14と記載されています。
Coding Standard | Unreal Engine Documentation
コーディング標準 | Unreal Engine ドキュメント

しかし、現在はC++17以降も使用できるようになっています。
ちょうどUE4.22でVisual Studio 2015のサポートを(基本的には)終了した頃からでしょうか。
※基本的にはと書いたのはtarget.csにCompilerの指定を書けばVS2015でも動作するためです。

おさらいとして、UE4で使用するIDEの変更方法についての記事も載せておきます。
papersloth.hatenablog.com

UE4C++のバージョン指定方法

UE4で使用されるC++のバージョン指定はProjectのtarget.cs内に記述をすることで変更が可能です。

以下はプロジェクト作成時の target.csです

using UnrealBuildTool;
using System.Collections.Generic;

public class ProjectNameTarget : TargetRules
{
    public ProjectNameTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Game;

        ExtraModuleNames.AddRange(new string[] { "ProjectName" });
    }
}

C++のバージョン指定は下記を追記するだけで行なえます。
CppStandard = CppStandardVersion.{任意のバージョン};

using UnrealBuildTool;
using System.Collections.Generic;

public class ProjectNameTarget : TargetRules
{
    public ProjectNameTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Game;

        ExtraModuleNames.AddRange(new string[] { "ProjectName" });
        CppStandard = CppStandardVersion.Cpp17; //C++17を指定
        // C++14の場合 -> CppStandardVersion.Cpp14
        // 最新のC++の場合 -> CppStandardVersion.Latest
    }
}


以上です!
お好きなIDEC++バージョンで快適な開発ライフを!

UE4 Lighting Channelsについて

環境

UE4.23.1

Lighting Channelsについて

通常のLightingではChannel 0番のみが使用されており、特に意識する必要はありません。
Lighting Channelsを使うと独特で面白い絵作りや
広いワールドに対してエリアごとに全く異なるライティングの絵作りなど
特徴的な表現ができるようになります。
ただし、パフォーマンスにも影響を与えるためプロファイリングをとって注意して扱ってください。
f:id:PaperSloth:20191112212109p:plain

設定方法

Lighting Channelsの設定が可能なのは
・Directional Light
・Point Light
・Spot Light
・Rect Light
上記4つになります。

・Sky Light についてはLighting Channelsが設定できないため、注意が必要です

設定箇所は各Lightの 「Light -> Lighting Channels」にあります。
f:id:PaperSloth:20191112211706p:plain
デフォルトでは0のみが使用されています。

Channelは単一でも組み合わせでも設定が可能です。
f:id:PaperSloth:20191112213104p:plain

さて、Channelを設定しても画面上で特に変化は起きないと思います。
Lighting ChannelsはLightだけでなく、各メッシュごとの設定が必要で
「Static Mesh, Skeletal Meshごとに設定が必要です」
設定箇所はLight同様に「Light -> Lighting Channels」です。
f:id:PaperSloth:20191112212436p:plain


さらにもう1点注意が必要なのが「影」です。
Shadow Castするのは同一のChannelのメッシュ同士のみです。

Channel 0に白、1に赤、2に青のChannelを設定した
Directional Lightを3つ配置しました。
言葉にすると分かりにくいので、下図をご覧ください。
f:id:PaperSloth:20191112212711p:plain

まずステージ全体のStatic Mesh(床)はLight Channel 0です。
そのため、0と0 & 1と書かれたキャラクターの影のみが落ちます。

続いてChannel 1と書かれたキャラクターと床は1の赤いライトのみが適用され
2と書かれたキャラクターと床には2の青いライトのみが適用されるようになっています。


以上の特性に気をつけて、色々な絵作りをやってみてください!
以上です。

UE4 Projectから直接参照されていないuassetをパッケージに含める方法

環境

UE4.23.1

登録方法と概要

Project内では通常使用されないが、特殊なケースで使用したい場合に使えると思います。
例:開発用に外部のjsoncsvからパス指定でロードするアセットを変更して確認を行いたい場合
例:ロードしたいアセットがパッケージに上手く紐付かずやむを得ず暫定対応でロードさせたい場合
...etc
なんにせよ通常の開発では使わないものと思いますし
ずっと登録したままだと無駄にパッケージサイズが肥大化するため注意が必要です。

注意点として、この方法が使えるのはContentフォルダ以下に配置された.uassetに限ります。

方法としては簡単で
「ProjectSetting -> (Project)Packaging -> (Packaging)Additional Asset Directories to Cook」
以下に参照先のディレクトリを登録するだけです。
f:id:PaperSloth:20191112205054p:plain

UE4 Blueprintでdelegateを引数で使用する方法

環境

UE4.23.0

Delagateとは

Blueprintから使用するDelegateではSetTimer by EventやEvent DispatcherにBindする際に使用するEvent等があります。
今回はSet Timer by Eventで例を作成していますが
Event DIspatcherを使用した場合でも同様にBindすることが可能です。
f:id:PaperSloth:20191023021502p:plain

関数やMacroからは通常delegateを引数に追加することができません。
f:id:PaperSloth:20191023021703p:plain

MacroでDelegateを使用する方法

MacroにはWildcardという型があり、それを引数にすることで使用できます。
f:id:PaperSloth:20191023022703p:plain

C++でいうところのTemplateのようなものだと理解してもらえればと思います。
WildcardはBlueprintのforeachloopノード等で使用されています。

例えば1秒後にEventを実行するようなMacroを組む場合は下記のような形になります。
f:id:PaperSloth:20191023022747p:plain

あとはEventをWildcardに接続すると下図のようにWildcard型がDelegateとして認識されます。
f:id:PaperSloth:20191023022909p:plain

実行結果は通常のSetTimer by Eventで1.0を設定したときと同じ結果を得ることができました。
f:id:PaperSloth:20191023023043p:plain

関数/MacroでDelegateを使用する方法

続いて関数とMacroのどちらでもDelegateを使用できる方法を紹介しますが
ハック的なやり方のため、動作の安全性については保証できません

関数またはMacroのノードグラフからSet Timer by Eventノードを呼び出します。
続いて、Event PinをInputに接続することでDelegateを入力引数として登録することができます。
f:id:PaperSloth:20191023023923g:plain
f:id:PaperSloth:20191023024028p:plain

動画ではMacroで説明を行いましたが、関数の場合でも同様の操作でDelegateの登録が可能です。
動作についても問題なく行えます。
f:id:PaperSloth:20191023024227p:plain


以上、UE4のちょっとしたハック的なテクニックでした。

実は過去記事でもこちらをサラッと紹介していました。
「FunctionLibraryに登録してFade終了後のCallback関数も登録可能にする」のところでFunction Libraryにdelegateを登録しています。
papersloth.hatenablog.com