/* [CONSTRUCTOR] Constructeur de la classe =========================================================*/ xManager::xManager(const char *t, int w, int h){ // default values _lasttick = SDL_GetTicks(); _fpstime = 1000/60; _window = NULL; _renderer = NULL; _texture = NULL; _debug = (SDL_Rect){0, 0, 0, 0}; // Initialisation des sous-sys. SDL SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER ); // Creation de la fenetre _window = SDL_CreateWindow( t, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_BORDERLESS | SDL_WINDOW_OPENGL ); // Gestion erreur if( _window == NULL ) return; cerr << "WINDOW CREATED" << endl; // On enregistre les dimensions de la fenetre _winrect.x = 0; _winrect.y = 0; _winrect.w = w; _winrect.h = h; SDL_GetWindowSize(_window, &_winrect.w, &_winrect.h); // Creation du renderer _renderer = SDL_CreateRenderer( _window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC ); // Gestion erreur if( _renderer == NULL ) return; cerr << "RENDERER CREATED" << endl; } /* [DESTROYER] Destructeur de la classe =========================================================*/ xManager::~xManager(){ SDL_DestroyTexture(_texture); SDL_DestroyRenderer(_renderer); SDL_DestroyWindow( _window ); SDL_Quit(); } /* [STATUS] Retourne le status =========================================================*/ bool xManager::status(){ return _window != NULL && _renderer != NULL; } /* [WINDOW] Retourne la fenetre =========================================================*/ SDL_Window* xManager::window(){ return _window; } /* [SCREEN] Retourne la fenetre =========================================================*/ SDL_Renderer* xManager::renderer(){ return _renderer; } /* [SETBACKGROUND] Modifie la couleur de fond =========================================================*/ bool xManager::setBackground(Uint8 r, Uint8 g, Uint8 b, Uint8 a){ if( !this->status() ) return false; SDL_SetRenderDrawColor( _renderer, r, g, b, a ); return true; } /* [SETIMAGE] Met une image en fond =========================================================*/ bool xManager::setImage(const char *url){ if( !this->status() ) return false; // On cree la texture associee _texture = IMG_LoadTexture( _renderer, url ); return _texture != NULL; } /* [COLLIDE] Retourne si 2 objets sont en collision =========================================================*/ // collisions *> // [0] -> VRAI si collision a droite // [1] -> VRAI si collision a gauche // [2] -> VRAI si collision en haut // [3] -> VRAI si collision en bas bool xManager::collide(SDL_Rect a, SDL_Rect b, vector& cols){ if( !this->status() ) return true; // Verification de collisions bool outLeft = (a.x >= b.x+b.w ); // Trop a droite bool outRight = (a.x+a.w <= b.x ); // Trop a gauche bool outUp = (a.y >= b.y+b.h ); // Trop en haut bool outDown = (a.y+a.h <= b.y ); // Trop en bas // Calcule du bord en question int distLeft = abs( (a.x+a.w) - b.x ); int distRight = abs( a.x - (b.x+b.w) ); int distBottom = abs( a.y - (b.y+b.h) ); int distTop = abs( (a.y+a.h) - b.y ); // Valeurs de retour pointeur cols[0] = !outRight && distRight <= 1; // plus proche de droite cols[1] = !outLeft && distLeft <= 2; // plus proche de gauche cols[2] = !outUp && distTop <= 2; // plus proche du haut cols[3] = !outDown && distBottom <= 1; // plus proche du bas // On retourne si il y a collision ou pas return !( outRight || outLeft || outUp || outDown ); } /* [HIT] Retourne si une texture est en collision avec une autre =========================================================*/ bool xManager::hit(xSprite* current, int movex, int movey){ if( !this->status() ) return true; // Anti conflit inter-thread _mutex_hit.try_lock(); /* (1) On recupere le SDL_Rect destination du sprite courant */ int xIndex = -1; for( int i = 0 ; i < _sprites.size() ; i++ ) if( _sprites[i] == current ){ xIndex = i; break; } if( xIndex == -1 ){ _mutex_hit.unlock(); return false; } SDL_Rect a = *current->dst(); a.x += movex; a.y += movey; // Contiendra le sens de collision vector collideFrom(4, false); // Contiendra le sens de collision vector collideTo(4, false); /* (2) On regarde si en dehors de la fenetre */ if( (a.x < _winrect.x ) // Inclus a droite || (a.x+a.w > _winrect.x+_winrect.w ) // Inclus a gauche || (a.y < _winrect.y ) // Inclus en haut || (a.y+a.h > _winrect.y+_winrect.h ) // Inclus en bas ){ // Si on tombe, on meurt if( a.y+a.h > _winrect.y+_winrect.h ) state = 2; cerr << _indexes[xIndex] << " collide with WINDOW" << endl; _mutex_hit.unlock(); return true; } /* (3) On compare avec toutes les autres textures */ for( int i = 0 ; i < _sprites.size() ; i++ ){ // Si c'est pas le sprite courant if( _sprites[i] != current ){ // On verifie que le sprite n'entre pas en collision if( this->collide(a, *(_sprites[i])->dst(), collideTo) ){ // On recupere la surface en collision inverse collideFrom[0] = collideTo[1]; // On inverse Droite collideFrom[1] = collideTo[0]; // et Gauche collideFrom[2] = collideTo[3]; // On inverse Haut collideFrom[3] = collideTo[2]; // et Bas // On lance les listeners de collision _sprites[i]->onCollide(collideTo, current); current->onCollide(collideFrom, _sprites[i]); _debug = *(_sprites[i])->dst(); _mutex_hit.unlock(); return true; } } } // On debloque la ressource _mutex_hit.unlock(); return false; } /* [HIT] Retourne si une texture est en collision avec une autre =========================================================*/ bool xManager::hit(string current, int movex, int movey){ if( !this->status() ) return true; _mutex_hit.try_lock(); /* (1) On recupere le SDL_Rect destination du sprite courant */ xSprite *sprite = NULL; sprite = this->get(current); // Gestion erreur if( sprite == NULL ){ _mutex_hit.unlock(); return false; } // Retour du resultat _mutex_hit.unlock(); return this->hit(sprite, movex, movey); } /* [GET] Renvoie le sprite =========================================================*/ xSprite *xManager::get(string index){ if( !this->status() ) return NULL; // On cherche la texture avec l'index for( int i = 0 ; i < _indexes.size() ; i++ ) if( _indexes[i] == index ) return _sprites[i]; return NULL; } /* [PUSH] Ajoute une texture au rendu principal =========================================================*/ void xManager::push(string index, xSprite* sprite){ if( !this->status() ) return; // On bloque l'acces inter-thread _mutex_push.try_lock(); _indexes.push_back( index ); _sprites.push_back( sprite ); // On debloque l'acces _mutex_push.unlock(); } /* [PULL] Retire une texture du rendu principal =========================================================*/ void xManager::pull(string index){ if( !this->status() ) return; // On bloque l'acces inter-thread _mutex_pull.try_lock(); // On cherche l'indice de la texture int xIndex = -1; for( int i = 0 ; i < _indexes.size() ; i++ ) if( _indexes[i] == index ) xIndex = i; // Si on a rien trouve if( xIndex == -1 ) return; // On supprime la texture et ses dimensions _indexes.erase( _indexes.begin() + xIndex ); _sprites.erase( _sprites.begin() + xIndex ); // On debloque l'acces _mutex_pull.unlock(); } /* [PULL] Retire une texture du rendu principal =========================================================*/ void xManager::pull(xSprite* sprite){ if( !this->status() ) return; // On bloque l'acces inter-thread _mutex_pull.try_lock(); // On cherche l'indice de la texture int xIndex = -1; for( int i = 0 ; i < _sprites.size() ; i++ ) if( _sprites[i] == sprite ) xIndex = i; // Si on a rien trouve if( xIndex == -1 ) return; // On supprime la texture et ses dimensions _indexes.erase( _indexes.begin() + xIndex ); _sprites.erase( _sprites.begin() + xIndex ); // On debloque l'acces _mutex_pull.unlock(); } /* [CLEARALL] Supprime toutes les sprites =========================================================*/ void xManager::clearAll(){ _indexes.erase( _indexes.begin(), _indexes.end() ); _sprites.erase( _sprites.begin(), _sprites.end() ); } /* [MANAGEFTP] Gestion de la vitesse de boucle =========================================================*/ void xManager::manageFps(const int fps){ if( !this->status() ) return; /* (1) Definition de fps */ if( fps != 0 ) _fpstime = 1000/fps; if( _lasttick == 0 ) _lasttick = SDL_GetTicks()-_fpstime; /* (2) Utilisation en fin de boucle */ // 1 > Si trop rapide, on attends if( SDL_GetTicks()-_lasttick < _fpstime ) SDL_Delay( _fpstime - (SDL_GetTicks()-_lasttick) ); // On enregistre le temps actuel _lasttick = SDL_GetTicks(); } /* [UPDATE] Mise a jour du rendu =========================================================*/ void xManager::update(){ if( !this->status() ) return; // cout << "Update MAIN SPRITE +" << _sprites.size() << " added sprites.." << endl; // On bloque l'acces inter-thread _mutex_update.try_lock(); /* (1) On efface le rendu */ SDL_RenderClear(_renderer); /* (2) On applique la couleur de fond */ SDL_RenderDrawRect(_renderer, &_winrect); /* (3) On ajoute le rendu principal (si existe) */ if( _texture != NULL) SDL_RenderCopy(_renderer, _texture, NULL, NULL); /* (4) On ajoute toutes les textures pushees */ for( int i = 0 ; i < _sprites.size() ; i++ ) SDL_RenderCopy( _renderer, _sprites[i]->texture(), _sprites[i]->src(), _sprites[i]->dst() ); // DEBUG _debug = (SDL_Rect){_debug.x-1, _debug.y-1, _debug.w+2, _debug.h+2}; SDL_RenderDrawRect(_renderer, &_debug); /* (n) On affiche le resultat */ SDL_RenderPresent(_renderer); // On debloque l'acces _mutex_update.unlock(); } /* [ATTACHEVENT] Ajoute une fonction a un type d'evenement =========================================================*/ void xManager::attachEvent(SDL_EventType t, void(*handler)(SDL_Event*)){ if( !this->status() ) return; // On attache le type d'evenement a la fonction _events.push_back( t ); _handlers.push_back( handler ); } /* [MANAGEEVENTS] Gestion des evenements =========================================================*/ void xManager::manageEvents(SDL_Event *event){ if( !this->status() ) return; // On lance les evenements en fonction de leur type for( int i = 0 ; i < _events.size() ; i ++ ) if( event->type == _events[i] ) // si type ok (*_handlers[i])(event); // on execute le handler } /* [DEBUG] Visualisation des donnees =========================================================*/ void xManager::debug(){ for( int i = 0 ; i < _sprites.size() ; i++ ){ cerr << "INDEX: " << _indexes[i] << " AT " << i << endl; cerr << " (" << (*_sprites[i]->dst()).x <<","<<(*_sprites[i]->dst()).y<<") -> (" << (*_sprites[i]->dst()).w << ", " << (*_sprites[i]->dst()).h << ")" << endl; } }