C++ 面向对象的游戏菜单系统开发概念化

C++ 面向对象的游戏菜单系统开发概念化,c++,oop,user-interface,menu,C++,Oop,User Interface,Menu,我试图为一个游戏编写一个面向对象的菜单系统,松散地基于模型、视图和控制器的思想。到目前为止,在我的应用程序中,我将视图命名为“渲染器”,模型没有后缀。我创建了一个通用的菜单类,它存储菜单项,即菜单项对象,还有一个菜单渲染器类,它为每个项目创建渲染器并渲染它们。问题是,我不确定将数据和逻辑存储在何处,以确定每个项目在屏幕上的位置,以及如何检查它是否悬停在屏幕上,等等。我最初的想法是在每个菜单项上存储并设置一个选定的属性,这些属性可以通过不同的视图进行不同的渲染,但即便如此,我如何定位组成按钮的图形

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

到目前为止的代码摘录如下:(更多代码位于)

/**
*抽象菜单模型
*
*菜单有许多项,并具有标题等属性
*/
班级菜单{
受保护的:
std::string _title;
标准::向量_项;
公众:
std::字符串get_title();
无效集合标题(标准::字符串);
std::vector get_items();
};
类菜单\u控制器:公共控制器{
私人:
菜单*\u菜单;
公众:
菜单控制器(菜单*);
虚拟空更新();
};
类菜单项{
受保护的:
std::string _title;
公众:
菜单项(标准::字符串标题);
虚拟菜单项();
std::字符串get_title();
};
类菜单\u渲染器:公共渲染器{
私人:
菜单*\u菜单;
位图_背景_位图;
静态字体_title_font;
标准::地图项目渲染器;
公众:
菜单渲染器(菜单*);
虚拟void render();
};
字体菜单\u呈现程序::\u title\u font=NULL;
菜单渲染器::菜单渲染器(菜单*菜单){
_菜单=菜单;
_背景位图=::加载位图(“blackjack\u menu\u bg.jpg”);
如果(!\u标题\u字体)
_标题字体=::加载字体(“maven\u pro\u regular.ttf”,48);
}
void菜单_渲染器::render(){
::绘制位图(\u背景\u位图,0,0);
/*绘制菜单标题*/
const char*title=_菜单->获取_title().c_str();
int title\u width=::文本宽度(\u title\u字体,title);
::绘制文本(标题、颜色、白色、字体、屏幕宽度()-标题宽度-20,20);
/*渲染每个菜单项*/
std::vector items=_菜单->获取_项();
对于(std::vector::iterator it=items.begin();it!=items.end();++it){
菜单项*项=*它;
如果(!\u项目\u渲染器计数(项目))
_item_renders[item]=新菜单_item_renderer(item,it-items.begin());
_item_渲染器[item]->render();
}
}
类菜单\u项\u渲染器:公共渲染器{
私人:
未签署的"命令";;
菜单项*\u项;
静态字体_title_font;
公众:
菜单项渲染器(菜单项*,未签名);
虚拟~菜单项渲染器();
虚拟void render();
};
字体菜单\项\呈现器::\标题\字体=NULL;
菜单项渲染器::菜单项渲染器(菜单项*项,未签名顺序){
_项目=项目;
_订单=订单;
如果(!\u标题\u字体)
_标题字体=::加载字体(“maven\u pro\u regular.ttf”,24);
}
菜单项渲染器::~菜单项渲染器(){
//TODO自动生成的析构函数存根
}
无效菜单项渲染器::渲染(){
const char*title=\u item->get\u title().c\u str();
int title\u width=::文本宽度(\u title\u字体,title);
无符号y=44*_顺序+20;
::填充矩形(颜色为红色,20,y,标题宽度+40,34);
::绘制文字(标题、颜色、白色、字体、30、y+5);
}

您的型号
类菜单
需要一个
添加视图(menuview*v)
更新()
方法

然后,您可以将小部件的更新委托给派生视图(
menu\u renderer
cli\u menu\u renderer

当控制器运行(或执行命令)时,控制器需要知道模型(作为成员),并且必须使用Setter(如
m\u菜单\u Model->set\u selected(item,state)
)更新模型,并且模型调用Setter上的
update()

您的控制器
菜单\u控制器
有一个更新方法,在那里您还可以请求输入,如
if(menuview->toggle\u select())m\u菜单\u model->toggle\u selected()(所有MenuView都必须实现)并调用setter,但这是视图和控制器的不灵活耦合(您可以使用命令模式检查MVC以获得更高级的组合)

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

然后,您可以使用这些值与鼠标位置进行比较,并使用如下鼠标悬停检测方法:

// View menu_item 
bool menu_item::over()
{
    if (::mouse_x > m_x
            && ::mouse_x < m_x + m_w
            && ::mouse_y > m_y
            && ::mouse_y < m_y + m_h) {
        return true;
    }
    return false;
}


// update on gui menu item
bool menu_item::update()
{
    if (over()) {
        m_over = true;
    }
    else {
        m_over = false;
    }
    // onclick for the idea 
    if ((::mouse_b & 1) && m_over) {
        // here you could invoke a callback or fire event
        m_selected = 1;
    } else {
        m_selected = 0;
    }
    return m_selected;
}

// update the command line interface menu item
bool cli_menu_item::update()
{
    if ((::enterKeyPressed & 1) && m_selected) {
        // here you could invoke a callback or fire event
        m_selected = 1;
    } else {
        m_selected = 0;
    }
    return m_selected;
}


void menu_item_renderer::render() {
    // update widgets
    _item->update();
    // ...
}

// Model
void menu::add_view(menuview *v) {
  m_view=v;
}

void menu::update() {
  if (m_view) m_view->update();
}

bool menu::set_selected(int item, int state) {
  m_item[index]=state;
  update();
}
//查看菜单项
bool菜单项::over()
{
如果(::鼠标\u x>m\u x
&&::鼠标x右键
&&::鼠标y更新();
// ...
}
//模型
无效菜单::添加视图(菜单视图*v){
m_视图=v;
}
无效菜单::更新(){
如果(m_视图)m_视图->更新();
}
bool菜单::设置选定项(int项,int状态){
m_项[索引]=状态;
更新();
}

也许更适合?也许,但我对stackoverflow的经验比gamedev丰富,这个问题更多的是关于OOP/MVC的概念,而不是gam
// View menu_item 
bool menu_item::over()
{
    if (::mouse_x > m_x
            && ::mouse_x < m_x + m_w
            && ::mouse_y > m_y
            && ::mouse_y < m_y + m_h) {
        return true;
    }
    return false;
}


// update on gui menu item
bool menu_item::update()
{
    if (over()) {
        m_over = true;
    }
    else {
        m_over = false;
    }
    // onclick for the idea 
    if ((::mouse_b & 1) && m_over) {
        // here you could invoke a callback or fire event
        m_selected = 1;
    } else {
        m_selected = 0;
    }
    return m_selected;
}

// update the command line interface menu item
bool cli_menu_item::update()
{
    if ((::enterKeyPressed & 1) && m_selected) {
        // here you could invoke a callback or fire event
        m_selected = 1;
    } else {
        m_selected = 0;
    }
    return m_selected;
}


void menu_item_renderer::render() {
    // update widgets
    _item->update();
    // ...
}

// Model
void menu::add_view(menuview *v) {
  m_view=v;
}

void menu::update() {
  if (m_view) m_view->update();
}

bool menu::set_selected(int item, int state) {
  m_item[index]=state;
  update();
}