Попытка использовать шаблоны для двойной отправки столкновения физики - PullRequest
5 голосов
/ 19 апреля 2011

Я хочу позволить компилятору создавать соединения функций для системы физических столкновений.У меня есть тестовая функция столкновения:

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

Замечание Iне хочу иметь функцию для стены, поражающей стену.Я хочу только написать или предоставить функции для взаимодействия, которое должно произойти.Я знаю, что это не работает, потому что 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();
    }
}

Вся физика - это WIP иэто не то, где я хочу, чтобы это закончилось, но это добирается там.Объект System инициализирует Windows и средство визуализации для конкретной платформы.В данном случае это openGL.Он создает все компоненты Windows, хотя и скомпилирован как консольное приложение.Я не хотел, чтобы люди имели дело с main () и winmain ().За исключением физики нет наследства.Три вызова рендера будут заменены на один после того, как я получу сцены в систему.Я планирую использовать то, что написал некоторое время назад, в сочетании с библиотекой шаблонов Gary Powell и Martin Weiser.

Я знаю, что просто смотрю на это неправильно.Посетитель может помочь изменить мой подход.

Так вот что я пытаюсь сделать.

Обновление 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 может помочь с этой новой переменной неизвестного типа.(Я забыл, как это называется).

Ответы [ 2 ]

2 голосов
/ 19 апреля 2011

Может как то так?(только часть попадания, 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);
    }
};
1 голос
/ 20 апреля 2011

OK. Вот чем я закончил.

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 за то, что они помогли мне разобраться.

...