I try to make a game interface using SDL in C language, where the user needs to click on start after the text is displayed so that it takes him to the menu. But when the text and the button is displayed, they disapear leaving the image blank without text or button, but when I click in the area where the button is supposed to be even if it's not appearing in the window, it takes me to the other image.
I don't know how to keep the text and button displayed and wait for the event of click on the "start button" to perform the action I wrote in the code
Here is the code :
#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;
}
TLDR: The start button doesn't show up because you render it only once before a
whileloop that clears it and never draws it again.In your
whileloop, the only thing you do when no events are raised is:So on each frame since the
whileloop has started, these three instructions are the only ones to be executed by your game.Here are what they do:
current_image.textureAnd at this point of execution, when entering the loop,
current_image.texturecontains thehandOpen.pngtexture. So it is the only thing to get drawn.Even if an event is raised during the loop, all your event handling code does is swapping the current image to render.
But at no point do you render your start button again.
You did render it before the
whileloop:But since you clear the window on each iteration of the
whileloop and never draw the start button again, it does not show up.Here is a revised version of your
whileloop that should hopefully do the work: