オブジェクトの更新、内部か外部か?


8

タイトルは少しわかりにくいですが、質問を短いフレーズで説明する方法は考えられません。だからここにあります:

物理/タイルベースなど、ゲームエンジンを作成しているときはいつでも、物事をどのように管理すればよいかわからないところにいつも行きます。世界のエンティティは自分で処理する必要がありますか、それとも管理するグローバルシステムが必要ですか?

簡単な例を次に示します。各オブジェクトが彼の周りの世界を見て(衝突をチェック)、それに基づいて移動する必要があります。

[注、これはオブジェクトがタイルごとに移動するタイルベースのゲームなので、物理を使用してタイル間を移動していません]

public class Actor : GameObject
    {
        private void MoveTo(Vector2 location)
        {
            if (world.getTile(location) != solid && world.objAtTile(location) == null)
            {
                Tweener.addTween(this, location);
            }
          }
        }

または、各オブジェクトの動きは、世界がすべてをチェックする世界で操作する必要がありますか?

public class Actor : GameObject
    {
        private void MoveTo(Vector2 location)
        {
            world.moveTo(location);
          }
        }

public class World
{

    public void moveObject(GameObject obj, Vector2 location)
    {
      //called from object

      if (getTile(location) != solid && objAtTile(location) == null)
         {
                Tweener.addTween(obj, location);
         }
    }
}

この例ではそれほど重要ではありませんが、後で問題が発生するのがわかります。前もって感謝します。


1
質問についてもっとActor知りましょworldう。
deceleratedcaviar

1
私はあなたがオブジェクトとコンポーネントを融合させていると思います、そしてそれは誰が何をしているのかという問題を混乱させていると思います。Componentは非常に多重定義された用語であるため、意味上の問題である可能性があります。オブジェクトとは何か、コンポーネントが何を意味するのか、実際に作業を行う小さなエンジンをどのように編成するのかを明確にすると、自分の質問に答えられると思います。
Patrick Hughes、

1
ゲームオブジェクト自体が動くのか、それとも世界がゲームオブジェクトを動かすのかについて、他の人にも同意する必要があります。上記のコードは、コンポーネントタイプシステムを本当に意味していると私に信じさせるものではないため、質問のタイトルに誤解を招く可能性があります。
ジェームズ

皆さんがそれを言及している今、私はいくつかの誤解を招く用語を使用しました。今すぐ調整します!編集:すでに変更されていることを確認してください、ありがとう!
omgnoseat 2011

@danielアクターは、効果的に移動するために、明らかにそれらの周りの世界についての知識が必要ですが、通常は両方をカプセル化するがどちらも知らないコンテナを中心に設計します。例えば。世界にはアクターとレベルの両方が含まれています。アクターはレベルについて知っています(または、必要なときにレベルについて通知されますが、永続的な参照ではありません)が、ワールドについては知りません。
11:15にジョッキング

回答:


2

例はJavaですが、タグで言語が指定されていません。C ++では、答えはありませんどちらも - あなたはこのためにメンバ関数を使用するべきではありません!

void move_to(actor *a, world *w, vec2 location);

4
記事の著者が書いた本の大ファンを言わなければならない。ただし、この記事の推論は、私が知る限り、優れた理論ですが、実用的なコードではありません。これらのメソッドを関連するオブジェクトから移動することで、それらに関連する機能を探す場所をさらに追加し、混乱と必要なメンテナンスのレベルを高めるだけです。私の見解なので、+や-はありません。ちょうど2セント。
ジェームズ

1
また、継承はClassNameの代わりに:ClassNameを使用したC#のように見えることも必要です。
ジェームズ

これはC#に基づく疑似コードですが、私の質問には関係ありません:)
omgnoseat

1
@omgnoseat:ベア関数のない言語ではアドバイスが不可能であり、ADLのないすべての言語でその有用性が低下するため、これは適切です。優れたアーキテクチャは、言語の選択と無関係ではありません

2
@James:関数自体がOO設計原則に従うメソッドを呼び出す場合、裸の関数について非OOはありません。それが記事の要点です。(OOも優れたデザインの同義語ではありません。明確または単純なデザインでOOを使用する必要がない場合は、デザインではなくOOを使用しないでください。)

1

簡単な答えはありません。

プログラミングにおけるほとんどのものと同様に、それはトレードオフです。個々のオブジェクトにより多くの電力を与えると、オブジェクトが大きくなり、したがって遅くなりますが、エンジンの理解と拡張が容易になります。すべてを一緒に処理できるメガクラスを用意する方が高速かもしれませんが、メガクラスを用意する必要があります。つまり、超大規模なクラスを作成することは、一般に悪い形と考えられています。

特定のタイプのすべてのオブジェクトを表す単一のクラスがあり、それらのデータをリストに格納し、インデックスのみを渡して個々のオブジェクトのプロパティを取得する、コンポーネントおよびデータ駆動型設計に関するいくつかの記事を読みました。私はこれを実行可能なタイプのアーキテクチャーと見なすことができますが、オブジェクト指向の全体のポイントにややこしいと感じ、批判もかなりの割合で受けています。

個人的にはオブジェクトにもっと力を与えることをお勧めします。それはオブジェクト指向言語でより理に適っており、(私は想像するでしょうが)時間の経過とともに理解し、維持するのが容易になります。


あなたは、あなたが記述したコンポーネントとデータ駆動型のデザインのスタイルは「オブジェクト指向の全体的なポイントを備えたねじ」であると言って、物事をいくぶん控えめに言います-それはまったくオブジェクト指向はありません。少なくとも「エンティティシステムはMMOG開発の未来」に記載されているように(エンティティのシステムはpkogの回答にリンクされています)、エンティティシステムは完全に異なるプログラミングパラダイムです。 re Doing It Wrong。
Dave Sherohman、2009

6
それらは完全にオブジェクト指向です。ほとんどの人が慣れているのはオブジェクト指向だけではありませんが、それは問題ありません。オブジェクト指向とは、状態をその状態で動作するメソッドと結合することです。それだけです。各オブジェクトが実際のオブジェクトまたはそのようなものである必要はありません。
カイロタン2011

@カイロタン:繰り返しになりますが、「エンティティシステムはMMOG開発の未来」で説明されているようなモデルについて具体的に話しています。この場合、コンポーネントは外部の「システム」によって操作されるダムデータです。動作/メソッドがないため、オブジェクトではありません。それらは関係です(データベース行またはC構造体と考えてください)。OOPと「オブジェクト」の日常的な使用との誤った同等性は、それとは何の関係もありません。パート3から:「ES実装のどこでもOOPを使用することには強く反対します。不適切な場所にOOPを忍び込んで、これを良いアイデアだと思い込ませるのは簡単すぎます。」
Dave Sherohman、2011

私はこの記事を知っていますが、これらのことをどのように行うべきかについての一人の意見です-それは標準的な方法ではなく、必ずしも最善の方法でもないため、コンポーネント駆動の設計が完全に異なると言うのは正しくありませんプログラミングパラダイム。OOコードを使用してコンポーネントベースのアーキテクチャを実装することは完全に可能であり、はるかに一般的です。OOコードを使用しても、ストアドプロシージャを使用するよりデータベースの「コンポーネント性」が損なわれることはありません。 。
カイロタン2009

@Dave、この質問はエンティティコンポーネントシステムに関するものではありません。ESもデータ駆動型設計もOOではありません。これは一般的ですが、そうすることは大きな間違いです。あなたがそれをググると、この神話を明らかにするいくつかの良い記事を見つけるでしょう。ただし、この質問はオブジェクトを設計する方法の一般的なオブジェクト指向の原則に関するものであり、より高いレベルの設計パターンはその質問にまったく答えません。
Maik Semder、2011

0

コメントの前に多くのことが不明確だったので、私は私の答えを更新しています。私の考えを説明する間、私と一緒に裸になってください。

一般的に、設計で考慮すべき2つの重要な側面は、凝集結合です。より再利用可能で拡張可能な設計を作成するには、高い凝集性と低い結合が必要であることは誰もが知っています。

したがって、世界がすべてを管理する必要がある場合、それは凝集度が低く、結合が密であることを意味します(すべてを知り、実行する必要があるため)。ただし、ゲームエンティティがすべてを実行する必要がある場合も同様です。彼の場所の更新、テクスチャのレンダリングなど。

あなたが本当に興味を持っているのは、エンティティの1つの側面に焦点を当てたシステムを作成することです。たとえば、ゲームエンティティはテクスチャを持つことができますが、レンダラーはそのテクスチャを画面にレンダリングする必要があります。レンダラーは、エンティティが持っている他のプロパティを気にしません。

少し詳しく言えば、ゲームエンティティは単なるプロパティのバッグです。これらのプロパティは、特定のプロパティに焦点を当てたシステムによって操作されます。そして、これがコンポーネントベースのエンティティシステム(CBES)の出番であり、プロパティ=コンポーネントです。

具体的には、システム(またはサブシステム)を使用したCBES 。この設計では、エンティティが持つ他のコンポーネントを気にせずに、エンティティの特定のコンポーネントに焦点を当てたいくつかのシステムを使用する傾向があります。また、システムは、これらのコンポーネントを処理するために必要な情報のみと結合されます。

あなたの例を見てみましょう。エンティティを移動する場所の入力はプレーヤーのコントローラーに基づいているため、おそらくPlayerControllerSystemが存在します。このシステムは、他の多くのものとは別に、エンティティのPositionComponentを制御します。この場合、PlayerControllerSystemはLevelとPositionComponentを認識する必要があります。後で衝突検出を追加することにした場合は、エンティティの位置を再び使用するCollisionSystemを作成しますが、今回はバウンディングボックスを計算します(またはBoundingBoxComponentを呼び出してください)。実際、コンポーネントを追加/削除するだけで、動作を(オンザフライであっても)簡単にオンまたはオフに切り替えることができます。したがって、より多くの動作は、より多くのシステムがエンティティのコンポーネントを操作していることを意味しますが、それらはすべて、低結合で明確に定義されたクラスにあります。スクリプトが必要ですか?ScriptComponentを追加します。バム!2つのクラスでスクリプト機能を追加しました。物理?音?また同じ。

したがって、私がSubSystemsでCBESを推奨しているのは、それが完全にOOであり、全体的に保守/拡張が容易なシステムであるためです。動作をエンティティに追加するのは、動作に必要なデータと必要なエンティティを決定するのと同じくらい簡単です。

サブシステムを備えたコンポーネントベースのエンティティシステムの詳細については、エンティティシステムの T = Machineによる優れた一連のブログ投稿がMMOG開発の未来です。著者は、Entity Systems Projectという名前のさまざまな実装を収集するためのWikiを作成することさえしました

一般的なコンポーネントベースのエンティティシステムに関する一般的な(そしてよく知られている)投稿は、 Tony Hawk Proのシステムを作成したEvolve階層です。

最後に、サンプルコードを含むライブラリを探している場合は、Artemisライブラリ以外に進めないでください。Artemisは主にJavaですが、これはC#のポートです(これは現在、XNAプロジェクトで使用しています)。


2
-1これは問題を解決しないため、移動するだけです。コンポーネントで構成されているかどうかにかかわらず、どのオブジェクトが決定を下すかについては、まだ明確な答えはありません。
カイロタン2011

1
2番目のリンクは、ゲームエンティティの動作をエンティティシステムに外部化する必要がある理由の広範なチュートリアルを提供します。アルテミスはまったく同じアーキテクチャに従います。
11

2番目のリンクは意見です。コンポーネントは多くの人に好まれていますが、すべての問題の解決策ではありません。また、コンポーネントには本質的な解決策はありません。
カイロタン2009

この質問で最も多く投票された答えは、「単純な答えはありません。プログラミングのほとんどのことと同様に、トレードオフです」から始まります。2番目のリンクは、多くのソリューションの1つを提供します。実際、それはその答えの正反対を主張しています。多分私はそれをより明確にするために私の答えを編集する必要があります。しかし、再び、多分これは
反対

@pek:私の反対票は、「コンポーネントの使用」がこの質問に対する回答ではないためです。私はコンポーネントを使用していますが、コンポーネントパターンをお勧めしますが、「コンポーネントベースのエンティティシステムを使用する」は、ゲーム開発やゲームソフトウェアアーキテクチャのすべての問題に対する回答ではありません。この質問は、コンポーネントや継承でも同じです。階層またはまったく関係のない静的エンティティタイプ!

0

私は通常、オブジェクトがそれ自体を処理するデザインを使用します(結局のところ、それがメソッドの目的です)が、ベースワールドにはすべてのオブジェクトのリストがあり、それらのリストを使用してそれらを調整します。したがって、次のようなもの:

class World {
  var walls = [];
  var actors = [];
  function update() {
    for each (actor in actors) {
      actor.update(walls);
    }
  }
}

class Actor {
  function update(walls) {
    this.move();
    for each (wall in walls) {
      this.collide(wall);
    }
  }
}

0

それを乾いた状態に保ち、恥ずかしがり屋で、他の人に話しなさい。

あなたが行きたい場所に移動できるかどうかを世界に尋ねるよりも、世界にあなたの俳優を動かすように依頼する方が良いです。これにより、ワールドクラスなどでパスファインディングアルゴリズムを簡単に変更できます。もちろん、これをアクターのベースクラスに任せることもできますが、それが私が取る方向と理由です。


-1

編集:元の質問に対するこの回答のために十分に明確な線を引かなかったと述べたフィードバックのために書き直されました。

できれば質問をもう少し明確にしたいと思います。オブジェクトに作用するロジックは、そのオブジェクトの内部または外部である必要があります。投稿の最後の部分では、後でトラブルを回避するために、質問をするための基礎としてデザインの寿命について具体的に言及しています。

私の簡単な高レベルの答えは、オブジェクトに作用するすべてのロジックをそのオブジェクト内に保持することです。

