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);

我在这里需要更多的间接层,但我看不到它。我知道这是可以做到的,因为所有信息在编译时都可用。不需要动态多态解决方案。

任何帮助是极大的赞赏!

更新 我想做的是建立我自己的现代(如安德烈的书)游戏库。到目前为止,我已经解决了大部分关系,但这一个让我难过。这不是时间关键问题,而是结果关键问题。我从事游戏工作很多年了,我不喜欢我从事过的任何游戏引擎。这意味着易于使用且易于扩展。既然控制台编译器变得不那么糟糕,它就可以在任何平台上运行。

这是我想要写的一个简单的例子。

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();
    }
}

所有的物理都是在制品,不是我希望它结束​​的地方,但它正在到达那里。System object 初始化 Windows 和平台特定的渲染器。在这种情况下,它是 openGL。尽管它被编译为控制台应用程序,但它会创建所有 Windows 组件。我不想让人们处理 main() 与 winmain()。除了物理,没有继承。在我将场景导入系统后,三个渲染调用将被替换为一个。我计划使用我不久前写的东西,结合 Gary Powell 和 Martin Weiser 的 View 模板库。

我知道我只是看不对。访客可以帮助改变我的方法。

所以这就是我想要做的。

更新 2 好的。到目前为止,我已经从评论和答案中获得了一些灵感,这就是我去的地方,但我还没有完成。

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

也许是这样的?(只有hit部分,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);
    }
}

没有必要从受害者或威胁效果继承。如果您想要包罗万象的解决方案,它们就在那里。M 和 V 类型可以是任何对象,所以如果你想继承或不继承,或者你想使用它。我必须为 ptrs 等创建所有变体。如果所有使用对象都继承自基类,那么它可以像使用动态多态性编写一样使用。如果您不想继承而是保留特殊的单独列表,您也可以这样做。

使用它很容易

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 回答