Mini projet LOO

Dependencies:   mbed APDS_9960 mbed-rtos

Dependents:   MoveYourTetris_OK

Home du projet

src/cJeu.cpp

Committer:
Willheisen
Date:
2016-04-24
Revision:
40:08490d120ec4
Parent:
38:418278e5eb6b

File content as of revision 40:08490d120ec4:

#include "cJeu.h"
#include "rtos.h"
#include "cScore.h"



//Constructeur par défaut
cJeu::cJeu()
{
    _mat = new cMatrice(8, 8);
}

//Second constructeur:
//Il crée de crée une matrice de x LEDs de large sur y LEDS de HAUT,
//avec la broche pin comme entrée d'interruption si détection de mouvement du capteur
//Entrées: x: nombre de colonnes, y: nombre de lignes
cJeu::cJeu(unsigned char x, unsigned char y)
{
    // On met le score à 0
    _score = 0;
    //on crée une nouvelle matrice
    _mat = new cMatrice(x, y);
    //on initialise la générateur de nombres pseudo-aléatoires
    srand(time(NULL));
}

//Accesseur qui retourne un pointeur sur la matrice
cMatrice* cJeu::get_matrice()
{
    return _mat;
}

//Accesseur qui retourne la valeur du score du joueur
unsigned char cJeu::get_score()
{
    return _score;
}

//Accesseur qui retourne un pointeur sur la valeur du mouvement détecté
unsigned char *cJeu::getDetec()
{
    return &_detec;
}

//Mutateur pour la matrice
void cJeu::set_matrice(cMatrice *mat)
{
    _mat = mat;
}


//Mutateur pour le score
void cJeu::set_score(unsigned char sc)
{
    _score = sc;
}

//Mutateur pour la valeur du mouvement détecté
void cJeu::setDetec(unsigned char detec)
{
    _detec = detec;
}

//Mutateur pour récupérer la valeur de mouvement depuis le 2e thread via le Message queue
void cJeu::setQueue(osMessageQId* queue, osPoolId* pool)
{
    _queue = queue;
    _pool = pool;
}

//Méthode d'initialisation de la liaison SPI et de la matrice RGB
void cJeu::initialiser()
{
    //paramètres: fréquence 100kHz (maximum pour la matrice RGB 125KHz)
    _spi.initSPI(100000);
    //envoi la matrice de LED le nombre de matrices à contrôler (par DaisyChain)
    _spi.setNbMatrice(2);
    //effacement de la matrice
    _mat->clear();
    _spi.envoyerMatrice(*_mat);
    wait(1);
    // On affiche le début du message d'accueil MoveYourTetris
    _mat->messageAccueil();
    _spi.envoyerMatrice(*_mat);
    wait(1);
    int i;
    i=0;
    //On décale le message pour affichage
    while(i<51) {//67 - 16= nbColonnes du message - nbLignes de la matrice
        _mat->decalerMatrice();
        _spi.envoyerMatrice(*_mat);
        wait(0.1);
        i++;
    }
    //On colore toute la matrice en bleue
    for(unsigned char i = 0; i < _mat->getCol(); i++) {
        for(unsigned char j = 0; j < _mat->getLig()/2; j++) {
            wait_ms(1);
            _mat->setValTab(i, j, LED_BLEU_FONCE);
            _spi.envoyerMatrice(*_mat);
        }
    }
    for(unsigned char i = 0; i < _mat->getCol(); i++) {
        for(unsigned char j = _mat->getLig()/2; j < _mat->getLig(); j++) {
            wait_ms(1);
            _mat->setValTab(i, j, LED_BLEU_FONCE);
            _spi.envoyerMatrice(*_mat);
        }
    }
    //Enfin on efface la matrice
    _mat->clear();
    _spi.envoyerMatrice(*_mat);
}

