c++ - 如何使用 SDL C++ 在 win32 窗口中设置 GUI 按钮?

标签 c++ sdl

我是 SDL 和游戏开发方面的新手。我想制作游戏,需要在游戏窗口中放置一个“开始”按钮。所以请任何人都可以帮助我如何去做? 整个屏幕上没有鼠标事件我只想创建一个按钮来点击它,我可以在哪里插入按钮的代码? 这是我的代码:

 int main (int argc, char *argv[]){
    int quit = 0;
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window* window = NULL;
    window = SDL_CreateWindow("Snaykie v1.0",350, 150, 800, 500,    SDL_WINDOW_SHOWN);
    if (window == NULL){
        std::cout << "Can not open the game" << std::endl;
        return 0;
    }
    SDL_Renderer* renderer = NULL;
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    SDL_Event* evt = new SDL_Event();

    SDL_Texture* txt = NULL;
    txt = IMG_LoadTexture(renderer, "mainview.bmp");

    SDL_Rect rct;
    rct.x = 0 ;
    rct.y = 0;
    rct.h = 500;
    rct.w = 800;

    SDL_Surface *button = NULL;

    while (!quit && evt->type != SDL_QUIT){
        SDL_PollEvent(evt);
       SDL_RenderClear(renderer);
       SDL_RenderCopy(renderer, txt, NULL, &rct);
       SDL_RenderPresent(renderer);
    }
    SDL_DestroyWindow(window);
    SDL_DestroyRenderer(renderer);
    delete evt;
    return 0;
}

最佳答案

不是一两行那么简单。这是一个例子:

#include <SDL2/SDL.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>

typedef struct {
    SDL_Rect draw_rect;    // dimensions of button
    struct {
        Uint8 r, g, b, a;
    } colour;

    bool pressed;
} button_t;

static void button_process_event(button_t *btn, const SDL_Event *ev) {
    // react on mouse click within button rectangle by setting 'pressed'
    if(ev->type == SDL_MOUSEBUTTONDOWN) {
        if(ev->button.button == SDL_BUTTON_LEFT &&
                ev->button.x >= btn->draw_rect.x &&
                ev->button.x <= (btn->draw_rect.x + btn->draw_rect.w) &&
                ev->button.y >= btn->draw_rect.y &&
                ev->button.y <= (btn->draw_rect.y + btn->draw_rect.h)) {
            btn->pressed = true;
        }
    }
}

static bool button(SDL_Renderer *r, button_t *btn) {
    // draw button
    SDL_SetRenderDrawColor(r, btn->colour.r, btn->colour.g, btn->colour.b, btn->colour.a);
    SDL_RenderFillRect(r, &btn->draw_rect);

    // if button press detected - reset it so it wouldn't trigger twice
    if(btn->pressed) {
        btn->pressed = false;
        return true;
    }
    return false;
}

int main (int argc, char *argv[]){
    int quit = 0;
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window* window = NULL;
    window = SDL_CreateWindow("",350, 150, 800, 500,    SDL_WINDOW_SHOWN);
    if (window == NULL){
        fprintf(stderr, "create window failed: %s\n", SDL_GetError());
        return 1;   // 'error' return status is !0. 1 is good enough
    }

    SDL_Renderer* renderer = NULL;
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if(!renderer) {   // renderer creation may fail too
        fprintf(stderr, "create renderer failed: %s\n", SDL_GetError());
        return 1;
    }

    SDL_Texture* txt = NULL;

    SDL_Rect rct;
    rct.x = 0 ;
    rct.y = 0;
    rct.h = 500;
    rct.w = 800;

    // button state - colour and rectangle
    button_t start_button = {
        .colour = { .r = 255, .g = 255, .b = 255, .a = 255, },
        .draw_rect = { .x = 128, .y = 128, .w = 128, .h = 128 },
    };

    enum {
        STATE_IN_MENU,
        STATE_IN_GAME,
    } state = 0;

    while(!quit) {
        SDL_Event evt;    // no need for new/delete, stack is fine

        // event loop and draw loop are separate things, don't mix them
        while(SDL_PollEvent(&evt)) {
            // quit on close, window close, or 'escape' key hit
            if(evt.type == SDL_QUIT ||
                    (evt.type == SDL_WINDOWEVENT && evt.window.event == SDL_WINDOWEVENT_CLOSE) ||
                    (evt.type == SDL_KEYDOWN && evt.key.keysym.sym == SDLK_ESCAPE)) {
                quit = 1;
            }

            // pass event to button
            button_process_event(&start_button, &evt);
        }

        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);

//      SDL_RenderCopy(renderer, txt, NULL, &rct);

        if(state == STATE_IN_MENU) {
            if(button(renderer, &start_button)) {
                printf("start button pressed\n");
                state = STATE_IN_GAME;   // state change - button will not be drawn anymore
            }
        } else if(state == STATE_IN_GAME) {
            /* your game logic */
        }

        SDL_RenderPresent(renderer);
    }
    SDL_DestroyWindow(window);
    SDL_DestroyRenderer(renderer);
    return 0;
}

(是C,但不是重点)。它绘制一个简单的常色矩形并检测其上的点击。用例如替换矩形是微不足道的。质地;添加文本可能有点困难,使用 SDL_ttf 可能是最简单的方法。

它可能会在很多方面得到改进,这取决于你想要得到什么。例如。它对按下鼠标按钮使用react,而在某些情况下,您可能希望对按钮释放使用react,并跟踪按下和释放按钮的位置。如果你有很多按钮,在每个按钮上调用事件更新是丑陋的,所以你可能想要为此配备不同的系统。您可能还希望拥有非矩形按钮(例如,图像指定的某些形状)——这将需要完全不同的方法,因为您需要检查鼠标点击是否符合形状 mask 。

我建议看一下 imgui .

作为旁注,不要 new SDL_Event,那绝对没有意义。

关于c++ - 如何使用 SDL C++ 在 win32 窗口中设置 GUI 按钮?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39133873/

相关文章:

c++ - 无法解决 Unresolved external 错误 LNK2019 错误

java - 双重检查创建单例问题的方式

c - 依赖 SDL 的应用程序的 Makefile 编译严重失败

c++ - 移动内容后调用 vector.resize(0) 是否安全

c++ - 我可以使用 C++ 类实例作为 Objective-C++ id 吗?

c++ - SDL2 平滑时间点之间的纹理( Sprite )动画功能

c++ - glVertexAttribDivisor 在 nVidia 上无法正常工作?

c++ - 不支持 GLSL 330 内核

c++ - 如何使基于 tslib 的校准保持永久?