5

物理衝突システムの関数の接続をコンパイラに構築させたいと考えています。私はテスト衝突機能を持っています:

template <typename T, typename U>
inline void Collision(T& t, U& u)
{
    if(u.CheckCollision(t.GetCollider()))
    {
        u.HitBy(t);
        t.Hit(u);
    }
}

次に、コライダー オブジェクトを使用して衝突オブジェクトを保持します。

template <typename T>
class Collidable
{
    T m_Collider;
    VictimEffect m_HitBy;
    MenaceEffect m_Hit;
 public:
    void SetCollider(const T& t) { m_Collider = t; }
    void SetVictim(VictimEffect effect) { m_HitBy = effect; }
    void SetMenace(MenaceEffect effect) { m_Hit = effect; }

    T& GetCollider()
    {
        return m_Collider;
    }
    template <typename V>
    void HitBy(V& menace)
    {
        m_HitBy.HitBy(menace.GetCollider());
    }
    template <typename V>
    void Hit(V& victim)
    {
        m_Hit.Hit(victim.GetCollider());
    }
    template <typename V>
    bool CheckCollision(V& menace)
    {
        return m_Collider.CheckCollision(menace);
    }
};

エフェクト関数に一定レベルの間接性を追加しました

class VictimEffect
{
public:
    template<typename C>
    void HitBy(C&)
    {;}
};

class MenaceEffect
{
public:
    template<typename C>
    void Hit(C&)
    {;}
};

私が行き着きたいと思っているのは、正しい関数シグネチャを持ち、ヒットしない型を必要としない任意のオブジェクトで関数を呼び出す方法です。

class Wall;
class Ball : public MenaceEffect
{
public:
    void Hit(Wall& wall);
    void Hit(Ball& ball);
};

class Wall : public VictimEffect
{
public:
    void HitBy(Ball& ball);
};

壁にぶつかる壁の機能を持たせたくないことに注意してください。発生する必要がある相互作用の関数のみを作成または提供したい。VictimEffect は派生関数を「認識」しないため、これが機能しないことはわかっています。

テンプレートパラメーターが使用されているすべての場所で、テンプレートパラメーターを指定せずにディスパッチしたい。衝突可能とは別に衝突可能効果を構築し、それを衝突可能オブジェクトに一般的に与えたいと考えています。衝突できるもののコレクションごとに異なる衝突可能なオブジェクトを持ちたくありません。基本的に欲しい

vector<collidable> movingThings;
vector<collidable> staticThings;
// get iterators ...
Collide(Moving, Static);

ここには間接的な層がもっと必要ですが、それが見えません。コンパイル時にすべての情報が利用可能であるため、それが可能であることはわかっています。動的なポリモーフィック ソリューションは必要ありません。

どんな助けでも大歓迎です!

更新 私がやろうとしているのは、独自の最新の (Andrei の本のように) ゲーム ライブラリを構築することです。これまでのところ、私はほとんどの関係を解決してきましたが、これには困惑しています. これは時間的に重要な問題ではなく、結果が重要な問題です。私は何年もの間ゲームの仕事をしてきましたが、私が取り組んできたゲーム エンジンはどれも好きではありません。これは、使いやすく、拡張しやすいことを目的としています。コンソール コンパイラがそれほどひどくなくなったので、どのプラットフォームでも動作します。

これは、私が書きたいことの簡単な例です。

int main()
{
    // System must come first
    System system(640, 480, false);
    Renderer renderer;
    Mouse mouse;
    Keyboard keys;

    // Make the ball
    Bounce ball;
    Sprite ballSprite("02.bmp");
    CollisionBox ballPhysics;
    BallCommand ballBehavior;

    ball.SpriteMover = boost::bind(&Sprite::Observer<Pos2D>, &ballSprite, _1);
    ball.PhysicsMover = boost::bind(&CollisionBox::Move, &ballPhysics, _1);

    // Make the bounds
    Boundary bounds;

    // Set up Physics
    Collidable<Boundary> boundC;
    boundC.SetCollider(bounds);
    boundC.SetVictim(ballBehavior);

    Collidable<CollisionBox> ballC;
    ballC.SetCollider(ballPhysics);

    PretendPhysics physics;
    physics.SetBall(ballC);
    physics.SetBounds(boundC);

    while(!mouse.LeftClick() && !keys.AnyKey())
    {
        ball.MoveRel(ballBehavior.Delta());
        physics.Update();

        renderer.Clear();
        renderer.Render(ballSprite);
        renderer.SwapBuffers();
    }
}

すべての Physics は WIP であり、私が望むところには行き着いていませんが、それは達成されつつあります。System object は、Windows とプラットフォーム固有のレンダラーを初期化します。この場合はopenGLです。コンソール アプリとしてコンパイルされますが、すべての Windows コンポーネントを作成します。私は人々に main() と winmain() を扱いたくありませんでした。物理学を除いて、継承はありません。シーンをシステムに取り込むと、3 つのレンダー コールが 1 つに置き換えられます。少し前に書いたものを、Gary Powell と Martin Weiser の View テンプレート ライブラリと組み合わせて使用​​する予定です。

私はそれを正しく見ていないことを知っています。訪問者は、私のアプローチを変えるのに役立ちます。

それが私がやろうとしていることです。

