在C中使用SDL保持内容显示的问题

6gpjuf90  于 2023-08-03  发布在  其他
关注(0)|答案(1)|浏览(99)

我试着用C语言中的SDL做一个游戏界面,用户需要在文本显示后点击开始,这样它就可以把他带到菜单上。但是当文本和按钮显示时,它们消失了,留下了没有文本或按钮的空白图像,但是当我点击按钮应该在的区域时,即使它没有出现在窗口中,它也会把我带到另一个图像。
我不知道如何保持文本和按钮显示,并等待点击“开始按钮”的事件来执行我在代码中编写的操作
代码如下:

#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>

#define SCREEN_WIDTH 1002
#define SCREEN_HEIGHT 584
#define LINE_SPACING 4
#define TEXT_COLOR {0, 0, 0, 0}


// Structure pour représenter une image
typedef struct
{
    SDL_Texture* texture;
    int width;
    int height;
} Image;

// Fonction pour charger une image à partir d'un fichier
Image load_image(SDL_Renderer* renderer, const char* file_path)
{
    SDL_Surface* surface = IMG_Load(file_path);
    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
    SDL_FreeSurface(surface);

    Image image;
    image.texture = texture;
    SDL_QueryTexture(texture, NULL, NULL, &image.width, &image.height);

    return image;
}

// Fonction pour libérer la mémoire occupée par une image
void free_image(Image* image)
{
    SDL_DestroyTexture(image->texture);
}

SDL_Color textColor= {255,255,255,255};
void render_text(SDL_Renderer* renderer, TTF_Font* font, const char* text, SDL_Color color, int x, int y, int delay)
{
    int len = strlen(text);
    char buffer[len + 1];
    memset(buffer, '\0', sizeof(buffer));
    int i = 0;
    bool done = false;
    SDL_Rect rect = { x, y, 0, 0 };
    SDL_Surface* surface = NULL;
    SDL_Texture* texture = NULL;
    Uint32 ticks;

    while (!done)
    {
        ticks = SDL_GetTicks();
        if (i < len)
        {
            strncat(buffer, &text[i], 1);
            surface = TTF_RenderText_Solid(font, buffer, color);
            texture = SDL_CreateTextureFromSurface(renderer, surface);
            rect.w = surface->w;
            rect.h = surface->h;
            SDL_RenderCopy(renderer, texture, NULL, &rect);
            SDL_RenderPresent(renderer);
            i++;
        }
        else
        {
            done = true;
        }
        SDL_Delay(delay - (SDL_GetTicks() - ticks));
    }
    SDL_FreeSurface(surface);
    SDL_DestroyTexture(texture);
}

void Render_text(const char* text, SDL_Rect rect)
{
    SDL_Renderer* renderer = NULL;
    TTF_Font* font = NULL;
    SDL_Surface* surface = TTF_RenderText_Solid(font, text, textColor);
    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
    SDL_FreeSurface(surface);

    int tex_width, tex_height;
    SDL_QueryTexture(texture, NULL, NULL, &tex_width, &tex_height);
    SDL_Rect dstrect = { rect.x + rect.w / 2 - tex_width / 2, rect.y + rect.h / 2 - tex_height / 2, tex_width, tex_height };
    SDL_RenderCopy(renderer, texture, NULL, &dstrect);
    SDL_DestroyTexture(texture);
    TTF_CloseFont(font);
}

void draw_oval(SDL_Renderer* renderer, int x, int y, int radius_x, int radius_y)
{
    const int points = 100;
    const float factor = 2.0f * M_PI / (float)points;
    SDL_Point oval[points];
    for (int i = 0; i < points; i++)
    {
        oval[i].x = x + (int)(radius_x * cosf(i * factor));
        oval[i].y = y + (int)(radius_y * sinf(i * factor));
    }
    SDL_RenderDrawLines(renderer, oval, points);
}

