0

ゲーム オブジェクトのクラス階層の設計に関するアドバイスを探しています。この議論では、主に 2 つの特定のクラスについて話します。ObjectSprite。_

Object、ゲーム内のあらゆるタイプのオブジェクトの基本クラスです。Spriteは から直接継承されますObjectが、 のパブリック メソッドの一部はObjectもはや意味がありません。説明するコードを次に示します。

class Object {
public:
    Object() : renderer(NULL), controller(NULL), collider(NULL) { }
    virtual ~Object();

    Renderer *getRenderer() const;
    Controller *getController() const;
    Collider *getCollider() const;

    void setRenderer(Renderer *renderer);
    void setController(Controller *controller);
    void setCollider(Collider *collider);
private:
    Renderer *renderer;
    Controller *controller;
    Collider *collider;
};

Objectには、レンダラー、コライダー、コントローラーの 3 つのコンポーネントがあります。 Spriteもちろん、これら 3 つのコンポーネントがありますが、SpriteRenderer. setRenderer私は、スプライトクラスにメソッドを公開したくないと考えました。

そこで、スプライト クラスを次のように記述すべきだと考えました。

class Sprite : protected Object {
public:
    Sprite(Texture *texture) : Object(), texture(texture) {
        setRenderer(new SpriteRenderer(this));
    }

    Renderer *getRenderer() const;
    Controller *getController() const;
    Collider *getCollider() const;

    void setController(Controller *controller);
    void setCollider(Collider *collider);
private:
    Texture *texture;
};

ゲッターとセッターは関連するObjectメソッドを呼び出すだけです。しかし、この場合、 をSpriteとして実際に使用することはできませんObject。たとえば、 を受け取る関数に渡すなどObjectです。

私の他の実装は次のとおりです。

class Sprite : public Object {
public:
    Sprite(Texture *texture) : Object(), texture(texture) {
        setRenderer(new SpriteRenderer(this));
    }
private:
    Texture *texture;
};

メソッドを公開しsetRendererます。

私の思考プロセスは、 aがaであるsetRendererためにメソッドを公開すべきではないということです。ただし、変更を防ぐ明確な方法はわかりません。SpriteObjectSpriteRendererSprite

一般的に、これは私が心配する必要のないものですか、それともこの設計を行う別の方法はありますか?

4

3 に答える 3

1

ゲッターとセッターを使用してオブジェクトをモデル化する代わりに、オブジェクトが実際に必要な動作を行うようにします。セッターがない場合は、セッターを公開することを心配する必要はありません。:)

たとえば、レンダラーを返す代わりに、オブジェクト自体をレンダリングします。そうすれば、スプライトはこの動作をオーバーライドできます。

class Object {
    virtual void render() = 0;
}

class Sprite : public Object {
    void render() {
      // use a SpriteRenderer
    }
}
于 2012-08-16T06:58:54.390 に答える
1

You should ask yourself: do you need to change the Renderer (and other components) on runtime? I believe this is not needed AFTER object instance is created. As the consequence I would not put methods setRenderer (and other setXXX) in the public API at all. Do you need to expose these parameters at all? If yes, then I can propose the following:

.

class Object
{
public:
    // Constructor with all the necessary parameters. 
    // For simplicity I keep only Renderer
    Object(const Renderer & renderer) :
        renderer_(renderer)
    {
    }

    const Renderer & getRenderer() const { return renderer_; }

private:
    // I think reference is better if Renderer MUST always be not NULL
    const Renderer & renderer_;

};

This way you have nice immutable class.

For constructing Sprite instances you might need SpriteFactory or SpriteBuilder.

.

class Sprite : public Object
{
public:
    Sprite(const Renderer & renderer, const SpriteSpecificStuff & stuff) :
        Object(renderer),
        ...
    {
    }
};

class SpriteBuilder
{
public:
    void setRenderer(const Renderer * renderer);
    void setSpriteSpecificStuff();

    std::auto_ptr<Sprite> build();
};

Again, using the builder you will have nice immutable class

于 2012-08-16T07:16:31.210 に答える
1

多重継承に関する私のコメントに沿って説明すると、オブジェクトは、レンダリング可能なもの、衝突できるもの、「制御」されているもの (システムでの意味が何であれ) と考えることができます。したがって、これら 3 つのプロパティ (および場合によってはそれ以上) をすべて含む単一の基本オブジェクトを使用する代わりに、機能ごとに 1 つの基本クラスを使用できます。

class Renderable
{
public:
    Renderable(Rendered *renderer) : remderer_(renderer) {}

    Renderer *getRenderer() const;
    void setRenderer(Renderer *renderer);

private:
    Renderer *renderer_;
}

class Controllable
{
public:
    Controllable(Constroller &constroller) : controller_(constroller) {}

    Controller *getController() const;

    void setController(Controller *controller);

private:
    Controller *controller_;
};

class Collidable {
public:
    Collidable(Collider *collider) : collider_(collider) {}

    Collider *getCollider() const;

    void setCollider(Collider *collider);

private:
    Collider *collider_;
};

次に、Sprite3 つの機能をすべて備えたクラスで、3 つすべてを継承します。

class Sprite : public Renderable, public Controllable, public Collidable
{
public:
    Sprite()
        : Renderable(new SpriteRenderer)  // Supply special renderer
        {}

private:
    // Disallow users of the `Sprite` class to call this function;
    using Renderable::setRenderer;
};

機能のクラスを持つこのシステムは、ゲームの世界で「オブジェクト」を作成するときに非常にうまく機能します。ファンタジー スタイルのゲームを例にとると、剣を武器として使用し、着用し、運ぶことができることを意味する、およびSwordから継承するクラスがあります。WeaponWearableCarryable

于 2012-08-17T05:01:15.213 に答える