更新 2 OK。これまでのコメントと回答からインスピレーションを得て、ここに行きましたが、まだ終わっていません。

template <typename T, typename V = VictimEffect, typename M = MenaceEffect>
class Collidable
{
    T m_Collider;
    V m_HitBy;
    M m_Hit;

public:
    Collidable(T collide, V victim, M menace) : m_Collider(collide), m_HitBy(victim),         m_Hit(menace) {;}
    Collidable(T collide) : m_Collider(collide) {;}
    Collidable(T collide, V victim) : m_Collider(collide), m_HitBy(victim) {;}

    T& GetCollider()
    {
        return m_Collider;
    }

    template <typename V>
    void HitBy(V& menace)
    {
        m_HitBy.HitBy(menace.GetCollider());
    }

    template <typename V>
    void Hit(V& victim)
    {
        m_Hit.Hit(victim.GetCollider());
    }

    template <typename V>
    bool CheckCollision(V& menace)
    {
        return m_Collider.CheckCollision(menace);
    }
};

それを使用するには、これを行います

    Collidable<Boundary, BallCommand> boundC(bounds, ballBehavior);
    Collidable<CollisionBox> ballC(ballPhysics);

万能は正しかった。ベースを渡すことで型情報を失っていました。今のベースは、どうでもいいことをキャッチするためだけにあります。

私のコンテナでは、タイプリストを使用してコンテナに追加されたすべてのタイプを収集し、それを使用して情報を処理するタイプ固有のコンテナを宣言できると思います。ただし、関数オブジェクトを渡す方が簡単な通常のイテレータを取り出すことができないという問題があります。

おそらく、C++ 0X はその新しい未知の型変数に役立つでしょう。(名前は忘れました)。

4

2 に答える 2

2

たぶん、このようなものですか?(ヒット部分のみ、hitByは左右対称)

class Wall;

class MenaceBase {
    public:
    template<typename T>
    void hit(T& t) {
        t.hitImpl(*this);
    }
};

class VictimBase {
    public:
};

template<typename M>
class Menace {
    public:
    virtual void hit(M&) = 0;
};

template<typename V>
class Victim {
    public:
    virtual void hitBy(V&) = 0;
};

class Ball : public MenaceBase, public Menace<Wall>, public Menace<Ball> {
    public:
    void hit(Wall& wall) {}
    void hit(Ball& ball) {}
};

class Wall : public VictimBase, public Victim<Ball> {
    public:
    void hitBy(Ball& ball) {}
    void hitImpl(Menace<Wall>& menace) {
        menace.hit(*this);
    }
};
于 2011-04-19T08:31:50.533 に答える
1

わかった。これが私が終わらせたものです。

class VictimEffect
{
public:
    template<typename C>
    void HitBy(C&)
    {;}
};

class MenaceEffect
{
public:
    template<typename C>
    void Hit(C&)
    {;}
};


template <typename T, typename M = MenaceEffect, typename V = VictimEffect>
class Collidable
{
    T m_Collider;
    M m_WeHit;
    V m_WeWereHit;

public:
    Collidable(T collide, M menaceEffect, V victimEffect) : m_Collider(collide), m_WeHit(menaceEffect), m_WeWereHit(victimEffect) {;}
    Collidable(T collide) : m_Collider(collide) {;}
    Collidable(T collide, M menaceEffect) : m_Collider(collide), m_WeHit(menaceEffect) {;}

    T& GetCollider()
    {
        return m_Collider;
    }

    template <typename V>
    void HitBy(V& menace)
    {
        m_WeWereHit.HitBy(menace.GetCollider());
    }

    template <typename V>
    void Hit(V& victim)
    {
        m_WeHit.Hit(victim.GetCollider());
    }

    template <typename V>
    bool CheckCollision(V& menace)
    {
        return m_Collider.CheckCollision(menace);
    }
};

template <typename T, typename U>
inline void Collision(T& t, U& u)
{
    if(u.CheckCollision(t.GetCollider()))
    {
        u.HitBy(t);
        t.Hit(u);
    }
}

Victim または Menace 効果から継承する必要はありません。包括的なソリューションが必要な場合は、そこにあります。M 型と V 型は任意のオブジェクトにすることができるため、継承するかどうか、または使用するかどうかを指定できます。ptr などのすべてのバリエーションを作成する必要があります。すべての使用オブジェクトが基本クラスから継承されている場合、動的ポリモーフィズムで記述されているかのように使用できます。継承したくない場合は、代わりに特別な個別のリストを保持することもできます。

使い方は簡単

class Boundary
{
// Put whatever code here.
    bool CheckCollision(CollisionBox bounce)
};

class BallCommand
{

public:
    void Hit(Boundary& bounds)
    {
        if(bounds.XHit())
        {
            xDir *= -1;
        }
        if(bounds.YHit())
        {
            yDir *= -1;
        }
    }
};

コードのどこかで使用します。

    Collidable<Boundary> boundC(bounds);
    Collidable<std::shared_ptr<CollisionBox>, BallCommand&> ballC(ballPhysics, ballBehavior);

    Collision(ballC, boundC);

クリーンアップ作業はまだありますが、かなり良いスタートだと思います。さらに簡単にするために std::function に変換します。

Omnifarious と Giovanni に感謝します。

于 2011-04-20T11:47:04.990 に答える