アンリアルエンジン用のクエストおよびダイアログエディターの作成:パート2技術的側面

画像



こんにちは私の名前はドミトリーです。 私は趣味としてアンリアルエンジンでコンピューターゲームを作っています。 今日は、クエストとダイアログを編集するためのプラグインについて話し続けます。 前回の記事でプラグインの使用方法を説明しましたが、今日はプラグインがゲームの世界およびそのインターフェースと対話できるようにするために知っておくべきことを説明します。



まず、プラグインをプロジェクトに接続するために、StoryGraphPluginフォルダーをプラグインフォルダーからフォルダー「プロジェクトのディレクター」\ pluginsに転送する必要があります。 Unrealエンジンのバージョンが一致しない場合、ゲームを再コンパイルする必要があります。



ただし、StoryGraphアセットを作成した後でも、何らかの操作を行う必要があります。 マップ上に配置するすべてのプロットオブジェクトは、特定のオブジェクトから派生する必要があります。それらのリストを次に示します。



1)ACharecter_StoryGraph-キャラクターの基本クラスには鈍いメソッドがあります:

ChangeState-この場合、メソッドはキャラクターの状態を生きている状態から死んだ状態に変更します。つまり、ブルートゥースでは、キャラクターが死んだときに状態を切り替える関数を作成する必要があります。

OpenDialog()-このキャラクターとの対話を開始するために呼び出す必要があるブループリントメソッド。

GetObjectName()-StoryGraphで定義されたキャラクター名を返す鈍いメソッド。レベルに複数のStoryGraphオブジェクトを配置し、それぞれに異なるキャラクター名がある場合、関数は最初のStoryGraphから名前を返します。

GetMessegeFromStoryGraph()-StoryGraphでメッセージ送信ノードがアクティブ化されると、鈍いイベントが発生し、このキャラクターはメッセージをこのキャラクターに送信します。



2)APlaceTrigger_StoryGraph-トリガーの基本クラスには、鈍いメソッドがあります。

GetPlaceTriggerType()-トリガーが機能するモードを確認する必要があります。

ChangeState()-ACharecter_StoryGraphのメソッドと同様に、他の状態(UnActive、Active)のみ。 UnInteractiveトリガーモードで使用する必要があります。

アクティブ化()-この方法は、非インタラクティブモードでは機能せず、他の2つのモードで機能するため、前の方法とは異なります。 インタラクティブモードでは、トリガーをアクティブにし、AdvanceInteractiveモードでは、トリガーと対話するためのダイアログボックスを開きます。

前のクラスと同様に、このクラスにはGetObjectName()およびGetMessegeFromStoryGraph()という鈍いメソッドがあります。



3)AInventoryItem_StoryGraph-在庫のプロットサブジェクトの基本クラス。 上記のGetObjectName()およびGetMessegeFromStoryGraph()に加えて、このクラスにはメソッドがあります

PickUp()-アイテムをキャラクターのインベントリに移動します。



4)AOtherActor_StoryGraph-上記のカテゴリに属さないオブジェクトのクラス。 GetObjectName()およびGetMessegeFromStoryGraph()のみに独自のメソッドはありません。



5)ALevelScriptActor_StoryGraph-LevelBluprintの基本クラスには1つのブループリントイベントがあります

GetMessegeFromStoryGraph()-ノードがアクティブになったときに呼び出され、レベルブループリントにメッセージを送信します



StoryGraphは、マップ上のオブジェクトに加えて、インターフェイス要素とやり取りします。それらのリストを次に示します。



1)AHUD_StoryGraph-HUDの基本クラス。 メソッドがあります:

EndGame()-Game Overノードがトリガーされたときに呼び出される鈍いイベント。

PrintQuestPhaseOnScreen()-ノードがトリガーされたときにトリガーされるブループリントイベント画面にクエストフェーズを印刷します。

OpenDialogEvent()-文字の1つがOpenDialog()を呼び出すと、鈍いイベントがトリガーされます。

OpenPlaceTriggerMessagesEvent()-トリガーについても同じこと。

ChangeLocalization()-ゲームの言語を変更します。

GetCurrentLocalization()-現在の言語を返します。