int main(int argc, char* argv[])
{
    SDL_Init(SDL_INIT_VIDEO);
    IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG);
    TTF_Init();

    SDL_Window* window = SDL_CreateWindow("CONNECT 4",
                                          SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                                          SCREEN_WIDTH, SCREEN_HEIGHT, 0);

    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1,
                             SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

    TTF_Font* font1 = TTF_OpenFont("arial.ttf", 29);
    TTF_Font* font2 = TTF_OpenFont("arial.ttf", 35);
    TTF_Font* font = TTF_OpenFont("arial.ttf", 24);

    SDL_Color color = TEXT_COLOR;
    int delay = 50;

    // Charger les images
    Image image1 = load_image(renderer, "back.png");
    Image image2 = load_image(renderer, "hand_close.png");
    Image image3 = load_image(renderer, "handOpen.png");
    Image image4 = load_image(renderer, "menu.png");
    Image image5 = load_image(renderer, "turn.png");
    Image image6 = load_image(renderer, "win.png");

    // Variable pour garder une trace de l'image actuelle
    Image current_image = image1;

    // Effacer l'écran
    SDL_RenderClear(renderer);

    // Afficher l'image actuelle
    SDL_RenderCopy(renderer, current_image.texture, NULL, NULL);

    // Mettre à jour l'écran
    SDL_RenderPresent(renderer);

    //Charger image 2
    SDL_Delay(500);
    current_image = image2;
    // Effacer l'écran
    SDL_RenderClear(renderer);

    // Afficher l'image actuelle
    SDL_RenderCopy(renderer, current_image.texture, NULL, NULL);

    // Mettre à jour l'écran
    SDL_RenderPresent(renderer);

    SDL_Delay(500);

    //charger image 3
    current_image = image3;
    // Effacer l'écran
    SDL_RenderClear(renderer);

    // Afficher l'image actuelle
    SDL_RenderCopy(renderer, current_image.texture, NULL, NULL);

    // Mettre à jour l'écran
    SDL_RenderPresent(renderer);


    SDL_Color color1 = {255, 0, 0, 0};
    render_text(renderer, font1, "You are caught in this castle!", color, 370, 300, delay);
    int y_pos = 350;
    render_text(renderer, font2,"To escape", color, 470, y_pos, delay);
    SDL_RenderPresent(renderer);
    y_pos += 50;
    render_text(renderer, font1, "You need to", color, 470, y_pos, delay);
    y_pos += 50;
    SDL_RenderPresent(renderer);
    render_text(renderer, font2,"WIN this game", color1, 430, y_pos, delay);
    SDL_RenderPresent(renderer);


    // Calcul de la taille du texte "START" pour le centrer dans le bouton
    int oval_width = 100;
    int oval_height = 50;
    int oval_x = (SCREEN_WIDTH - oval_width) /2 +40;
    int oval_y = SCREEN_HEIGHT - oval_height - 10; // mettre une marge de 10 pixels entre le bouton et le bord inférieur de la fenêtre
    SDL_Surface* text_surface = TTF_RenderText_Solid(font, "START", textColor);
    SDL_Texture* text_texture = SDL_CreateTextureFromSurface(renderer, text_surface);
    SDL_Rect text_rect = { oval_x + (oval_width - text_surface->w) / 2, oval_y + (oval_height - text_surface->h) / 2, text_surface->w, text_surface->h };

    // Dessin du bouton ovale
    SDL_SetRenderDrawColor(renderer, 190, 140, 255, 255);

    SDL_Rect oval_rect = { oval_x, oval_y, oval_width, oval_height };

    SDL_RenderFillRect(renderer, &oval_rect);
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderDrawRect(renderer, &oval_rect);

    // Dessin du texte "START" centré dans le bouton
    SDL_RenderCopy(renderer, text_texture, NULL, &text_rect);
    // Affichage du rendu final
    SDL_RenderPresent(renderer);


    SDL_Event event;
    bool done = false;

    while (!done)
    {
        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
            case SDL_QUIT:
                done=true;
                break;
            case SDL_MOUSEBUTTONDOWN:
                // Vérification si le clic de souris est dans la zone du bouton "start"
                if (event.button.x >= oval_x && event.button.x <= oval_x + oval_width && event.button.y >= oval_y && event.button.y <= oval_y + oval_height)
                {
                    if (current_image.texture == image3.texture)
                    {
                        if (event.button.x >= 0 && event.button.x <= 1002 && event.button.y >= 0 && event.button.y <= 584)
                        {
                            current_image = image4;
                            printf("hhh");
                        }
                    }
                    else if (current_image.texture == image4.texture)
                    {
                        if (event.button.x >= 390 && event.button.x <= 610 && event.button.y >= 268 && event.button.y <= 330)
                        {
                            current_image = image5;
                        }
                    }
                    else if (current_image.texture == image5.texture)
                    {
                        if (event.button.x >= 0 && event.button.x <= 1002 && event.button.y >= 0 && event.button.y <= 584)
                        {
                            current_image = image6;
                        }
                    }
                }
                break;
            default:
                break;
            }
        }
        // Effacer l'écran
        SDL_RenderClear(renderer);

        // Afficher l'image actuelle
        SDL_RenderCopy(renderer, current_image.texture, NULL, NULL);

        // Mettre à jour l'écran
        SDL_RenderPresent(renderer);
    }

