2

1つのボタン(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

基本的なロジック/計算に取り掛かると、答えは「いいえ」です。トリックを見逃していません。少なくとも計算に関しては、各ターゲットを一度に 1 つずつチェックする方法を見つけたことがありません。多くの方法でコードをよりきれいにすることができます。「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 つずつ調べています。

カップルの注意事項:

  1. 各アイテムのヒットボックスをチェックするのに実際の計算上のオーバーヘッドはあまりないと思います - あなたが非常に高いフレームレートでそれをしているのでない限り.

  2. 確かに、ある種の空間インデックス (画面上のボタンの位置によって編成された b ツリーまたはクアッド ツリーなど) を使用してチェックを最適化することはできますが、#1 を参照してください。;-)

10 個または 15 個のボタン/コントロールの代わりに何千ものボタン/コントロールがある場合は、#1 が当てはまらないため、おそらく #2 を実行する必要があります。

** * ** * ** *アップデート* ** * ** * ****

これに使用できるクラスの簡単なサンプルを次に示します。.h と main.cpp に関する限り、典型的なアプローチは、ヘッダーを「Button.h」に配置し、実装 (コード) を「Button.cpp」に配置することですが、これを main の先頭に配置することもできます。 .cpp を使用して開始します。クラス定義にすべてのロジックが含まれています。

私が実際に新しいコードを書いていないことに気付くでしょう。「IsIn()」テストはあなたの論理そのものです。クラスに合わせて変数名を変更しただけです。そして、既に 1 つのボタンがあるので、そのボタンをレンダリングするコードを 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 に答える