2)UGameScreen_StoryGraphWidget-ゲーム画面にあるウィジェットの基本クラス。 このウィジェットには、プレイヤーのメッセージと、いわゆるDefaultAnswerが表示されます。プレイヤーは、キャラクターが



3)UJurnal_StoryGraphWidget-ウィジェットは現在アクティブなクエストを表示します。



4)URadar_StoryGraphWidget-レーダーはGameScreenウィジェットに配置する必要があり、目標を表示します



5)UDialog_StoryGraphWidget-トリガーと対話するためのダイアログボックスまたはウィンドウを表示します。



6)UInventory_StoryGraphWidget-ウィジェットには、プロット項目が配置されているインベントリが表示されます。



その後、すべてが正常に機能します。



問題点



次に、このプラグインを作成するために解決しなければならなかった問題について説明します。



最初の問題は、Unreal Engineのレベルがクローズドシステムであることです。レベルにあるオブジェクトのすべてのポインターはレベルのオブジェクトを指している必要があり、レベル外のオブジェクトはレベルのオブジェクトを指すポインターを持つことができません。 StoryGraphオブジェクトはレベルの外側にあるため、これは問題ですが、そのオブジェクトを何らかの方法でレベルオブジェクトに移動する必要があります。 幸いなことに、Unrealエンジンにはいわゆるレイジーポインター(TAssetPtr)があります。 それらは、現在ロードされていないオブジェクトを参照できるため、怠areです。また、それらを使用すると、外部のオブジェクトからレベルオブジェクトを参照できます。



私にとって2番目の問題は、グラフオブジェクト(UEdGraph)をゲームで使用できないという事実でした。 つまり、ゲームはコンパイルとパックさえありますが、このゲームを実行しようとすると、エラーでクラッシュします。 したがって、ノードを配列に配置し、グラフ上に「アダプターオブジェクト」UProxyNodeBaseを配置します。これは、エディターでの編集時にノードをメソッド呼び出しにリダイレクトするだけです。 また、このオブジェクト自体はエディターモジュールにあるため、ゲームをパックするときに考慮されません。



さて、プラグインをすでに作成したときに、開発モードでコンパイルして、これを取得しようとしました:



間違い
UE4-StoryGraphPluginRuntime.lib(Module.StoryGraphPluginRuntime.cpp.obj) : error LNK2005: "void * __cdecl operator new(unsigned __int64)" (??2@YAPEAX_K@Z) already defined in StoryTestProgect.cpp.obj

1>UE4-StoryGraphPluginRuntime.lib(Module.StoryGraphPluginRuntime.cpp.obj) : error LNK2005: "void * __cdecl operator new(unsigned __int64,struct std::nothrow_t const &)" (??2@YAPEAX_KAEBUnothrow_t@std@@@Z) already defined in StoryTestProgect.cpp.obj

1>UE4-StoryGraphPluginRuntime.lib(Module.StoryGraphPluginRuntime.cpp.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPEAX@Z) already defined in StoryTestProgect.cpp.obj

1>UE4-StoryGraphPluginRuntime.lib(Module.StoryGraphPluginRuntime.cpp.obj) : error LNK2005: "void __cdecl operator delete(void *,struct std::nothrow_t const &)" (??3@YAXPEAXAEBUnothrow_t@std@@@Z) already defined in StoryTestProgect.cpp.obj

1>UE4-StoryGraphPluginRuntime.lib(Module.StoryGraphPluginRuntime.cpp.obj) : error LNK2005: "void * __cdecl operator new[](unsigned __int64)" (??_U@YAPEAX_K@Z) already defined in StoryTestProgect.cpp.obj

1>UE4-StoryGraphPluginRuntime.lib(Module.StoryGraphPluginRuntime.cpp.obj) : error LNK2005: "void * __cdecl operator new[](unsigned __int64,struct std::nothrow_t const &)" (??_U@YAPEAX_KAEBUnothrow_t@std@@@Z) already defined in StoryTestProgect.cpp.obj

1>UE4-StoryGraphPluginRuntime.lib(Module.StoryGraphPluginRuntime.cpp.obj) : error LNK2005: "void __cdecl operator delete[](void *)" (??_V@YAXPEAX@Z) already defined in StoryTestProgect.cpp.obj

