Lua でカスタム フロー ノードを作成する

Stingray エンジンに組み込まれているノード セットを拡張する、独自のカスタム フロー ノードを作成できます。Stingray のレベル編集ツールを操作しているレベル設計者およびゲームプレイ プログラマは、これらのカスタム ノードを、他の組み込みノードと同様に、レベルおよびユニットのフロー グラフにフックすることができます。ただし、ランタイムでゲーム内でカスタム ノードがトリガされるか、または評価された場合、これらは独自のカスタム Lua コードを呼び出します。

これらのカスタム ノードを使用すると、ゲームプレイに対する複雑なカスタム応答を作成したり、定義したカスタム Lua 関数をゲーム エンジンが実行するタイミングについてゲーム設計者が直接コントロールしたりできます。

注: Stingray SDK を使用して、Lua でなく C でカスタム フロー ノードを実装することもできます。詳細については、「C でカスタム フロー ノードを作成する」を参照してください。

カスタムの Lua フロー ノードを使用するには:

  1. フロー グラフでノードを評価するときに呼び出される Lua コールバック関数をいくつか記述します。以下の「コールバック関数の記述」を参照してください。

  2. 拡張子が .script_flow_nodes のデータ リソース ファイル内で、予測される入力の種類や生成される出力など、各ノードの特性を定義します。以下の「フロー ノードの定義」を参照してください。

  3. カスタム ノードがランタイムでトリガされるときはいつでも、ノードの定義が格納されている .script_flow_nodes ファイルと、そこから呼び出される関数が格納された Lua スクリプト ファイルが両方ともメモリにロードされていることを確認してください。これらのファイルの使用メモリは比較的少ない傾向があるため、ゲームの初期化中にこれらをすべてロードし、最終的にシャットダウンするまでロードしたままにしておくことをお勧めします。

    コールバック関数が含まれている Lua スクリプトを、Lua 環境の一部としてランタイムでロードする方法の詳細については、「ユーザ独自のスクリプト ファイルをロードして実行する」を参照してください。

    ゲーム内で .script_flow_nodes ファイルを取得する方法の詳細については、「コンテンツとリソースを管理する」を参照してください。

コールバック関数の記述

ゲーム エンジンが Lua 関数を呼び出すときは、常に 2 つの引数が渡されます。

Lua 関数は 1 つの値、つまり、フロー ノード環境設定の returns 設定で設定された名前およびタイプと一致するエントリが含まれているテーブルを返す必要があります。以下を参照してください。必要に応じて、引数内での受け渡しに使用されたのと同じテーブルを再利用できます。ノードの特定の評価中に戻り値を設定しない場合、フロー ノードはテーブルに最後に割り当てられた値を再利用します。値を設定しない場合は、テーブルを返す必要がありません。

たとえば、次の関数は、a および b という 2 つの入力値(いずれも浮動小数点数)を受け入れる方法と、sum という浮動小数点値をテーブルのメンバーとして返す方法を示します。

function FlowCallbacks.add(t)
    t.sum = t.a + t.b
    return t
end

この関数を呼び出して、そこから出力される浮動小数点値を処理するフロー ノード定義については、以下のクエリー例を参照してください。

フロー実行コンテキストを取得する

Lua 関数を記述するときに、フロー ノードが現在動作しているコンテキストについての詳細が必要になることがあります。たとえば、フロー ノードがユニット フローで使用することを目的としている場合は、現在評価中のフロー グラフを含むユニットの ID の情報が必要になることがあります。

この情報は、stingray.Application.flow_callback_context_world()stingray.Application.flow_callback_context_unit()stingray.Application.flow_callback_context_level()、および stingray.Application.flow_callback_context_entity() を呼び出して Lua Application から取得することができます。

Lua フロー ノードの定義

カスタム フロー ノードは、拡張子が .script_flow_nodes のデータ ファイル内で定義する必要があります。これらのデータ ファイルはプロジェクトのリソース フォルダ内の任意の場所に配置することができ、プロジェクト内の他のデータ ファイルと一緒に、必要に応じてメモリに出し入れすることができます。

プロジェクトには .script_flow_nodes ファイルを必要な数だけ含めることができるため、プロジェクトにとって適切な方法でノード定義を整理することができます。

.script_flow_nodes ファイル形式

.script_flow_nodes ファイルは、他のほとんどの Stingray データ リソースで使用されているのと同じ SJSON 形式です。詳細については、「SJSON データ形式について」を参照してください。

各ファイルには、最上位の nodes 要素が 1 つ含まれている必要があります。この要素の値には、それぞれ単一のフロー ノードを定義するオブジェクトのリストを指定する必要があります。これらのノード オブジェクトはそれぞれ、以下で定義された複数の環境設定パラメータを使用できます。

注: すべての名前は各フロー ノード内で一意である必要があります。たとえば、引数と同じノードの戻り値の両方に同じ名前を使用してはなりません。

たとえば、次のようになります。

// A sample .script_flow_nodes file.
nodes = [
    // demonstrates basic usage, calling a specified Lua function
    {
        name = "Tile Collapsed"
        category = "Tiles/Actions"
        visibility = "unit"
        function = "flow_callback_tile_collapsed"
        args = {
            collapsed_tile = "unit"
            other_unit = "unit"
        }
    }
    // your nodes list can have as many node definitions as you need.
    {
        name = "Wake Enemy"
        category = "AI"
        visibility = "all"
        function = "flow_callback_ai_enemy_awake"
        args = {
            enemy = "unit"
        }
    }
]

