我应该如何在SDL中为多个按钮进行缩放?

时间:2012-10-29 23:54:45

标签: c++ sdl

我有一个简单的脚本,显示一个按钮(这是一个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是否会进行所有这些检查,当我添加更多按钮时会很快变得很长,所以我想知道我是否错过了一个简化我的工作的技巧?

1 个答案:

答案 0 :(得分: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。 ; - )

  3. 如果不是10或15个按钮/控件而是 THOUSANDS ,那么你可能会想要做#2,因为#1将不再是真的。

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

    这是一个可以用于此的类的简短示例。至于.h vs 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();
       }
    }