1>UE4-StoryGraphPluginRuntime.lib(Module.StoryGraphPluginRuntime.cpp.obj) : error LNK2005: "void __cdecl operator delete[](void *,struct std::nothrow_t const &)" (??_V@YAXPEAXAEBUnothrow_t@std@@@Z) already defined in StoryTestProgect.cpp.obj

1>UE4-StoryGraphPluginRuntime.lib(Module.StoryGraphPluginRuntime.cpp.obj) : error LNK2005: "void __cdecl UELinkerFixupCheat(void)" (?UELinkerFixupCheat@@YAXXZ) already defined in StoryTestProgect.cpp.obj

1>UE4-StoryGraphPluginRuntime.lib(Module.StoryGraphPluginRuntime.cpp.obj) : error LNK2005: "bool const GIsDebugGame" (?GIsDebugGame@@3_NB) already defined in StoryTestProgect.cpp.obj

1>UE4-StoryGraphPluginRuntime.lib(Module.StoryGraphPluginRuntime.cpp.obj) : error LNK2005: "class FFixedUObjectArray * & GObjectArrayForDebugVisualizers" (?GObjectArrayForDebugVisualizers@@3AEAPEAVFFixedUObjectArray@@EA) already defined in StoryTestProgect.cpp.obj

1>UE4-StoryGraphPluginRuntime.lib(Module.StoryGraphPluginRuntime.cpp.obj) : error LNK2005: "bool GIsGameAgnosticExe" (?GIsGameAgnosticExe@@3_NA) already defined in StoryTestProgect.cpp.obj

1>UE4-StoryGraphPluginRuntime.lib(Module.StoryGraphPluginRuntime.cpp.obj) : error LNK2005: "wchar_t * GInternalGameName" (?GInternalGameName@@3PA_WA) already defined in StoryTestProgect.cpp.obj

1>UE4-StoryGraphPluginRuntime.lib(Module.StoryGraphPluginRuntime.cpp.obj) : error LNK2005: "wchar_t const * const GForeignEngineDir" (?GForeignEngineDir@@3PEB_WEB) already defined in StoryTestProgect.cpp.obj

1>UE4-StoryGraphPluginRuntime.lib(Module.StoryGraphPluginRuntime.cpp.obj) : error LNK2005: "struct FNameEntry * * * GFNameTableForDebuggerVisualizers_MT" (?GFNameTableForDebuggerVisualizers_MT@@3PEAPEAPEAUFNameEntry@@EA) already defined in StoryTestProgect.cpp.obj








長い間、これらのエラーがどこから来たのか理解していませんでしたが、StoryGraphPluginRuntime.cppで置き換える必要があるすべてのものが判明しました



ここにあります:



 IMPLEMENT_PRIMARY_GAME_MODULE(FStoryGraphPluginRuntime, StoryGraphPluginRuntime, "StoryGraphPluginRuntime");
      
      





これについて:



 IMPLEMENT_MODULE(FStoryGraphPluginRuntime, StoryGraphPluginRuntime);
      
      





そしてそれは働いた。 しかし、その後、プラグインを配送モードでコンパイルし、エラーが再び発生したかったのですが、残念ながらそれらを保存しませんでしたが、本質は「;」を入れなかったことです さらに、コンパイラはエンジン自体のファイルを指しています。 一般的に、すべてが再びシンプルになりました。 ログを表示するには、新しいカテゴリを宣言する必要があります。これは次のように行われます。



 DECLARE_LOG_CATEGORY_EXTERN(StoryGraphPluginRuntime, All, All) DEFINE_LOG_CATEGORY(StoryGraphPluginRuntime)
      
      







しかし、Development and Development Editorではすべてがセミコロンなしで機能しますが、Shippingモードでは次のように記述する必要があります。



 DECLARE_LOG_CATEGORY_EXTERN(StoryGraphPluginRuntime, All, All); DEFINE_LOG_CATEGORY(StoryGraphPluginRuntime);
      
      





そして、エラー時のコンパイラがこれらの行を参照するのではなく、単にエンジンライブラリを参照するという事実によって、すべてが悪化しています。



それだけです



ここにソースがあります

デモへのリンク



また、以前の記事へのリンク: Unrealエンジン用のクエストおよびダイアログエディターの作成:パート1プラグインの説明



All Articles