このトピックでは、ランタイムのゲームプレイ中にプロジェクト内のエンティティを操作する方法の概要を説明します。
ランタイムでエンティティを操作する必要がある場合は、その大部分を Lua から実行する必要があります。
ストーリーを使用して、任意の種類のコンポーネント データの値を設定できます。Story Editor 内のエンティティ トラックにエンティティを追加する場合は、そのトラックを右クリックし、エンティティのコンポーネントによって維持される数値やブール演算データ値に対して新しいアニメーション トラックを追加できます。「Story Editor」も参照してください。
エンティティ システムがまだフローに公開されていなくても、カスタム フロー ノードを定義することで必要な任意の関数を公開することができます(「Lua でカスタム フロー ノードを作成する」を参照してください)。
コンポーネントを使用する場合は、コンポーネント マネージャ、コンポーネント ID、コンポーネント インスタンスの違いについて理解する必要があります。
コンポーネントのタイプごとに、該当するコンポーネント タイプの個々のインスタンスをすべて作成および更新するコンポーネント マネージャがエンジンによって作成されます。個々のコンポーネントを操作して、プロパティ値の取得と設定、関数の呼び出しなどを行う場合も、コンポーネント マネージャを使用します。
エンティティ内の各コンポーネントには、所有元のエンティティ内で一意の ID が設定されています。この名前は、エンティティが選択されている場合に、Property Editor に表示されます。次に示す Transform、Unit、Flow などが該当します。
この ID は、フローおよび Lua で特定のコンポーネントにアクセスして、プロパティ値の取得や設定を行う場合も使用します。
通常は、コンポーネントを識別できるように、文字列を使用して名前を付ける必要があります。ただし、これらの名前は内部ではハッシュ整数値として格納されます。Lua を使用していて、DataComponent.lookup() のような関数に ID を渡す必要がある場合は、文字列値またはハッシュを渡すことができます。文字列を渡すと、Stingray で自動的に変換されます。ただし、この変換は 1 方向に行われるため、DataComponent.instance_ids() などの関数を呼び出してエンジンから ID 名を取得した場合は、ハッシュ整数が返されます。
コンポーネント インスタンスは、エンジン内で実際にスポーンされた特定のエンティティに割り当てられている特定のコンポーネントを表します。一般に、コンポーネントのインスタンスは、次のいずれかの操作を行って対応するタイプのコンポーネント マネージャから取得されます。
重要: コンポーネント インスタンスは、取得元のフレーム内でのみ有効です。コンポーネント インスタンスを保存して、この後のフレーム内で使用することはできません。代わりに、コンポーネントのインスタンス IDを保存し、次にインスタンスが必要になった場合はこの ID を使用してもう一度ルックアップを行い、インスタンスを再取得します。
マネージャがユーザに対して個々のコンポーネントの操作を許可するには、関連するインスタンスを渡すか、関連するインスタンスを識別するエンティティおよびコンポーネント ID を渡します。マネージャがユーザにエンティティおよびコンポーネント ID を渡した場合、コンポーネント マネージャはユーザをルックアップします。たとえば、ユーザは DataComponent.set_property ( self, instance, key, value ) を使用してインスタンスのプロパティを設定するか、または DataComponent.set_property_by_id ( self, entity, id, key, value ) を使用して自分が指定したエンティティおよび ID からインスタンスを検索するように DataComponent を設定することができます。
コンポーネント ID を使用する方が便利な場合があります。ただし、同じコンポーネント マネージャに、指定したフレーム内の同じコンポーネント インスタンスについての呼び出しを複数回行う必要がある場合は、コンポーネント インスタンスを自分で検索して、追加ルックアップを呼び出す際のオーバーヘッド(少量)を回避する方が、一般には効率的です。
注: Lua のインスタンスとインスタンス ID が紛らわしいのは、両方とも数値として公開される点です。ID の内容と、実際のインスタンスに対する参照の内容を区別する必要があります。
Stingray Editor 内のレベルに配置したエンティティは、ランタイムでゲームにそのレベルをロードすると、自動的にスポーンされます。これらのエンティティは、まだ破壊されていない場合、レベルをロード解除するときに自動的に破壊されます。
さらに、EntityManager API から次の方法を使用して、ランタイムでエンティティをスポーンすることもできます。
ゲーム内のエンティティが不要となった場合は、EntityManager.destroy() を呼び出して破壊することができます。この関数は、上記の関数を呼び出すことでエンティティを動的に作成したか、またはレベルがゲームにロードされたときにエンティティが自動的にスポーンされたかどうかに関係なく、任意のエンティティに対して呼び出すことができます。
エンティティのリストを取得するには、主に次の 2 つの方法があります。
stingray.World.entities() は、現在「生きている」すべてのエンティティのリストを返します。これには、次のものが含まれます。
stingray.Level.entities() は、Stingray Editor で指定したレベルに配置され、そのレベルがロードされたときにスポーンされたすべてのエンティティのリストを返します。このリストには、Lua スクリプトによって、またはレベルがロード解除されたときに動的に破壊されたエンティティはいずれも含まれません。
Stingray Editor で行う場合と同様に、コンポーネントを動的に追加および削除することで、ゲームプレイ コードにエンティティを設定できます。これを実行するには、エンティティに対して作成または破壊するコンポーネントの種類に対応したのコンポーネント マネージャを使用します。EntityManager からこのコンポーネント マネージャを取得します。
たとえば、次のようになります。
function add_remove_components(entity) -- get the component managers local data_component_manager = stingray.EntityManager.data_component() local xform_component_manager = stingray.EntityManager.transform_component(SimpleProject.world) -- assign a new data component local id = "My New Data Component" local new_component_id = stingray.DataComponent.create(data_component_manager, entity, id) -- remove the first instance of a given component on an entity local xform_component_ids = { stingray.TransformComponent.instance_ids(xform_component_manager, entity) } if next(xform_component_ids) then stingray.TransformComponent.destroy(xform_component_manager, entity, xform_component_ids[1]) end -- remove a component instance with a specific ID local my_instance = stingray.DataComponent.lookup(data_component_manager, entity, "My New Data Component") if my_instance then stingray.DataComponent.destroy(data_component_manager, my_instance) end end
Lua を使用して、エンティティに割り当てたコンポーネントにアクセスすることができます。コンポーネントのインスタンスを取得したら、関連するコンポーネント マネージャ オブジェクトの API が、コンポーネントと対話する関数を提供します。
たとえば、次の関数は、TransformComponent を使用してエンティティのトランスフォーム コンポーネントからエンティティのワールド空間位置を取得する方法を示します。また、DataComponent マネージャ API を使用してカスタム データ コンポーネントに新しいデータ値を設定する方法も示します。
function change_component_values(entity) -- get the component managers local data_component_manager = stingray.EntityManager.data_component() local xform_component_manager = stingray.EntityManager.transform_component(SimpleProject.world) -- get component values from a transform component. -- there can only be one transform component on an entity, so instances() returns a single ID. local xform_component_id = stingray.TransformComponent.instances(xform_component_manager, entity) if xform_component_id then -- get its data values local world_matrix = stingray.TransformComponent.world_pose(xform_component_manager, entity) -- use the values print("Entity's world space transform: " .. tostring(world_matrix)) end -- set new data component values on a data component. -- there can be many different data components with different fields, so we -- need to iterate through a list of IDs to find the one that has the value we want to set. local data_component_ids = { stingray.DataComponent.instances(data_component_manager, entity) } for index, data_component_id in ipairs(data_component_ids) do -- check that the data component contains the field we want to change... local property_value = stingray.DataComponent.get_property(data_component_manager, entity, data_component_id, "custom_numeric_field") if property_value then -- set the new value stingray.DataComponent.set_property(data_component_manager, entity, data_component_id, "custom_numeric_field", 250) end end end