エンティティシステムに機能を実装するにはどうすればよいですか?


31

エンティティ・システム(約2つの質問尋ねる後12)、およびいくつかの読書記事をそれらの上に、私ははるかに良い以前よりもそれらを理解していると思います。主にパーティクルエミッタ、入力システム、カメラの構築については、まだいくつかの不確実性があります。エンティティシステムの理解にはまだいくつかの問題が残っており、他のあらゆる範囲のオブジェクトに適用される可能性がありますが、これらは非常に異なる概念であり、かなり広い範囲をカバーし、エンティティシステムとその方法を理解するのに役立つため、これら3つを選択しましたこれらの問題を自分で処理します。

JavaScriptでエンジンを構築しており、入力処理、柔軟なアニメーションシステム、パーティクルエミッター、数学クラスと関数、シーン処理、カメラとレンダー、および多数のコア機能のほとんどを実装しています。エンジンが通常サポートするその他のもの。Byte56の答えを読んで、エンジンをエンティティシステムにすることに興味を持ちました。基本的なシーンの哲学を持つHTML5ゲームエンジンのままですが、コンポーネントからのエンティティの動的な作成をサポートする必要があります。


私が今抱えている問題は、古いエンジンの概念をこの新しいプログラミングパラダイムに適合させることです。これらは、更新された以前の質問の定義の一部です。

  • アンエンティティの識別子です。データはなく、オブジェクトではなく、すべてのエンティティのシーンリスト内のインデックスを表す単純なIDです(実際にコンポーネントマトリックスとして実装する予定です)。

  • A コンポーネントが、そのデータを操作することができる方法と、データ保持部です。最良の例はVector2D、または「位置」コンポーネントです。これにはdata:xyがありますが、データの操作を少し簡単にするいくつかのメソッドもあります:add()normalize()など。

  • A システムは、一定の要件を満たしているエンティティのセットを操作することができるものです。通常、エンティティは、操作対象のコンポーネントの指定されたセットを持っている必要があります。システムは「論理」部分、「アルゴリズム」部分であり、コンポーネントによって提供されるすべての機能は、純粋にデータ管理を容易にするためのものです。


カメラ

カメラには、Vector2D位置プロパティ、回転プロパティ、およびポイントを中心とするいくつかのメソッドがあります。各フレームは、シーンとともにレンダラーに送られ、すべてのオブジェクトはその位置に従って変換されます。その後、シーンがレンダリングされます。

エンティティシステムでこの種のオブジェクトをどのように表現できますか?カメラはエンティティ、コンポーネント、または組み合わせになりますか(私の回答によると)?

パーティクルエミッタ

パーティクルエミッタの問題点は、何がどうあるべきかということです。10,000個以上のパーティクルをサポートしたいので、パーティクル自体がエンティティであってはならないことは間違いありません。そのようなエンティティを作成すると、パフォーマンスに大きな打撃を与えると考えています。

エンティティシステムでこの種のオブジェクトをどのように表現できますか?

入力マネージャー

最後に話したいのは、入力の処理方法です。現在のバージョンのエンジンには、というクラスがありInputます。これは、キーの押下やマウスの位置の変更などのブラウザーイベントにサブスクライブし、内部状態も維持するハンドラーです。次に、プレーヤークラスにはreact()、入力オブジェクトを引数として受け入れるメソッドがあります。これの利点は、入力オブジェクトを.JSONにシリアル化し、ネットワーク上で共有できるため、スムーズなマルチプレイヤーシミュレーションが可能になることです。

これはどのようにエンティティシステムに変換されますか?

回答:


26
  • カメラ:これをコンポーネントにすると、かなりきれいになります。それはただisRenderingショーンが言ったような旗と深さの範囲。「視野」(2Dでスケールと呼ぶかもしれませんか?)と出力ゾーンに加えて。出力ゾーンは、このカメラがレンダリングされるゲームウィンドウの部分を定義できます。あなたが言及したような独立した位置/回転はありません。カメラコンポーネントを持つ作成したエンティティは、そのエンティティの位置と回転コンポーネントを使用します。次に、カメラ、位置、および回転コンポーネントを持つエンティティを探すカメラシステムがあります。システムはそのエンティティを取得し、その位置、回転、表示の深さ、および視野から、画面の指定された部分まで「見る」ことができるすべてのエンティティを描画します。これにより、複数のビューポート、「キャラクタービュー」ウィンドウ、ローカルマルチプレイヤー、

  • パーティクルエミッタ:これも単なるコンポーネントでなければなりません。パーティクルシステムは、位置、回転、パーティクルエミッタを持つエンティティを探します。エミッターには、現在のエミッターを再現するために必要なすべてのプロパティがあります。レート、初期速度、減衰時間など、それらが何であるかはわかりません。複数のパスを作成する必要はありません。パーティクルシステムは、どのエンティティがそのコンポーネントを持っているかを知っています。既存のコードを大量に再利用できると思います。

  • 入力:上記の提案を考えると、これをコンポーネントにすることが最も理にかなっていると言わざるを得ません。きみのinput system現在の入力イベントでフレームごとに更新されます。次に、入力コンポーネントを持つすべてのエンティティを通過すると、それらのイベントが適用されます。入力コンポーネントには、すべての関連するメソッドコールバックのキーボードイベントとマウスイベントのリストがあります。メソッドのコールバックがどこにあるかはよくわかりません。おそらくいくつかの入力コントローラークラス?エンジンのユーザーが後で変更する場合に最も意味のあるものは何でも。しかし、これにより、カメラエンティティ、プレーヤーエンティティ、または必要なものに簡単に入力コントロールを適用できるようになります。多数のエンティティの動きをキーボードと同期させたいですか?同じ入力に応答するすべての入力コンポーネントを提供するだけで、入力システムはそれらを要求するすべてのコンポーネントにこれらの移動イベントを適用します。

そのため、これのほとんどは頭の外にあるので、おそらくそれ以上の説明がなければ意味がありません。それで、あなたがはっきりしていないものを私に知らせてください。基本的に、私はあなたに取り組むべき多くを与えました:)


別の素晴らしい答え!ありがとう!今、私の唯一の問題は、エンティティをすばやく保存および取得することです。したがって、ユーザーは実際にゲームループ/ロジックを実装できます。適切な推測を行うためにメモリ内の未定義の値...これは問題になります。ブラウザによって実装方法が異なる可能性があるためです。
jcora

これはアーキテクチャ的に純粋に思えますが、レンダリングシステムは、すべてのエンティティを反復処理することなく、アクティブなカメラをどのように決定しますか?
ペース

@Paceアクティブなカメラを非常にすばやく見つけたいので、カメラシステムがアクティブなカメラを持つエンティティへの参照を保持できるようにします。
マイケルハウス

複数のカメラを制御するロジックをどこに配置しますか(見る、回転する、移動するなど)?複数のカメラをどのように制御しますか?
プラズマセル

@plasmacelコントロールを共有するオブジェクトが複数ある場合、入力を受け取るオブジェクトを決定するのはコントロールシステムの責任です。
マイケルハウス

13

これに私がどのようにアプローチしたかを以下に示します。

カメラ

私のカメラは、コンポーネントが接続されている他のエンティティです。

  1. TransformTranslation、その他、速度などのプロパティがRotationありScaleます。

  2. Pov(ビューポイント)はFieldOfViewAspectRatioNearFar、及び何が他に、射影行列を生成するために必要なIsOrtho視点と正射影との間のスイッチを使用するフラグ。PovまたProjectionMatrix、読み取り時に内部的に計算され、他のプロパティが変更されるまでキャッシュされるレンダリングシステムで使用される遅延ロードプロパティも提供します。

専用のカメラシステムはありません。Render Systemはのリストを保持し、Povレンダリング時に使用するものを決定するロジックを含んでいます。

入力

InputReceiver成分は、任意のエンティティに結合させることができます。これには、エンティティ固有の入力処理を保持するために使用されるイベントハンドラー(または言語がサポートしている場合はラムダ)があり、現在および以前のキー状態、現在および以前のマウス位置、ボタン状態などのパラメーターを取得しますマウスとキーボードに個別のハンドラがあります)。

たとえば、エンティティ/コンポーネントに慣れるときに作成した小惑星のようなテストゲームでは、2つの入力ラムダメソッドがあります。1つは、矢印キーとスペースバー(発射用)を処理することにより、船の航行を処理します。もう1つは、一般的なキーボード入力を処理します-終了、一時停止など、再起動レベルなどのキー。非表示のコマンドプロセッサエンティティ。

