私は現在、ゲーム開発に戻るために小さな趣味のプロジェクトを作成しており、ECS(エンティティコンポーネントシステム)を使用してエンティティを構造化することにしました。ECSのこの実装は、次のように構成されています。
- エンティティ:私の場合
int
、コンポーネントのリストへのキーとして使用されるのは一意の識別子です。 - コンポーネント:データのみを保持します。たとえば、
Position
コンポーネントはx
andy
座標をMovement
保持し、コンポーネントはspeed
anddirection
変数を保持します。 - システム:コンポーネントを処理します。たとえば、
Position
およびMovement
コンポーネントを取得し、speed
およびdirection
を位置x
とy
座標に追加します。
これは問題なく動作しますが、今度はゲームにスクリプト言語の形式でスクリプトを実装したいと思います。以前のプロジェクトでは、ゲームオブジェクトのOOP実装を使用しました。つまり、スクリプトは非常に単純明快でした。たとえば、単純なスクリプトは次のようになります。
function start()
local future = entity:moveTo(pos1)
wait(future)
local response = entity:showDialog(dialog1)
if wait(response) == 1 then
local itemStack = entity:getInventory():removeItemByName("apple", 1)
world:getPlayer():getInventory():addItemStack(itemStack)
else
entity:setBehavior(world:getPlayer(), BEHAVIOR_HOSTILE)
end
end
ただし、ECSを使用する場合、エンティティ自体にはmoveTo
orのような関数はありませんgetInventory
。代わりに、ECSスタイルで記述された上記のスクリプトは次のようになります。
function start()
local movement = world:getComponent(MOVEMENT, entity)
movement:moveTo(pos1)
local position = world:getComponent(POSITION, entity)
local future = Future:untilEquals(position.pos, pos1)
wait(future)
local dialogComp = world:getComponent(DIALOG, entity)
local response = dialogComp:showDialog(dialog1)
if wait(response) == 1 then
local entityInventory = world:getComponent(INVENTORY, entity)
local playerInventory = world:getComponent(INVENTORY, world:getPlayer())
local itemStack = entityInventory:removeItemByName("apple", 1)
playerInventory:addItemStack(itemStack)
else
local entityBehavior = world:getComponent(BEHAVIOR, entity)
local playerBehavior = world:getComponent(BEHAVIOR, world:getPlayer())
entityBehavior:set(playerBehavior, BEHAVIOR_HOSTILE)
end
end
これは、 OOPバージョンに比べてはるかに冗長です。これは、スクリプトがほとんどプログラマー以外(ゲームのプレーヤー)を対象としている場合には望ましくありません。
1つの解決策は、をカプセル化し、直接Entity
などの機能を提供しmoveTo
、残りを内部で処理するラッパーオブジェクトのようなものにすることですが、このような解決策は、すべてのコンポーネントとすべての新しいコンポーネントが追加されると、新しい関数でラッパーオブジェクトを変更する必要があります。
以前にECSでスクリプトを実装したことのあるすべてのゲーム開発者に-どのようにそれをしましたか ここでの主な焦点は、エンドユーザーの使いやすさにあり、 "メンテナンス"コストは最小限に抑えられます(コンポーネントを追加するたびに変更する必要がないことが望ましいです)。
moveTo
として、MovementSystemなどのユースケースで、メソッドを基盤となるシステムの一部として公開しないでください。これにより、作成したスクリプトで使用できるだけでなく、必要な場所でC ++コードの一部としても使用できます。つまり、新しいシステムが追加されたときに新しいメソッドを公開する必要がありますが、いずれにしても、これらのシステムが導入するまったく新しい動作として期待されています。
System
、コンポーネントをデータ構造のままにできるように、クラスに特化することもできます。