// Libérer les ressources
    free_image(&image1);
    free_image(&image2);
    free_image(&image3);
    free_image(&image4);
    free_image(&image5);
    free_image(&image6);


    TTF_CloseFont(font);
    TTF_CloseFont(font1);
    TTF_CloseFont(font2);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);

    IMG_Quit();
    TTF_Quit();
    SDL_Quit();

    return 0;
}

字符串

zf9nrax1

zf9nrax11#

**TLDR:**开始按钮不显示,因为在while循环之前只渲染了一次,该循环会清除它并且不再绘制它。

在你的while循环中,当没有事件发生时,你要做的唯一一件事是:

// Clean the screen
SDL_RenderClear(renderer);

// Render the current image
SDL_RenderCopy(renderer, current_image.texture, NULL, NULL);

// Update the screen
SDL_RenderPresent(renderer);

字符串
因此,在while循环开始后的每一帧上,这三条指令是游戏唯一要执行的指令。
以下是他们的工作:

  • 清除当前窗口(基本上使屏幕上的所有内容都是黑色或白色)
  • 渲染current_image.texture中包含的纹理
  • 将渲染器的内容绘制到窗口上

在执行的这一点上,当进入循环时,current_image.texture包含handOpen.png纹理。所以这是唯一能画出来的东西。
即使在循环过程中引发了事件,事件处理代码所做的全部工作也只是交换要呈现的当前图像。
但在任何时候都不要再次呈现开始按钮。
while循环之前**渲染了它:

// Drawing the oval button
SDL_SetRenderDrawColor(renderer, 190, 140, 255, 255);

SDL_Rect oval_rect = { oval_x, oval_y, oval_width, oval_height };

SDL_RenderFillRect(renderer, &oval_rect);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderDrawRect(renderer, &oval_rect);

// Drawing "START" text centered in the button
SDL_RenderCopy(renderer, text_texture, NULL, &text_rect);
// Displaying the final result
SDL_RenderPresent(renderer);


但是,由于您在while循环的每次迭代中都清除了窗口,并且不再绘制开始按钮,因此它不会显示。
下面是while循环的修改版本,希望它能完成这项工作:

SDL_Event event;
bool done = false;
bool showStartButton = true;

while (!done)
{
    while (SDL_PollEvent(&event))
    {
        switch (event.type)
        {
            case SDL_QUIT:
                done = true;
                break;
            case SDL_MOUSEBUTTONDOWN:
                // Checking if the mouse click is in the "start" button's area
                if (event.button.x >= oval_x && event.button.x <= oval_x + oval_width && event.button.y >= oval_y && event.button.y <= oval_y + oval_height)
                {
                    if (current_image.texture == image3.texture)
                    {
                        if (event.button.x >= 0 && event.button.x <= 1002 && event.button.y >= 0 && event.button.y <= 584)
                        {
                            current_image = image4;
                            showStartButton = false;
                        }
                    }
                    else if (current_image.texture == image4.texture)
                    {
                        if (event.button.x >= 390 && event.button.x <= 610 && event.button.y >= 268 && event.button.y <= 330)
                        {
                            current_image = image5;
                        }
                    }
                    else if (current_image.texture == image5.texture)
                    {
                        if (event.button.x >= 0 && event.button.x <= 1002 && event.button.y >= 0 && event.button.y <= 584)
                        {
                            current_image = image6;
                        }
                    }
                }
                break;
            default:
                break;
        }
    }
    // Clean the screen
    SDL_RenderClear(renderer);

    // Render the current image
    SDL_RenderCopy(renderer, current_image.texture, NULL, NULL);

    if (showStartButton) {
        // Drawing the oval button
        SDL_SetRenderDrawColor(renderer, 190, 140, 255, 255);

        SDL_Rect oval_rect = { oval_x, oval_y, oval_width, oval_height };

        SDL_RenderFillRect(renderer, &oval_rect);
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderDrawRect(renderer, &oval_rect);

        // Drawing "START" text centered in the button
        SDL_RenderCopy(renderer, text_texture, NULL, &text_rect);
    }

    // Update the screen
    SDL_RenderPresent(renderer);
}

相关问题