2

我有一个简单的脚本,它显示一个按钮(这是一个 png 图像),当用户单击它时,应用程序退出。

但我想添加多个按钮,我发现我目前的想法会导致很长的 if:else 情况,我想知道这是否是唯一的方法。

这就是我在 main.cpp 文件中设置当前菜单的方式。

bool handle_mouse_leftClick(int x, int y, SDL_Surface *button) {
 if( ( ( mouseX > x ) && ( mouseX < x + button->w ) ) && ( ( mouseY > y ) && ( mouseY < y + button->h ) ) ) {
        return true;
  } else {
        return false;
 }
}

这是我的检测功能。

下面是我的主要功能,它充当我的游戏循环,我已经删除了不相关的代码以使其更容易理解:

//menu button
SDL_Surface *button;
button = IMG_Load("button.png");

while(!quit){
   //handle events
         while( SDL_PollEvent( &event ) ){
               switch(event.type){
                    case SDL_QUIT: quit = true; break;
                    case SDL_MOUSEBUTTONDOWN:

                  if (event.button.button == SDL_BUTTON_LEFT) {
                       if(handle_mouse_leftClick(btnx,btny,button)){
                             quit = true;
                       }
                  }
                    break;
         }
 }

问题是我的 main.cpp 是否应该进行所有这些检查,当我添加更多按钮时会很快变得很长,所以我想知道我是否错过了简化工作的技巧?

4

1 回答 1

2

当您深入了解基本逻辑/计算时,我会说答案是“不”,您没有错过任何技巧。我从来没有找到一种方法来一次检查每个目标 - 至少在计算方面。您可以通过多种方式使您的代码简洁。您可以有一个公开“bool IsIn(int x, int y)”方法的 GuiElement 类。然后你的大案例陈述看起来更像:

bool handle_mouse_leftClick(int x, int y, SDL_Surface *button) 
{
     if (Button1.IsIn( mouseX, mouseY )
     {
         // do this
     }
     else if (Button2.IsIn( mouseX, mouseY ))
     {
         // do that
     } 
     else 
     {
          return false;
     }
 }

然后,您可以使用列表或表格进一步减少金额代码:

int handle_mouse_leftClick(int x, int y, SDL_Surface *button) 
{
     for (unsigned int i = 0; i < buttonList.size(); i++
     {
        if (buttonList[i].IsIn( mouseX, mouseY ))
        {
             return i;   // return index of button pressed
        }
        return -1;   // nothing pressed
     }
 }

但它最终仍然一次只查看每个矩形。

几个警告:

  1. 我认为检查每个项目的命中框并没有太多真正的计算开销——除非你以某种疯狂的高帧速率进行。

  2. 当然,您可以使用某种空间索引(例如由屏幕上按钮的位置组织的 b 树或四叉树)来优化检查,但是……请参阅 #1。;-)

如果您有THOUSANDS而不是 10 或 15 个按钮/控件,那么您可能想要执行 #2,因为 #1 将不再适用。

** * ** * ** *更新* ** * ** * ****

这是可用于此的类的简短示例。至于 .h 与 main.cpp,典型的方法是将标头放在“Button.h”中,将实现(代码)放在“Button.cpp”中,但您可以将其放在 main 的顶部.cpp 开始 - 它在类定义中具有所有逻辑。

你会注意到我并没有真正编写任何新代码。“IsIn()”测试是您的逐字逻辑,我只是​​更改了变量名以匹配类。而且由于您已经有一个按钮,我假设您可以重用渲染该按钮的代码 Render() 方法。

最后,如果不是您熟悉的东西,您根本不必创建列表/向量。呈现按钮的代码可以只调用“okButton.Render()”,然后调用“cancelButton.Render()”。

示例“按钮”类:

class Button
{
private:
    int m_x, m_y;            // coordinates of upper left corner of control
    int m_width, m_height;   // size of control

public:
    Button(int x, int y, int width, int height, const char* caption)
    {
       m_x = x;
       m_y = y;
       m_width = width;
       m_height = height;
       // also store caption in variable of same type you're using now for button text
    }

    bool IsIn( int mouseX, int mouseY )
    {
        if (((mouseX > m_x) && (mouseX < m_x + m_width)) 
        && ((mouseY > m_y) && (mouseY < m_y + m_height ) ) ) {
            return true;
        } else {
            return false;
        }
    }

    void Render()
    {
        // use the same code you use now to render the button in OpenGL/SDL
    }
};

然后创建它/它们(使用列表方法):

Button okButton( 10, 10, 100, 50, "OK" );
buttonList.push_back( okButton );

Button cancelButton( 150, 10, 100, 50, "Cancel" );
buttonList.push_back( cancelButton );

在你的渲染循环中:

void Update()
{
   for (unsigned int i = 0; i < buttonList.size(); i++
   {
       buttonList[i].Render();
   }
}
于 2012-10-30T00:10:45.690 回答