オブジェクトを移動するのにワールドは必要ありません。必要なのは、移動するオブジェクトと移動先の場所を表すベクトルだけです。目的地が選択されているとき、または衝突のために環境への反応が必要なときに、世界が作用する可能性がありますが、それらは作業するために与えられた例の外です。

質問の根本的な部分に対処し、設計の寿命を延ばすために、コンポーネント指向のアーキテクチャを提案します。コンポーネントアーキテクチャは、オブジェクトをデータと機能の個別のセットに分解します(データのロジックを維持するための上記の私の答えに進むと仮定します)。構造がCEntity-> CHuman-> CSoldier-> CPlayerCharacterのようになっている場合は、ロジックを変更する必要があり、そのツリーのどこにあるかに応じて、常に問題が発生します(たとえば、人間のタイプは他にいくつありますか?)複数のオブジェクトタイプに影響を与える可能性があります。

代わりに、コンポーネントシステムには、ICompRenderable、ICompMoveable、ICompHealth、ICompInventoryなどのCEntityオブジェクトの構成を定義する一連のインターフェイスがあります。CCompMoveableHumanと、場合によってはCCompMoveableSoldierとCCompMoveablePlayerを使用して、個々の移動パターンを別々に保つ場所。兵士がフォーメーションで実行するように変更されたとしましょう。この変更は、そのコンポーネントを使用して構築されたエンティティにのみ影響します。

まとめると、ロジックを適用するデータとロジックを含めることをお勧めします。また、オブジェクトを個別のコンポーネントに分割して、「どこに配置すればよいですか」を削減することをお勧めします。質問し、メンテナンスの容易さとその拡張性により、将来への安定性を提供します。

お役に立てれば。


過去数時間、コンポーネントパターンを調査してきました。(pekのリンクは非常に優れています)しかし、実際の「動作」がどこで発生するかはまだ明確ではありません。エンティティには入力、レンダリング、物理学のためのさまざまなコンポーネントがあることは明らかですが、私が正しく理解した場合、コンポーネントには機能するために必要なデータのみが含まれ、実際には実装は含まれません。再び移動に戻りましょう;コンポーネントを使用してエンティティを移動するにはどうすればよいですか?inputcomponentを拡張して実装をそこにコーディングする必要がありますか?
omgnoseat 2011

私はオブジェクトのロジックを保持していますが、実際にはデータ指向の設計の上にコンポーネントシステムを行っています。つまり、ほとんどのオブジェクトは実際にはロジックにすぎず、連続した高速処理のためにデータ内の場所にマップされています... 。そして、一日の終わりに、一度に1つのデザインパターンを学習します:D -1に関しては、それがそのようにタグ付けされた理由を知っていただければ幸いです。理由を知っている。
ジェームズ

1
@ジェームズ、十分公正。エンティティコンポーネントシステムは元の質問に答えないため、反対票を投じました。位置コンポーネントは引き続きそれ自体を移動できます。または、世界はすべての位置コンポーネントを反復して移動できます。カイロタンがペックの回答に反対票を投じたのと同じ理由で、-1の理由は明白であると思いました。また、コンポーネントシステムがそれ自体移動することが必須であっても(そうではありません)、それでも答えにはならず、オプションの1つの使用例にすぎません。しかし、問題はどちらか一方を使用する理由、それらの長所と短所についてでした。答えはそれをカバーしていません。
Maik Semder、2011

@Maik Semder。フィードバックをお寄せいただきありがとうございます。質問の最後にあるように、最初の質問とそもそもの全体的な動機をより明確にするために、答えを書き直しました。
ジェームズ

@ジェームス、私のコメントに応じて回答を編集する時間を割いていただき、ありがとうございます。「オブジェクト内でオブジェクトに作用するすべてのロジックを維持する」という提案された回答は、OOのコア機能、つまりカプセル化を無効にします。Joeのリンクが示すように、フレンド以外のメンバー以外の関数を使用すると、オブジェクトのカプセル化のレベルが上がります。さらに、カプセル化を実際に測定する方法として、明確な方法を紹介します。move関数をworldまたはactorのいずれかに配置すると、デザインのカプセル化が減少し、柔軟性が低下し、コードの保守が難しくなります。
Maik Semder、2011

-1

コンポーネントベースのアーキテクチャについて読むことをお勧めします。ブログの投稿、プレゼンテーション、それらについての書き込みはかなり多く、私がこれまで以上に優れた仕事をすることができます。

AltDevBlogADayにはそれに関するかなりの数の投稿があり、ゲームエンティティに関するこのシリーズは非常に良いものです:http://altdevblogaday.com/2011/07/10/the-game-entity-–-part-ia-retrospect/解決しようとしている問題に焦点を当てた複数の部分。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.