2

在我的 C# 游戏引擎中,我曾经通过向管理器对象添加/删除动作来处理有序绘图,该管理器对象按优先级对动作进行排序,然后执行它们。

这是一个非常简化的示例:

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 */ }
}

通过添加一些辅助方法,代码变得非常优雅并且易于在我的引擎中使用。

我最近转向 C++,但找不到任何简单的方法来实现相同的结果。

我尝试使用 std::function,但是为了删除对象销毁的方法,我不得不将 draw 方法存储在调用者拥有的指针中,然后将其包装到 lambda 中并传入。非常不雅且耗时.

有没有办法获得类似于 C# 示例中显示的代码?

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类,它有一个纯虚拟执行、一个优先级和一个指向某个所有者的指针。这个想法是不创建其他类、元组,而是使用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 回答