diff --git a/V1/data.c b/V1/data.c new file mode 100644 index 0000000000000000000000000000000000000000..8715d1b569a095ff1f66abf5e12ea00d40c86077 --- /dev/null +++ b/V1/data.c @@ -0,0 +1,126 @@ +/** + * \file data.c + * \brief Gestion des données du jeu + * \author DJERMOUNI Yanis - YATIME Marouane + * \date 26 mai 2021 + */ +#include <stdio.h> +#include <stdlib.h> + +#include "sdl2.h" +#include "const.h" +#include "graphics.h" +#include "logic.h" +#include "data.h" + + + +/** + * \brief La fonction indique si le jeu est fini en fonction des données du monde + * \param world les données du monde + * \return 1 si le jeu est fini, 0 sinon + */ +int is_game_over(world_t *world){ + if(world->gameover != CONTINUE) + return 1; + return 0; +} + + + +void init_bullet(spaceship_t *spaceship) +{ + if(spaceship->bullets.bullet_nb+1 < NB_BULLETS) + { + init_sprite(&spaceship->bullets.bullet[spaceship->bullets.bullet_nb].bullet, spaceship->spaceship.x + SHIP_SIZE/2 - BULLET_SIZE/2, spaceship->spaceship.y, BULLET_SIZE, BULLET_SIZE, BULLET); + spaceship->bullets.bullet[spaceship->bullets.bullet_nb].vy = 0.02*INITIAL_SPEED; + spaceship->bullets.bullet_nb++; + } +} + + +/** + * \brief La fonction initialise le spaceship + * \param spaceship le spaceship + */ +void init_spaceship(spaceship_t *spaceship) +{ + init_sprite(&spaceship->spaceship, SCREEN_WIDTH/2 - SHIP_SIZE/2, SCREEN_HEIGHT - SHIP_SIZE, SHIP_SIZE, SHIP_SIZE, SPACESHIP); + spaceship->bullets.bullet_nb = 0; // pas utilisé au départ +} + + +/** + * \brief La fonction initialise un sprite + * \param sprite le sprite + * \param x abscisse + * \param y ordonnée + * \param w largeur + * \param h hauteur + */ +void init_sprite(sprite_t *sprite, double x, double y, double w, double h, int type){ + sprite->x = x; + sprite->y = y; + sprite->w = w; + sprite->h = h; + sprite->is_visible = 1; + sprite->type = type; +} + + +/** + * \brief La fonction initialise les données du monde du jeu + * \param world les données du monde + */ +void init_data(world_t *world){ + init_sprite(&world->finish_line, 0, -60000, SCREEN_WIDTH, FINISH_LINE_HEIGHT, FINISH_LINE); + init_spaceship(&world->spaceship); + init_sprite(&world->background, 0, -SCREEN_HEIGHT*100, SCREEN_WIDTH, SCREEN_HEIGHT, BACKGROUND); + world->vy = INITIAL_SPEED; + + //on n'est pas à la fin du jeu + world->gameover = CONTINUE; +} + + +/** + * \brief La fonction nettoie les données du monde + * \param world les données du monde + */ +void clean_data(world_t *world){ + /* utile uniquement si vous avez fait de l'allocation dynamique (malloc); la fonction ici doit permettre de libérer la mémoire (free) */ + +} + + + +void update_bullets(world_t *world) +{ + + for(int j = 0; j < world->spaceship.bullets.bullet_nb; j++) + { + if(!world->spaceship.bullets.bullet[j].bullet.is_visible) + world->spaceship.bullets.bullet[j].vy = -world->vy; + world->spaceship.bullets.bullet[j].bullet.y -= world->spaceship.bullets.bullet[j].vy; + + } + +} + +void update_background(world_t* world){ + world->background.y += world->vy; +} + +/** + * \brief La fonction met à jour les données en tenant compte de la physique du monde + * \param renderer + * \param world les données du monde + */ +void update_data(world_t *world){ + //world->finish_line.y += world->vy; + screen_collide(&world->spaceship.spaceship); + handle_sprites_collision(&world->spaceship.spaceship, &world->finish_line, world); + update_bullets(world); + update_background(world); +} + diff --git a/V1/event.c b/V1/event.c new file mode 100644 index 0000000000000000000000000000000000000000..49805e54f8cec00e6553bd45664a734be2b84afd --- /dev/null +++ b/V1/event.c @@ -0,0 +1,44 @@ +/** + * \file event.c + * \brief Gestion des entrées claviers du joueur + * \author DJERMOUNI Yanis - YATIME Marouane + * \date 26 mai 2021 + */ +#include <stdio.h> +#include <stdlib.h> + +#include "sdl2.h" +#include "const.h" +#include "event.h" +#include "data.h" + +/** + * \brief La fonction gère les évènements ayant eu lieu et qui n'ont pas encore été traités + * \param event paramètre qui contient les événements + * \param world les données du monde + */ +void handle_events(SDL_Event *event, world_t *world){ + while( SDL_PollEvent( event ) ) { + //Si l'utilisateur a cliqué sur le X de la fenêtre + if( event->type == SDL_QUIT ) { + //On indique la fin du jeu + world->gameover = EXIT; + } + + //si une touche est appuyée + if(event->type == SDL_KEYDOWN){ + if(event->key.keysym.sym == SDLK_ESCAPE) //Echap + world->gameover = EXIT; + if(event->key.keysym.sym == SDLK_LEFT) //Fleche de gauche + world->spaceship.spaceship.x -= MOVING_STEP; + if(event->key.keysym.sym == SDLK_RIGHT) //Fleche de droite + world->spaceship.spaceship.x += MOVING_STEP; + if(event->key.keysym.sym == SDLK_DOWN) //Fleche du bas + world->vy -=5; + if(event->key.keysym.sym == SDLK_UP) //Fleche du haut + world->vy +=5; + if(event->key.keysym.sym == SDLK_SPACE) + init_bullet(&world->spaceship); + } + } +} diff --git a/V1/graphics.c b/V1/graphics.c new file mode 100644 index 0000000000000000000000000000000000000000..381cf0b6c3753303411fd871580ba23fa0a3afe4 --- /dev/null +++ b/V1/graphics.c @@ -0,0 +1,168 @@ +/** + * \file graphics.c + * \brief Gestion de l'affichage du jeu + * \author DJERMOUNI Yanis - YATIME Marouane + * \date 26 mai 2021 + */ +#include <stdio.h> +#include <stdlib.h> + +#include "sdl2.h" +#include "const.h" +#include "graphics.h" +#include "data.h" + +/** + * \brief La fonction initialise les textures nécessaires à l'affichage graphique du jeu + * \param screen la surface correspondant à l'écran de jeu + * \param ressources les ressources du jeu +*/ +void init_textures(SDL_Renderer *renderer, ressources_t *ressources) +{ + ressources->background = load_image( "ressources/road.bmp", renderer); + ressources->spaceship = load_image( "ressources/voiture.bmp", renderer); + ressources->finish_line = load_image( "ressources/finish_line.bmp", renderer); + ressources->meteorite = load_image( "ressources/meteorite.bmp", renderer); + ressources->bullet = load_image( "ressources/bullet.bmp", renderer); + ressources->font = load_font("ressources/BNKGOTHM.TTF", 15); +} + + +/** + * \brief La fonction nettoie les textures + * \param ressources les ressources du jeu +*/ +void clean_textures(ressources_t *ressources) +{ + clean_texture(ressources->background); + clean_texture(ressources->spaceship); + clean_texture(ressources->finish_line); + clean_texture(ressources->meteorite); + clean_texture(ressources->bullet); + clean_font(ressources->font); +} + + +/** + * \brief La fonction applique la texture du fond sur le renderer lié à l'écran de jeu + * \param renderer le renderer + * \param texture la texture liée au fond +*/ +void apply_background(SDL_Renderer *renderer, SDL_Texture *texture) +{ + if(texture != NULL) + apply_texture(texture, renderer, 0, 0); +} + + +/** + * \brief La fonction applique un sprite sur le renderer lié à l'écran de jeu + * \param renderer le renderer + * \param texture la texture + * \param sprite la texture liée au sprite +*/ +void apply_sprite(SDL_Renderer *renderer, SDL_Texture *texture, sprite_t* sprite) +{ + if(texture != NULL && sprite->is_visible) + apply_texture(texture, renderer, sprite->x, sprite->y); +} + + + +/** + * \brief La fonction applique les meteores sur le renderer lié à l'écran de jeu + * \param renderer le renderer + * \param texture la texture + * \param world les données du monde +*/ +void apply_bullets(SDL_Renderer *renderer, SDL_Texture *texture, bullets_t *bullets){ + for(int i = 0; i < bullets->bullet_nb; i++) + apply_sprite(renderer, texture, &bullets->bullet[i].bullet); +} + + +/** + * \brief La fonction applique tout les textes du jeu (au moment voulu) sur le renderer lié à l'écran de jeu + * \param renderer le renderer + * \param texture la texture + * \param world les données du monde +*/ +void print_all_text(SDL_Renderer *renderer, ressources_t *ressources, world_t *world) +{ + //Timer + char timer[20]; + sprintf(timer, "Temps : %.3lf", (double)(SDL_GetTicks() - world->t0)/(double)1000); + apply_text(renderer, 0, 0, 200, 14*2, timer, ressources->font,(SDL_Color){250, 0, 137}); + + //Message de fin + if(world->gameover == WIN) + apply_text(renderer, (SCREEN_WIDTH-250)/2, (SCREEN_HEIGHT-14*4)/2, 250, 14*4, "Victoire!", ressources->font,(SDL_Color){250, 0, 137}); + else if(world->gameover == LOOSE) + apply_text(renderer, (SCREEN_WIDTH-250)/2, (SCREEN_HEIGHT-14*4)/2, 250, 14*4, "Gameover", ressources->font,(SDL_Color){250, 0, 137}); +} + + +/** + * \brief La fonction qui affiche un menu pour commencer le jeu + * \param renderer le renderer + * \param texture la texture + * \param world les données du monde +*/ +void print_menu_debut(SDL_Renderer *renderer, ressources_t *ressources, world_t *world){ + apply_background(renderer, ressources->background); + //message de menu + apply_text(renderer, (SCREEN_WIDTH-610), 20, 400, 14*4, "Bienvenue", ressources->font,(SDL_Color){243, 89, 0}); + apply_text(renderer, (SCREEN_WIDTH-620), 160, 400, 14*4, "Appuyer sur ", ressources->font,(SDL_Color){243, 89, 0}); + apply_text(renderer, (SCREEN_WIDTH-620), 210, 400, 14*4, "'ENTRER'", ressources->font,(SDL_Color){240, 248, 255, 0.993}); + apply_text(renderer, (SCREEN_WIDTH-620), 250, 400, 14*4, "pour commencer", ressources->font,(SDL_Color){243, 89, 0}); + apply_text(renderer, (SCREEN_WIDTH-800), 600, 200, 14*3, "YATIME MAROUANE", ressources->font,(SDL_Color){253, 217, 13}); + apply_text(renderer, (SCREEN_WIDTH-250), 600, 200, 14*3, "AIT OUALI MAROUANE", ressources->font,(SDL_Color){253, 217, 13}); + update_screen(renderer); + +} + + +/** + * \brief La fonction qui affiche un menu dans la fin du jeu + * \param renderer le renderer + * \param texture la texture + * \param world les données du monde +*/ +void print_menu_fin(SDL_Renderer *renderer, ressources_t *ressources, world_t *world){ + apply_background(renderer, ressources->background); + //message de menu + apply_text(renderer, (SCREEN_WIDTH-250), 0, 200, 14*4, "MERCI DE VOTRE", ressources->font,(SDL_Color){243, 89, 0}); + apply_text(renderer, (SCREEN_WIDTH-250), 50, 200, 14*4, "PARTICIPATION", ressources->font,(SDL_Color){243, 89, 0}); + apply_text(renderer, (SCREEN_WIDTH-250), 160, 200, 14*4, "Appuyer sur ", ressources->font,(SDL_Color){243, 89, 0}); + apply_text(renderer, (SCREEN_WIDTH-250), 210, 200, 14*4, "'ENTRER'", ressources->font,(SDL_Color){240, 248, 255, 0.993}); + apply_text(renderer, (SCREEN_WIDTH-250), 250, 200, 14*4, "pour REJOUER", ressources->font,(SDL_Color){243, 89, 0}); + apply_text(renderer, (SCREEN_WIDTH-300), 452, 120, 14*2.3, "YATIME MAROUANE", ressources->font,(SDL_Color){253, 217, 13}); + apply_text(renderer, (SCREEN_WIDTH-125), 452, 123, 14*2.3, "DJERMOUNI YANIS", ressources->font,(SDL_Color){253, 217, 13}); + + update_screen(renderer); + +} + + +/** + * \brief La fonction rafraichit l'écran en fonction de l'état des données du monde + * \param renderer le renderer lié à l'écran de jeu + * \param world les données du monde + * \param textures les textures + */ +void refresh_graphics(SDL_Renderer *renderer, world_t *world, ressources_t *ressources){ + + //application des ressources dans le renderer + sprite_t tmp = world->background; + for(int i = 0; i < 200; i++){ + apply_sprite(renderer, ressources->background, &tmp); + tmp.y += SCREEN_HEIGHT; + } + + apply_sprite(renderer, ressources->spaceship, &world->spaceship.spaceship); + apply_sprite(renderer, ressources->finish_line, &world->finish_line); + apply_bullets(renderer, ressources->bullet, &world->spaceship.bullets); + print_all_text(renderer, ressources, world); + // on met à jour l'écran + update_screen(renderer); +} diff --git a/V1/logic.c b/V1/logic.c new file mode 100644 index 0000000000000000000000000000000000000000..98e33b0011c0d94b61174611e6016ed4c8f72e28 --- /dev/null +++ b/V1/logic.c @@ -0,0 +1,77 @@ +/** + * \file logic.c + * \brief Gestion de la logique du jeu (physique) + * \author DJERMOUNI Yanis - YATIME Marouane + * \date 26 mai 2021 + */ +#include <stdio.h> +#include <stdlib.h> + +#include "sdl2.h" +#include "const.h" + +#include "logic.h" +#include "data.h" + + + +/** + * \brief gere les collisions entre le sprite et l'écran (gauche et droite) + * \param s le sprite + */ +void screen_collide(sprite_t* sprite) +{ + //left + if(sprite->x < 145) // Trouvé a l aide des pixels du background + sprite->x = 145; + //right + if(sprite->x + sprite->w > 700) // 700 taille de la piste de route + sprite->x = 700 - sprite->w; +} + + +/** + * \brief gere les collisions entre deux sprites + * \param sp1 un sprite + * \param sp2 un sprite + * \return 1 si collision, 0 sinon + */ +int sprites_collide(sprite_t *sp1, sprite_t *sp2){ + if(abs(sp1->x + sp1->w/2 - sp2->x - sp2->w/2) <= (sp1->w + sp2->w)/2 && abs(sp1->y + sp1->h/2 - sp2->y - sp2->h/2) <= (sp1->h + sp2->h)/2) + return 1; + return 0; +} + + +/** + * \brief rend la vitesse(world.vy) nulle lors de la collision + * \param sp1 un sprite + * \param sp2 un sprite + * \param world les données du monde + * \param make_disappear vaut 1 si on doit faire disparaître le sprite, 0 si on ne veut pas, autre cas particulier + * \return 1 si une meteore doit être détruite, 0 sinon + */ +void handle_sprites_collision(sprite_t *sp1, sprite_t *sp2, world_t *world) +{ + if(sprites_collide(sp1, sp2) == 1) + { + if((sp1->type == SPACESHIP && sp2->type == FINISH_LINE) || (sp2->type == SPACESHIP && sp1->type == FINISH_LINE)) + { + world->spaceship.spaceship.is_visible = 0; + world->gameover = WIN; + } + else if(((sp1->type == SPACESHIP && sp2->type != FINISH_LINE) || (sp2->type == SPACESHIP && sp1->type != FINISH_LINE)) && (sp1->is_visible && sp2->is_visible)) + { + world->spaceship.spaceship.is_visible = 0; + world->gameover = LOOSE; + } + else if((sp1->type == BULLET && sp2->type == METEORE && sp2->is_visible) || (sp2->type == BULLET && sp1->type == METEORE && sp1->is_visible)) + { + sp2->is_visible = 0; + sp1->is_visible = 0; + } + + } + if(world->gameover == CONTINUE) + world->gameover = CONTINUE; +} diff --git a/V1/main.c b/V1/main.c new file mode 100644 index 0000000000000000000000000000000000000000..f0920940960cbeb5e65e45a01c63ea70ff28aa5a --- /dev/null +++ b/V1/main.c @@ -0,0 +1,138 @@ +/** + * \file main.c + * \brief Boucle de jeu + * \author DJERMOUNI Yanis - YATIME Marouane + * \date 26 mai 2021 + */ +#include <stdio.h> +#include <stdlib.h> + +#include "sdl2.h" +#include "sdl2-ttf.h" +#include "const.h" +#include "graphics.h" +#include "logic.h" +#include "data.h" +#include "event.h" + + + +/** + * \brief fonction qui initialise le jeu: initialisation de la partie graphique (SDL), chargement des textures, initialisation des données + * \param window la fenêtre du jeu + * \param renderer le renderer + * \param ressources les ressources + * \param world le monde + */ +void init(SDL_Window **window, SDL_Renderer ** renderer, ressources_t *ressources, world_t * world){ + init_sdl(window,renderer,SCREEN_WIDTH, SCREEN_HEIGHT); + init_ttf(); + init_data(world); + init_textures(*renderer,ressources); +} + + +/** +* \brief fonction qui nettoie le jeu: nettoyage de la partie graphique (SDL), nettoyage des textures, nettoyage des données +* \param window la fenêtre du jeu +* \param renderer le renderer +* \param ressources les ressources +* \param world le monde +*/ +void clean(SDL_Window *window, SDL_Renderer * renderer, ressources_t *ressources, world_t * world){ + clean_data(world); + clean_textures(ressources); + clean_ttf(); + clean_sdl(renderer,window); +} + + +/** +* \brief fonction qui permet de relancer la boucle de jeu après une partie finie +* \param world le monde +*/ +void re_init(world_t * world) +{ + clean_data(world); + init_data(world); + world->t0 = SDL_GetTicks(); +} + + + +/** + * \brief programme principal qui implémente la boucle du jeu + */ +int main(int argc, char* args[]) +{ + SDL_Event event; + world_t world; + ressources_t ressources; + SDL_Renderer *renderer; + SDL_Window *window; + + //initialisation du jeu + init(&window,&renderer,&ressources,&world); + + //affichage du menu dans le début + print_menu_debut(renderer, &ressources, &world); + while(1) { + if(SDL_PollEvent(&event)) { + //ENTRER est pressée + if(event.key.keysym.sym == SDLK_RETURN + || event.key.keysym.sym == SDLK_RETURN2 + || event.key.keysym.sym == SDLK_KP_ENTER) { break; } + + //ECHAP ou si on quitte + if(event.type == SDL_QUIT + || event.key.keysym.sym == SDLK_ESCAPE) + { + clean(window,renderer,&ressources,&world); + return 0; + } + } + } + + world.t0 = SDL_GetTicks(); + + while(1){ //tant que le jeu n'est pas fini + //gestion des évènements + handle_events(&event,&world); + + //mise à jour des données liée à la physique du monde + update_data(&world); + + //rafraichissement de l'écran + refresh_graphics(renderer, &world,&ressources); + + //pause de 10 ms pour controler la vitesse de rafraichissement + pause(10); + + if(is_game_over(&world)) + { + pause(2000); + + //afichage du menu dans la fin du jeu + print_menu_fin(renderer, &ressources, &world); + while(1) { + if(SDL_PollEvent(&event)) { + //ENTRER est pressée + if(event.key.keysym.sym == SDLK_RETURN + || event.key.keysym.sym == SDLK_RETURN2 + || event.key.keysym.sym == SDLK_KP_ENTER) { re_init(&world); break;} + + //ECHAP ou si on quitte + if(event.type == SDL_QUIT + || event.key.keysym.sym == SDLK_ESCAPE) + { + clean(window,renderer,&ressources,&world); + return 0; + } + } + } + } + } + + //Jamais atteint + return 0; +} diff --git a/V1/sdl2-ttf.c b/V1/sdl2-ttf.c new file mode 100644 index 0000000000000000000000000000000000000000..b0590d0d6860b3b2818e97b4c0ca5fb5ef5b85e4 --- /dev/null +++ b/V1/sdl2-ttf.c @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "sdl2-ttf.h" + +void init_ttf(){ + if(TTF_Init()==-1) { + printf("TTF_Init: %s\n", TTF_GetError()); + } +} + + + +TTF_Font * load_font(const char *path, int font_size){ + TTF_Font *font = TTF_OpenFont(path, font_size); + if(font == NULL){ + fprintf(stderr, "Erreur pendant chargement font: %s\n", SDL_GetError()); + } + return font; +} + + + + + +void apply_text(SDL_Renderer *renderer, int x, int y, int w, int h, const char *text, TTF_Font *font, SDL_Color color){ + SDL_Surface* surface = TTF_RenderText_Solid(font, text, color); + + SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface); + SDL_Rect dstrect2 = {x, y, w, h}; + SDL_RenderCopy(renderer, texture, NULL, &dstrect2); + +} + +void clean_font(TTF_Font * font){ + TTF_CloseFont(font); +} + + +void clean_ttf(){ + TTF_Quit(); +} diff --git a/V1/sdl2.c b/V1/sdl2.c new file mode 100644 index 0000000000000000000000000000000000000000..8dc898cdf847743190cfbf92fbe128cc83de4ca2 --- /dev/null +++ b/V1/sdl2.c @@ -0,0 +1,98 @@ +/** + * \file sdl2-light.c + * \brief sur-couche de SDL2 pour simplifier son utilisation pour le projet + * \author Mathieu Constant + * \version 0.2 + * \date 10 mars 2021 +*/ + +#include "sdl2.h" +#include <stdio.h> +#include <stdlib.h> + + + +int init_sdl(SDL_Window **window, SDL_Renderer **renderer, int width, int height) +{ + if(0 != SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)) + { + fprintf(stderr, "Erreur initialisation de la SDL : %s", SDL_GetError()); + return -1; + } + if(0 != SDL_CreateWindowAndRenderer(width, height, SDL_WINDOW_SHOWN, window, renderer)) + { + fprintf(stderr, "Erreur lors de la creation de l'image et du renderer : %s", SDL_GetError()); + return -1; + } + return 0; +} + + + + +SDL_Texture *load_image(const char path[], SDL_Renderer *renderer) +{ + SDL_Surface *tmp = NULL; + SDL_Texture *texture = NULL; + tmp = SDL_LoadBMP(path); + if(NULL == tmp) + { + fprintf(stderr, "Erreur pendant chargement image BMP: %s", SDL_GetError()); + return NULL; + } + SDL_SetColorKey(tmp, SDL_TRUE, SDL_MapRGB(tmp->format, 255, 0, 255)); + texture = SDL_CreateTextureFromSurface(renderer, tmp); + SDL_FreeSurface(tmp); + if(NULL == texture) + { + fprintf(stderr, "Erreur pendant creation de la texture liee a l'image chargee: %s", SDL_GetError()); + return NULL; + } + return texture; +} + + +void apply_texture(SDL_Texture *texture,SDL_Renderer *renderer,int x, int y){ + SDL_Rect dst = {0, 0, 0, 0}; + + SDL_QueryTexture(texture, NULL, NULL, &dst.w, &dst.h); + dst.x = x; dst.y=y; + + SDL_RenderCopy(renderer, texture, NULL, &dst); + +} + + +void clean_texture(SDL_Texture *texture){ + if(NULL != texture){ + SDL_DestroyTexture(texture); + } + +} + + +void clear_renderer(SDL_Renderer *renderer){ + SDL_RenderClear(renderer); +} + + + + +void update_screen(SDL_Renderer *renderer){ + SDL_RenderPresent(renderer); +} + + + +void pause(int time){ + SDL_Delay(time); +} + + +void clean_sdl(SDL_Renderer *renderer,SDL_Window *window){ + if(NULL != renderer) + SDL_DestroyRenderer(renderer); + if(NULL != window) + SDL_DestroyWindow(window); + SDL_Quit(); +}