2012-12-02 11 views
7

私はSFMLとOpenGLを使って小さなゲームを作って初心者のC++スキルを練習しています。プログラミングの部分は大部分がうまくいっていますが、実際のコード/クラスの設計については質問があります。C++/OOPゲームデザイン

私は1つのクラスMainLoopを持っています。このクラスには、ゲームループが含まれていて、イベント、グラフィックス、コマンド、ゲーム、UIの各クラスのインスタンスが1つあります。私は当初、それらのすべてを単一のクラス(異なる.cppファイルで区切られた関数)にすることを望んでいましたが、それはOOP/C++にとって間違ったアプローチであると言われました。しかし、私はそれらを分離して(カプセル化、モジュール性、デバッグ)良い側を見ることができますが、私はあまりにも多くの悪いものに遭遇しているようです。ユーザーがUIボタンを押した場合の例を挙げてみましょう。

まず、MainLoopは、SFMLのウィンドウクラスからイベントを取得します。 MainLoopはそれを自分のイベントクラスに送ります。イベントクラスはイベントを解釈し、それをUIクラスに送信して、ボタンにヒットしたかどうかを確認します。 trueの場合、UIクラスはbuttonコマンドを解釈するCommandクラスにUIクラスを送信します。そして最後に、コマンドクラスはそれをGameクラスまたはそれ以外の場所に送ります。

私にはとても重いようですが、少なくとも私が今やっているやり方では、多くの前方宣言が必要でした(そして、私がトンで終わったことを知る前に循環依存性の)。私はそれがパフォーマンスのためにもうまくいくとは思わない。

とにかく、ここに私は行方不明のトリックですか?どのようにこれらのクラスを結び付けるべきですか、どのようにコミュニケーションをとるべきですか?たとえば、EventクラスからUIクラスにコマンドを転送する方法はありますか?私は本当に前方宣言を持っていなければならず、あらゆるものを包み込んでいくべきでしょうか、そうではありませんか? MainLoopクラスをすべて実行して、代わりに宣言を必要としない整数/浮動小数点/文字を使用してリターンを転送する必要がありますか?私はちょっとここで紛失している。

答えて

4

私はゲームを開発する際に使用したいくつかのデザインを提案することができますが、それらは確かに良いことではありませんが、多くの問題はありませんでした。私はあなたにそのアイデアを与えるためにそれを短くしておきます。

まず、ビューマネージャが必要です。このマネージャはゲームの現在のビューを管理する必要があります。これはビューのスタックなどとして実装できます。だから、あなたのゲームのすべてのビューを知っており、現在のものに物事をディスパッチすることができるViewManagerクラスがあります。