//Méthode de création d'une nouvelle pièce de manière pseudo-aléatoire
//Entrées
void cJeu::nouvellePiece()
{
    //On génère un nombre aléatoire entre 1 et 5 pour la pièce
    unsigned char nb = 1 + ((float)rand()/RAND_MAX) * 5;
    //On génère un deuxième nombre pour choisir la couleur de la pièce
    unsigned char couleur = 1 + ((float)rand()/RAND_MAX) * 7;
    //Selon le nombre généré, on va créer une nouvelle pièce
    switch(nb) {
            //On crée une pièce "L"
        case 1: {
            _ptrForme = new cEl(3,0);
            break;
        }
        //On crée une pièce "ligne"
        case 2: {
            _ptrForme = new cLigne(3,0);
            break;
        }
        //On crée une pièce "Z"
        case 3: {
            _ptrForme = new cZed(3,0);
            break;
        }
        //On crée une pièce "T"
        case 4: {
            _ptrForme = new cTe(3,0);
            break;
        }
        //On crée une pièce "carré"
        case 5: {
            _ptrForme = new  cCarre(3,0);
            break;
        }
        default:
        {}

    }//Et on choisi sa couleur
    switch(couleur) {
        case 1: {
            couleur = LED_ROUGE;
            break;
        }
        case 2: {
            couleur = LED_ORANGE;
            break;
        }
        case 3: {
            couleur = LED_JAUNE;
            break;
        }
        case 4: {
            couleur = LED_VERT;
            break;
        }
        case 5: {
            couleur = LED_BLEU_CLAIR;
            break;
        }
        case 6: {
            couleur = LED_BLEU_FONCE;
            break;
        }
        case 7: {
            couleur = LED_MAGENTA;
            break;
        }
        default:
        {}
    }
    //Enfin, on "attache" la pièce la matrice et on affiche celle-ci
    _mat->afficherForme(_ptrForme, couleur);
    _spi.envoyerMatrice(*_mat);
}

//Destructeur de la classe cJeu, qui appelle la méthode fin,
//qui désalloue tous les objets alloués dynamiquement
cJeu::~cJeu()
{
    fin();
}


/*Méthode de gestion d'une partie
Entrées: aucune.
Sorties: aucune.
*/
void cJeu::nouvelleManche()
{
    bool resultat = false;
    //On met le score à 0
    _score = 0;
    // Tant que l'on a pas perdu
    while (!resultat) {
        //on joue une nouvelle pièce
        resultat = partieEnCours();
    }
    afficherScore();
}

/*Méthode qui permet de voir s'il une ligne est complète.
Entrées: aucune.
Sortie, une variable de type unsigned char égale à 1 si une ligne est complète, 0 le cas échéant.
Principe:
    On parcourt chaque LED de chaque ligne de la matrice.
    Si une LED n'est pas éteinte, alors on incrémente une variable.
    Si cette variable atteint la valeur 8, c'est que toutes les LEDs d'une ligne sont allumées,
    donc que la ligne est complète.
    Si une de ces lignes est complète, alors on fait descendre toutes les pièces au-dessus
    de la ligne(autres que celle de la manche) d'un cran.    */
unsigned char cJeu::ligneComplete()
{
    unsigned char total = 0, numLigne = 0, res = 0;
    //On parcourt chaque ligne de la matrice.
    for( unsigned char i = 0; i < _mat->getLig(); i++) {
        total = 0;
        for( unsigned char j = 0; j < _mat->getCol(); j++) {
            //Pour chaque LED de la ligne, si celle-ci n'est pas éteinte
            if(_mat->getValTab(j, i) != LED_NOIR) {
                //alors on incrémente une variable
                total ++;
            }
            //Si cette variable atteint la valeur 8 (ligne complète de LEDs non éteinte),
            if(total == 8) {
                //on note le numéro de la ligne complète
                total = 0;
                numLigne = i;
                //et on quitte la boucle
                res = 1;
                    //Et on augmente le score!
                _score+=10;
            }
        }
    }

    // On nettoie la ligne complétée
    for(int i = 0; i < _mat->getCol(); i++) {
        _mat->setValTab(i, numLigne, LED_NOIR);
    }
    //On descend toutes les LEDs allumées au dessus de numLigne d'un cran
    for( unsigned char i = numLigne; i > 0; i--) {
        for( unsigned char j = 0; j < _mat->getCol(); j++) {
            _mat->setValTab(j, i, _mat->getValTab(j, i-1));
        }
    }

//On renvoie 1 pour indiquer la présente d'une ligne complète
return res;
}

