2

In my C# game engine, I used to handle ordered drawing by adding/removing action to a manager object, which sorted the actions by priority, then executed them.

Here is a very simplified example:

class DrawManager
{
    public List<Tuple<Action, int>> DrawActions = new List<Tuple<Action, int>>();
    void Draw() { foreach (var tuple in DrawActions) tuple.Item1(); }
}

class Example
{
    DrawManager manager;

    Example()
    {
        manager.DrawActions.Add(new Tuple<Action, int>(DrawBackground, 0));
        manager.DrawActions.Add(new Tuple<Action, int>(DrawForeground, 100));
    }
    ~Example()
    {
        manager.DrawActions.Remove(manager.DrawActions.Find(x => x.Item1 == DrawBackground));
        manager.DrawActions.Remove(manager.DrawActions.Find(x => x.Item1 == DrawForeground));
    }

    void DrawBackground() { /* draw something */ }
    void DrawForeground() { /* draw something */ }
}

By adding some helper methods, the code becomes very elegant and easy to use in my engine.

I've moved to C++ recently, and I can't find any easy way to achieve the same result.

I tried using std::function, but in order to remove the method on object destruction, I had to store the draw method in a pointer owned by the caller, then wrap it into a lambda and pass it in. Very inelegant and time consuming.

Is there any way to get code similar to the one shown in the C# example?

4

2 に答える 2

6

std::function次の代わりに使用できますAction

typedef std::function<void()> Action;
std::vector<std::pair<Action, int> > DrawActions;
void Draw() {
    for_each(DrawActions.begin(), DrawActions.end(), [](std::pair<Action, int>& a) {
       a.first(); 
    });
}
于 2012-10-28T15:20:32.543 に答える
1

std::function を使用しない他のアイデアでは、std::set を使用し、実行するアクションごとにクラスを作成します。アクション クラスは、それらを使用するクラスの cpp ファイル (共有されていない限り、ヘッダー ファイルではなく) で定義され、完全に隠されているという考えになります。

最初にActionクラスを定義します。このクラスには、純粋な仮想execute、優先度レベル、および所有者へのポインターがあります。アイデアは、他のクラスやタプルを作成するのではなく、Actionクラスを使用してこれらの値を格納することです。

class Action
{
public:
    Action(const int priority, void * owner) : priority(priority), owner(owner) {}
    virtual ~Action() {}

    virtual void execute() = 0;

    struct PrioritySorter
    {
        bool operator()(Action* a, Action* b)
        {
            return a->priority < b->priority;
        }
    };

    bool ownerIs(void * owner) const { return this->owner == owner; }

private:
    const int priority;
    void * owner;
};

次に、いくつかのアクションを作成します。

class DrawBackgroundAction : public Action
{
public:
    DrawBackgroundAction(const int priority, void * owner) : Action(priority, owner) {}

    void execute()
    {
        cout << "drawing background" << endl;
    }
};

class DrawForegroundAction : public Action
{
public:
    DrawForegroundAction(const int priority, void * owner) : Action(priority, owner) {}

    void execute()
    {
        cout << "drawing foreground!!!" << endl;
    }
};

class DrawSomethingElseAction : public Action
{
public:
    DrawSomethingElseAction(const int priority, void * owner) : Action(priority, owner) {}

    void execute()
    {
        cout << "drawing something else" << endl;
    }
};

DrawManagerは、優先順位によって並べ替えられたセットにアクションを格納します。「所有されている」アクション (他のクラス) を削除したい場合は、それを行うことができます。

class DrawManager
{
public:
    DrawManager() {}
    ~DrawManager()
    {
        for ( ActionList::iterator i = actions.begin(), e = actions.end(); i != e; i++ )
        {
            delete *i;
        }
        actions.clear();
    }

    void draw()
    {
        for ( ActionList::iterator i = actions.begin(), e = actions.end(); i != e; i++ )
        {
            (*i)->execute();
        }
    }

    void addAction(Action* action)
    {
        actions.insert(action);
    }

    void removeOwnedActions(void * owner)
    {
        for ( ActionList::iterator i = actions.begin(), e = actions.end(); i != e; i++)
        {
            if ( (*i)->ownerIs(owner) )
            {
                delete *i;
                actions.erase(i);
            }
        }
    }

private:
    typedef std::set<Action*,Action::PrioritySorter> ActionList;
    ActionList actions;
};

例のクラス:

class Example
{
public:
    Example()
    {
        manager.addAction(new DrawForegroundAction(100,this));
        manager.addAction(new DrawBackgroundAction(0,this));
        manager.addAction(new DrawSomethingElseAction(50,this));
    }

    void drawAll()
    {
        manager.draw();
    }

    void removeTheActionsIfYouWant()
    {
        manager.removeOwnedActions(this);
    }

private:
    DrawManager manager;
};

そしてテスト:

int main()
{
    Example ex;

    cout << "Drawing all" << endl;

    ex.drawAll();

    ex.removeTheActionsIfYouWant();

    cout << "Drawing again" << endl;

    ex.drawAll();

    return 0;
}
于 2012-10-29T14:11:13.863 に答える