船のInputReceiverコンポーネント(C#)にアタッチされるフレーム間に保持されるキーを処理するイベントハンドラーを次に示します。

  void ship_input_Hold(object sender, InputEventArgs args)
    {
        var k = args.Keys;
        var e = args.Entity;

        var dt = (float)args.GameTime.ElapsedGameTime.TotalSeconds;

        var verlet = e.As<VerletMotion>();
        var transform = e.As<Transform>();

        if (verlet != null)
        {

        /// calculate applied force 
            var force = Vector3.Zero;
            var forward = transform.RotationMatrix.Up * Settings.ShipSpeedMax;

            if (k.Contains(Keys.W))
                force += forward;

            if (k.Contains(Keys.S))
                force -= forward;

            verlet.Force += force * dt;
        }

        if (transform != null)
        {
            var theta = Vector3.Zero;

            if (k.Contains(Keys.A))
                theta.Z += Settings.TurnRate;

            if (k.Contains(Keys.D))
                theta.Z -= Settings.TurnRate;

            transform.Rotation += theta * dt;
        }

        if (k.Contains(Keys.Space))
        {
            var time = (float)args.GameTime.TotalGameTime.TotalSeconds - _rapidFireLast;

            if (time >= _rapidFireDelay)
            {
                Fire();
                _rapidFireLast = (float)args.GameTime.TotalGameTime.TotalSeconds;
            }
        }
    }

お使いのカメラがモバイルの場合、それは自身の与えるInputReceiverTransform、コンポーネント実装は一種コントロールの好きなことをラムダまたはハンドラを添付し、すれば完了です。

これはInputReceiver、ナビゲーションハンドラーを搭載したコンポーネントを船から小惑星などに移動し、代わりにそれを飛び回らせることができるという点で、きちんとしています。または、Povコンポーネントをシーン内の他の何か(小惑星、街灯など)に割り当てることにより、そのエンティティの視点からシーンを表示できます。

InputSystemキーボード、マウスなどの内部状態を保持するクラスはInputSystem、内部エンティティコレクションをInputReceiverコンポーネントを持つエンティティにフィルターします。そのUpdate()メソッドでは、そのコレクションを反復処理し、レンダリングシステムがRenderableコンポーネントで各エンティティを描画するのと同じ方法で、これらの各コンポーネントに接続された入力ハンドラーを呼び出します。

粒子

これは、パーティクルとのやり取りをどのように計画するかに大きく依存します。1つのオブジェクトのように振る舞うパーティクルシステムだけが必要な場合(たとえば、花火でプレーヤーが触れたり触れたりできないことを示している場合)、単一のエンティティとParticleRenderGroup、パーティクルに必要な情報を含むコンポーネントを作成します-減衰など- Renderableコンポーネントによってカバーされていません。レンダリング時に、レンダリングシステムはエンティティにRenderParticleGroupアタッチされているかどうかを確認し、それに応じて処理します。

衝突検出に参加したり、入力に応答したりするために個々のパーティクルが必要であるが、それらをバッチとしてレンダリングしたい場合Particleは、パーティクルごとにその情報を含むコンポーネントを作成し、個別のエンティティ。レンダーシステムは引き続きそれらをバッチ処理できますが、他のシステムでは別個のオブジェクトとして扱われます。(これはインスタンス化で非常にうまく機能します。)

次に、MotionSystem(またはエンティティの位置の更新などを処理する使用)または専用のいずれかでParticleSystem、フレームごとに各パーティクルに必要な処理を実行します。RenderSystem/建物の一括処理し、それらが作成され、破壊されているとして、粒子のコレクションをキャッシュするための責任を負うこと、および必要に応じてそれらをレンダリングします。

このアプローチの良い点の1つは、パーティクルの衝突、カリングなどの特別なケースを用意する必要がないことです。他のすべての種類のエンティティ用に作成したコードは引き続き使用できます。

結論

クロスプラットフォームに移行することを検討している場合-JavaScriptには適用できない-プラットフォーム固有のコード(つまり、レンダリングと入力)はすべて2つのシステムに分離されています。ゲームロジックはプラットフォームに依存しないクラス(モーション、コリジョンなど)のままなので、移植時にそれらに触れる必要はありません。

私は、アプリケーションのニーズを満たすためにパターンを微調整するのではなく、パターンを厳密に守るためにパターンに靴べらをかけることは悪いというショーンの立場を理解し、同意します。Input、Camera、Particlesには、そのような処理を必要とするものは何もありません。


複数のカメラを制御するロジックをどこに配置しますか(見る、回転する、移動するなど)?
プラズマセル

7

入力およびゲームロジックは、エンティティコンポーネントシステム外の専用のコードチャンクで処理される可能性があります。それをデザインに押し込むことは技術的には可能ですが、利益はほとんどありません-ゲームロジックとUIはハックし、何をしようとも漏れやすい抽象化でいっぱいです時間の。

同様に、パーティクルエミッターは、特にパフォーマンスにまったく関心がある場合は特別な獣です。エミッターコンポーネントは理にかなっていますが、グラフィックスはこれらのコンポーネントで特別な魔法を実行し、残りのレンダリングの魔法と混合します。

カメラに関しては、カメラにアクティブフラグと「深度」インデックスを付け、有効になっているすべてのカメラをグラフィックシステムにレンダリングさせます。これは実際には、GUI(ゲームワールドの上に正投影モードでレンダリングしたいですか?問題ありません。異なるオブジェクトマスクとGUIが上位層に設定された2台のカメラだけです)を含む多くのトリックに便利です。また、特殊効果レイヤーなどにも役立ちます。


4

カメラはエンティティですか、それともコンポーネントですか?

この質問が本当に何を求めているのか分かりません。ゲーム内にあるのはエンティティのみであるため、カメラはエンティティでなければなりません。カメラ機能は、何らかのカメラコンポーネントを介して実装されます。「位置」と「回転」のコンポーネントを別々にしないでください-それはあまりにも低レベルです。これらは、世界のあらゆるエンティティに適用されるWorldPositionコンポーネントに結合する必要があります。どちらを使用するかについては、何らかの方法でシステムにロジックを取得する必要があります。カメラ処理システムにハードコードするか、スクリプトなどを添付します。役立つ場合は、カメラコンポーネントで有効/無効フラグを設定できます。

パーティクル自体がエンティティであってはならないことを確信しています

私も。パーティクルエミッタはエンティティであり、パーティクルシステムは特定のエンティティに関連付けられたパーティクルを追跡します。このようなことは、「すべてがエンティティである」ことはばかげて非現実的であることに気付くところです。実際には、エンティティであるのは、コンポーネントの組み合わせから恩恵を受ける比較的複雑なオブジェクトのみです。

入力に関しては、入力はゲームの世界には存在しないため、システムによって処理されます。ゲームのすべてがコンポーネントを中心に展開するわけではないため、必ずしも「コンポーネントシステム」ではありません。ただし、入力システムがあります。何らかの種類のPlayerコンポーネントで入力に応答するエンティティをマークすることもできますが、入力は複雑で完全にゲーム固有になるため、このためのコンポーネントを作成しようとする意味はほとんどありません。


1

これらの問題を解決するための私のアイデアをいくつか紹介します。彼らはおそらく彼らに何か間違っているでしょうし、おそらくより良いアプローチがあるでしょうので、あなたの答えの人々に私を向けてください!

カメラ

任意のエンティティに追加できる「カメラ」コンポーネントがあります。ただし、このコンポーネントにどのデータを配置する必要があるかは実際にはわかりません。「位置」コンポーネントと「回転」コンポーネントを別々に持つことができます。このfollowメソッドは実装されている必要はありません。既に添付されているエンティティを追跡しているからです!そして、自由に移動できます。このシステムの問題は、さまざまなカメラオブジェクトにあります。どのカメラオブジェクトRendererSystemを使用するかをどのように知ることができますか?また、以前はカメラオブジェクトを渡すだけでしたが、今ではRendererSystemすべてのエンティティに対して2回反復する必要があるようです:最初はカメラのように動作するものを見つけ、2番目はすべてを実際にレンダリングするためです。

ParticleEmitter

ParticleSystem「エミッタ」コンポーネントを持つすべてのエンティティを更新するがあります。パーティクルは、そのコンポーネント内の相対座標空間にあるダムオブジェクトです。ここにレンダリングの問題があります。ParticleRendererシステムを作成するか、既存のシステムの機能を拡張する必要があります。

入力システム

ここでの私にとっての主な関心事は、ロジックまたはreact()メソッドでした。私が思いついた唯一の解決策は、そのための個別のシステムと、使用するシステムを示す各システムのコンポーネントです。これは本当にハックが多いように思え、うまく処理する方法がわかりません。一つのことは、私が懸念している限り、Inputクラスとして実装し続けることができるということですが、ゲームの残りの部分にどのように統合できるかわかりません。


RendererSystemがすべてのエンティティを反復処理する理由は実際にはありません-既にドロアブル(およびカメラ、ライト(ライトがドロアブルでない場合))のリストを持っているか、それらのリストがどこにあるかを知っている必要があります。また、レンダリングしたいカメラのカリングを行うことになる可能性が高いため、カメラに表示可能な描画可能なエンティティIDのリストが含まれている可能性があります。多くのカメラと1台のアクティブなカメラ、または異なるPOVに接続された1台のカメラを使用できます。どちらも、スクリプトやトリガー、入力などの任意の数で制御できます

@ melak47、それは本当です、私もそれについて考えましたが、私はアレミスがそれをする方法でそれを実装したかったです。しかし、この「システムは関連エンティティへの参照を格納する」にはますます欠陥があるようです
...-jcora

Artemisは、各コンポーネントタイプを独自のリストに保存しませんか?描画可能なコンポーネント、カメラコンポーネント、ライトなどのリストは正確にはありませんか?
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.