その後、あなたのような外部からの基本的なインタフェースを提供しなければならない抽象クラスGameView必要があります。マウスイベント

  • activate()deactivate()へを受け取ることになりますビュー
  • receivedMouseEvent(Event e)を描く

    • drawMe()を、ビューマネージャでビューがプッシュまたはポップされたときに実行されるアクションを実行する

    この抽象クラスでは、ゲームの特定のビューまたはビューの一部を実装して、ビュースタックにプッシュしてポップすることができるようにする必要があります。

    良いことは、UI要素、クリックに反応する例えばクラスActiveAreaActiveAreaから継承Buttonを管理するためのサブクラスを持つことである、また、2枚の状態のグラフィックスを提供することができます。これらの要素は、抽象ビューに格納されているクリック可能な要素のリストの中に含まれている必要があります。そのため、すべての具体的なビューで共通の実装にボタンを追加できます。この方法では、例えば(メタコード)あなたは、自分の状態を管理し、それぞれのビューを持つことになります。このように

    void AbstractView::receiveEvent(Event e) { 
        for (ActiveArea *area in areas) 
        if (area.isInside(e)) { 
         area->action(); 
         return; 
        } 
    
        innerReceiveEvent(e); //which should be a pure virtual function that will call a method specified in concrete views 
    } 
    

    、および描画および管理イベントの世話をするビューマネージャ、

    void ViewManager::draw() { 
        for (AbstractView *view in views) // from top to bottom of the stack 
        view.draw(); 
    } 
    
    のようなものを持つことができます
  • +0

    私はそのようなアプローチを考慮していませんでしたが、それは有益です。これまでは、イベント/ UI /コマンドで実装するシンプルなグローバル・アクションの「GameState」を使用していましたが、表示する内容と入力に反応する方法を決定しています。私。 GameState == MainMenuの場合は、これらのUIオブジェクトを描画します(メインのゲームビューでこれらを描画するなど)。あなたのアプローチは、きれいなクリーナーであり、より有用かもしれません。しかし、あなたはそれらをまったく破壊しないのですか?あなたはそれらをアクティブ/非アクティブにするだけですか? – user1870725

    +0

    これは主にあなたの特定の問題に依存します。ビューが重い場合はそれらを破壊する必要があります。そうでなければ、それらを無効にすることができます。もちろん、前者のアプローチでは、ビューの永続的な状態(内部オブジェクトである可能性がある)が必要であるため、必要なときにリカバリできるようにする必要があります。 – Jack

    +0

    私はあなたが示唆したアプローチも使用しましたが、私は、全体の複雑さが特定のしきい値を超えて成長したと説明したものに似た何かに切り替える必要があると感じたので、コードはリパクタリングする価値があったほど大変でした。 – Jack

    3

    私はそれが重いと思われるかもしれませんが、これを行うには適切な方法です。関数呼び出しはまったく重くはなく、すべてのことを読みやすくすることに注意してください。少なくとも、それはすべきです。 ;-)

    すべてのクラスには、クラス定義を含むヘッダーファイルが必要ですが、そのメンバー関数の実装はできません。すべてのファイルには、任意のクラスヘッダーファイルを含めることができます。テンプレートを使用している場合(実装がヘッダーファイル内に存在する必要がある場合のみ)、循環依存関係が存在する可能性がありますが、説明からはあなたがそれらを所有しているとは思われません。ヘッダーはお互いを含める必要はありません。関数の引数でポインタや参照を他のクラスに渡す必要がある場合は、ヘッダの先頭に他のクラスを前方宣言しても問題ありません。ソースファイルの先頭にインクルードすることができるはずです。そうでない場合は、あなたのケースでこれが必要と思われる理由について、より多くの情報を提供してください。

    +0

    私は同意します..可能なところでは宣言を先に進めています。レイヤーを作成することで、OOの目的は複雑さを管理することであるクラスとそのパブリック関数について考えてみましょう抽象化のまた、パフォーマンスに関しては、通常、選択したアルゴリズム/データ構造は、関数を呼び出すよりも影響があります。ゲームやその他のリアルタイムソフトウェアでは、パフォーマンスを妥協しなければならないことがあります。 –

    +1

    どこでも前方宣言を使用するのはちょっと奇妙なようです。それぞれの授業は、最適には、「自分自身で立つことができる」べきではありませんか?モジュール性のために、私は意味します。私。私のGraphicsクラスでUIクラスが必要な場合(例えば、描画用のUI要素の座標を取得するために)、UIクラスも含めずに別のアプリケーションでGraphicsクラスを使用することはできません。同様に、コマンドがあるサブクラス(イベントなど)から別のサブクラス(UIなど)に直接移動するか、MainLoopクラスで中継する必要がありますか? – user1870725

    +0

    あなたのGraphicsクラスは "a" UIクラスを必要としますが、あなたのものである必要はありません。同じインターフェース(または少なくとも使用する部品)を定義する必要があります。メインループを辿るのは、どのクラスが何を管理するかによって異なります。あなたのグラフィックスクラスが画面上に何かを描画する必要がある場合は、UIに直接呼び出すことができます。しかし、ボタン・プレスでコマンドを起動する必要がある場合、ボタン・プレスを検出するUIはそのボタンの意味を知る必要があるとは思わない。ですから、MainLoopにどのコマンドを呼び出すかを決定させるのは意味があります。 –

    関連する問題