次のセクションでは、.script_flow_nodes ファイル内で定義されたフロー ノードに設定できるすべてのパラメータを示します。

name

フロー ノードの名前。

category

指定した場合、ノードはフロー エディタのこのカテゴリに表示されます。フロー ノードをサブカテゴリ内に表示するには、名前内でスラッシュを使用します。

visibility

指定した場合、フロー ノードは指定したオブジェクト タイプのフロー エディタにのみ表示されます。指定しない場合、または「all」に設定した場合、ノードはすべてのフロー エディタに表示されます。

使用可能な値は次のとおりです。

function

このパラメータを使用すると、フロー ノードには In という単一の入力イベントが割り当てられます。この In イベントがトリガされると、ゲーム エンジンはここで指定された Lua 関数を呼び出します。

この設定値には、次のいずれかを指定できます。

注: ノードごとに呼び出す必要がある Lua 関数を指定するには、function または function_map を使用する必要があります。単一のノードに両方のパラメータを使用しないでください。

function_map

このパラメータを使用すると、それぞれ別の Lua 関数を呼び出す、フロー ノードの代替トリガ イベントのリストを設定できます。

このパラメータには、サブリストのリストを含める必要があります。各サブリストには次の 2 つの項目を含める必要があります。

たとえば、次のようになります。

    // demonstrates usage of a function_map
    {
        name = "Giant Dust"
        function_map = [
            ["Armpit Left"  "CinematicGiant.cb_dust_armpit_left"]
            ["Armpit Right" "CinematicGiant.cb_dust_armpit_right"]
            ["Elbow Left"   "CinematicGiant.cb_dust_elbow_left"]
            ["Elbow Right"  "CinematicGiant.cb_dust_elbow_right"]
            ["Hip Left"     "CinematicGiant.cb_dust_hip_left"]
            ["Hip Right"    "CinematicGiant.cb_dust_hip_right"]
            ["Knee Left"    "CinematicGiant.cb_dust_knee_left"]
            ["Knee Right"   "CinematicGiant.cb_dust_knee_right"]
        ]
        args = {
            unit = "unit"
        }
    }

注: ノードごとに呼び出す必要がある Lua 関数を指定するには、function または function_map を使用してください。単一のノードに両方のパラメータを使用しないでください。

args

Lua 関数が受け入れる引数、およびそれらのタイプを定義するオブジェクトです。

各引数を指定する場合は、次のセクションに記載されている 2 つの方法を使用できます。いずれの方法でも、args オブジェクト内の各要素のキーは、フロー ノードに表示される入力変数スロットの名前と、Lua 関数に渡されるテーブル内の変数の名前を指定します。ただし、値の表現方法は 2 つの構文で異なります。

単純な構文

この構文の場合、args オブジェクト内の各要素の値は、フロー ノードに表示される入力スロットに接続できる変数のタイプといった引数のタイプです。このタイプに対して使用可能な値は、unitactormovervector3quaternionfloatboolstringinstance_idmaterialidlightmesh です。

たとえば、次のようになります。

        ...
        args = {
            setting = "float"
            character = "unit"
            position = "vector3"
        }
        ...

詳細な構文

この構文の場合、各要素の値はテーブルになります。このテーブルには次のエントリを含めることができます。

たとえば、次のようになります。

    // demonstrates the detailed syntax for argument definitions, with
    // default values and enumerations
    {
        name = "SetEnemyAttitude"
        args = {
            unit = "unit"
            hostility = {
                type = "enum"
                choices = [
                    "Neutral"
                    "Hostile"
                    "Friendly"
                    ]
                default = "Neutral"
            }
            courtesy = {
                type = "float"
                default = 0.5
            }
        }
    }

returns

Lua 関数の出力値を定義するオブジェクトです。

これらの戻り値はフロー ノードに出力変数スロットとして表示されます。つまり、他のフロー ノードの入力スロットに接続できます。

戻り値を宣言する構文は、上記の引数の単純な構文と同じです。

戻り値には上記の args 設定と同じタイプに加えて、event タイプを使用できます。event タイプを使用した場合、フロー ノードには out 変数コネクタではなく、out event コネクタが設定されます。対応するエントリが true に設定されているテーブルを関数が返すと、out event がトリガされます。複数の event エントリを true に設定することで、複数の out event をトリガできます。

下位互換性を維持するために、イベントを指定しない場合は、out という単一のイベントが自動生成されます。この out イベントは、Lua 関数が返されたテーブル内に記録した内容に関係なく、常に関数がテーブルを返した時点でトリガされます。

query

query パラメータを true に設定すると、フロー ノードは「クエリー ノード」になります。 クエリー ノードには入力イベントがありません。その代わりに、別のノードがクエリー ノードの出力データを必要としている場合は、オンデマンドで自動的にトリガされます。クエリー ノードは通常、ユニットの現在位置など、いつでも古くなる可能性のある変動しやすいデータを取得する場合に役立ちます。

たとえば、次のようになります。

    // demonstrates a basic query node
    {
        name = "Add"
        args = {
            a = "float"
            b = "float"
        }
        returns = {
            sum = "float"
        }
        query = true
        function = "FlowCallbacks.add"
    }