/*Méthode de gestion du jeu en cours:
Entrées: aucune.
Sorties: perdu, variable type integer qui passe à 1 si on perd.
Principe:
    ->gestion des mouvements de la pièce
    ->gestion des collision
    ->gestion de la fin (gagné ou perdu)
*/
bool cJeu::partieEnCours()
{
    int _mvt = 0;
    bool perdu = false;
    cCollision col;
    /*La boucle suivante correspond à une "manche" du jeu:
    On crée une nouvelle pièce.
    Si celle-ci ne peut pas descendre, c'est que la matrice est remplie donc que le joueur a perdu.
    On colore toute la matrice en bleue puis on l'efface.
    Sinon, on effectue s'il y a eu mouvement de l'utilisateur le mouvement de le pièce correspondante.
    On rafraîchit la matrice,
    Puis si c'est possible, on descend la pièce d'une ligne et on rafraîchi de nouveau */

    while(!perdu) {
        //On crée une nouvelle pièce.
        nouvellePiece();
        //Si celle-ci ne peut pas descendre, c'est que la matrice est remplie donc que le joueur a perdu.
        if(col.pieceBas(*_ptrForme, *_mat) == true) {
            //On colore toute la matrice en bleue
            for(unsigned char i = 0; i < _mat->getCol(); i++) {
                for(unsigned char j = 0; j < _mat->getLig()/2; j++) {
                    wait_ms(1);
                    _mat->setValTab(i, j, LED_BLEU_FONCE);
                    _spi.envoyerMatrice(*_mat);
                }
            }
            for(unsigned char i = 0; i < _mat->getCol(); i++) {
                for(unsigned char j = _mat->getLig()/2; j < _mat->getLig(); j++) {
                    wait_ms(1);
                    _mat->setValTab(i, j, LED_BLEU_FONCE);
                    _spi.envoyerMatrice(*_mat);
                }
            }
            //Puis on l'efface
            _mat->clear();
            _spi.envoyerMatrice(*_mat);
            //on signale que le jeu est fini
            perdu = true;
        }

        //Tant que la pièce en cours peut descendre
        while(col.bordBas(*_ptrForme, *_mat) == false && col.pieceBas(*_ptrForme, *_mat) == false && !perdu) {
            //On lit la message queue
            osEvent evt = osMessageGet(*_queue, 500);
            if (evt.status == osEventMessage) {
                message_t *message = (message_t*)evt.value.p;
                //et on récupère la valeur du mouvement détecté
                _mvt = message->val;
                osPoolFree(*_pool, message);
                //Si pas de mouvement reçu
            } else {
                _mvt = 0;
            }
            //Selon la valeur du mouvement, on effectue le mouvement de la pièce correspondant.
            //A chaque fois, on test de non-collision est fait avant de faire le mouvement.
            switch(_mvt) {
                case 1: {
                    if(col.pieceBas(*_ptrForme, *_mat) == false && col.bordBas(*_ptrForme, *_mat) == false) {
                        _ptrForme->rotationHoraire();
                    }
                    break;
                }
                case 2: {
                    while(col.pieceBas(*_ptrForme, *_mat) == false && col.bordBas(*_ptrForme, *_mat) == false) {
                        _ptrForme->deplacementBas();
                        _mat->updateMatrice();
                        _spi.envoyerMatrice(*_mat);
                    }
                    break;
                }
                case 3: {
                    if(col.pieceGauche(*_ptrForme, *_mat) == false && col.bordGauche(*_ptrForme) == false) {
                        _ptrForme->deplacementGauche();
                    }
                    break;
                }
                case 4: {
                    if(col.pieceDroite(*_ptrForme, *_mat) == false && col.bordDroit(*_ptrForme) == false) {
                        _ptrForme->deplacementDroite();
                    }
                    break;
                }
                default: {
                    _ptrForme->deplacementBas();
                    break;
                }
            }
            //on rafraîchi la matrice
            _mat->updateMatrice();
            _spi.envoyerMatrice(*_mat);
        }
        delete _ptrForme;
        //On regarde si des lignes sont complètes
        while(ligneComplete()==1){
            _spi.envoyerMatrice(*_mat);
            wait(0.5);
        }
    }
    return perdu;
}

//Méthode de suppression des objets alloués dynamiquement
void cJeu::fin()
{
    delete _ptrForme;
    delete _pool;
    delete _queue;
    delete _mat;
}

void cJeu::afficherScore()
{
    int centaines, dizaines;
    cScore score;
    centaines = _score/100; 
    dizaines = (_score-(centaines*100))/10;
    for(unsigned char i = 0; i < 5; i++) {
        for(unsigned char j = 0; j < 4; j++) {
            _mat->setValTab(i+2, j+1, score.getChiffre(centaines, i, j));
        }
    }

    // On affiche les dizaines
    for(unsigned char i = 0; i < 5; i++) {
        for(unsigned char j = 0; j < 4; j++) {
            _mat->setValTab(i+2, j+6, score.getChiffre(dizaines, i, j));
        }
    }
    
    //puis on affiche les unités
    for(unsigned char i = 0; i < 5; i++) {
        for(unsigned char j = 0; j < 4; j++) {
            _mat->setValTab(i+2, j+11, score.getChiffre(0, i, j));
        }
    }
    _spi.envoyerMatrice(*_mat);
}