OOP游戏菜单系统开发概念化

时间:2012-08-21 14:29:55

标签: c++ oop user-interface menu

我正在尝试为游戏编写一个OO菜单系统,松散地基于模型,视图,控制器的想法。到目前为止,在我的应用程序中,我将视图命名为“渲染器”,模型没有后缀。我创建了一个通用菜单类,它存储菜单的项目,即menu_item对象,还有一个菜单渲染器类,它为每个项目创建渲染器并渲染它们。问题是我不知道在哪里存储数据和逻辑来处理每个项目应该放置在屏幕上的位置,以及如何检查它是否正在悬停等等。我最初的想法是存储和设置每个菜单项上的选定属性,可以通过不同的视图进行不同的渲染,但即便如此我如何处理组成按钮的图形元素?

到目前为止的代码摘录如下:(更多代码https://gist.github.com/3422226

/**
 * Abstract menu model
 *
 * Menus have many items and have properties such as a title
 */
class menu {
protected:
    std::string _title;
    std::vector<menu_item*> _items;
public:
    std::string get_title();
    void set_title(std::string);
    std::vector<menu_item*> get_items();
};

class menu_controller: public controller {
private:
    menu* _menu;
public:
    menu_controller(menu*);

    virtual void update();
};

class menu_item {
protected:
    std::string _title;
public:
    menu_item(std::string title);
    virtual ~menu_item();

    std::string get_title();
};

class menu_renderer: public renderer {
private:
    menu*   _menu;
    bitmap  _background_bitmap;
    static font _title_font;
    std::map<menu_item*, menu_item_renderer*> _item_renderers;

public:
    menu_renderer(menu*);

    virtual void render();
};

font menu_renderer::_title_font = NULL;

menu_renderer::menu_renderer(menu* menu) {
    _menu = menu;
    _background_bitmap = ::load_bitmap("blackjack_menu_bg.jpg");
    if (!_title_font)
        _title_font = ::load_font("maven_pro_regular.ttf",48);
}

void menu_renderer::render() {
    ::draw_bitmap(_background_bitmap, 0, 0);

    /* Draw the menu title */
    const char* title = _menu->get_title().c_str();
    int title_width = ::text_width(_title_font, title);
    ::draw_text(title, color_white, _title_font, screen_width() - title_width - 20, 20);

    /* Render each menu item */
    std::vector<menu_item*> items = _menu->get_items();
    for (std::vector<menu_item*>::iterator it = items.begin(); it != items.end(); ++it) {
        menu_item* item = *it;
        if (!_item_renderers.count(item))
            _item_renderers[item] = new menu_item_renderer(item, it - items.begin());
        _item_renderers[item]->render();
    }
}

class menu_item_renderer: public renderer {
private:
    unsigned _order;
    menu_item* _item;
    static font _title_font;
public:
    menu_item_renderer(menu_item*, unsigned);
    virtual ~menu_item_renderer();

    virtual void render();
};

font menu_item_renderer::_title_font = NULL;

menu_item_renderer::menu_item_renderer(menu_item* item, unsigned order) {
    _item = item;
    _order = order;
    if (!_title_font)
        _title_font = ::load_font("maven_pro_regular.ttf",24);
}

menu_item_renderer::~menu_item_renderer() {
    // TODO Auto-generated destructor stub
}

void menu_item_renderer::render() {
    const char* title = _item->get_title().c_str();
    int title_width = ::text_width(_title_font, title);
    unsigned y = 44 * _order + 20;
    ::fill_rectangle(color_red, 20, y, title_width + 40, 34);
    ::draw_text(title, color_white, _title_font, 30, y + 5);
}

1 个答案:

答案 0 :(得分:2)

您的模型class menu需要add_view(menuview *v)update()方法。

然后,您可以将窗口小部件的更新委派给派生的视图(menu_renderercli_menu_renderer)。

当Controller运行(或执行命令)并且必须使用Setter(如m_menu_model->set_selected(item, state))更新模型并且模型调用{{1}时,Controller需要知道模型(作为成员)在Setters上。

你的控制器update()有一个更新方法,在那里你也可以要求输入,比如menu_controller(所有菜单视图必须实现)并调用setter,但这是一个不灵活的View和控制器(您可以使用命令模式检查MVC以获得更高级的组合)。

对于位置,您可以设置成员变量,如int m_x,m_y,m_w,m_h。 但是这些成员特定于带GUI的View,因此只有派生的View需要它们。

然后你可以使用这些值来比较鼠标位置并使用像这样的MouseOver检测方法:

if (menuview->toggle_select()) m_menu_model->toggle_selected();