Completed Snake Program

Dependencies:   N5110 PinDetect PowerControl mbed

Fork of DocTest by Craig Evans

main.cpp

Committer:
MBirney
Date:
2015-04-30
Revision:
7:2942e97924f0
Parent:
6:1de103a19681
Child:
8:b857684a3983

File content as of revision 7:2942e97924f0:

#include "main.h"

// create enumerated type (0,1,2,3 etc. for direction)
enum DirectionName {
    UP,
    DOWN,
    LEFT,
    RIGHT,
    CENTRE,
    UNKNOWN
};

// create enumerated type (0,1,2 for difficulty)
enum Difficulty {
    EASY,
    MEDIUM,
    HARD,
};

Difficulty currentDifficulty=EASY;// initialise to easy mode


// struct for Joystick
typedef struct JoyStick Joystick;
struct JoyStick {
    float x;    // current x value
    float x0;   // 'centred' x value
    float y;    // current y value
    float y0;   // 'centred' y value
    int button; // button state (assume pull-down used, so 1 = pressed, 0 = unpressed)
    DirectionName direction;  // current direction
};
// create struct variable
Joystick joystick;

DirectionName previousDirection =RIGHT;//initial direction =Right

// read default positions of the joystick to calibrate later readings
void calibrateJoystick()
{
    button.mode(PullDown);
    // must not move during calibration
    joystick.x0 = xPot;  // initial positions in the range 0.0 to 1.0 (0.5 if centred exactly)
    joystick.y0 = yPot;
}
void updateJoystick()
{
    // read current joystick values relative to calibrated values (in range -0.5 to 0.5, 0.0 is centred)
    joystick.x = xPot - joystick.x0;
    joystick.y = yPot - joystick.y0;
    // read button state
    joystick.button = button;

    // calculate direction depending on x,y values
    // tolerance allows a little lee-way in case joystick not exactly in the stated direction
    if ( fabs(joystick.y) < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
        joystick.direction = CENTRE;
    } else if ( joystick.y > DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
        joystick.direction = DOWN;
    } else if ( joystick.y < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
        joystick.direction = UP;
    } else if ( joystick.x > DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
        joystick.direction = RIGHT; // remember switched this with right
    } else if ( joystick.x < DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
        joystick.direction = LEFT;
    } else {
        joystick.direction = UNKNOWN;
    }
}

//GAME FUNCTIONS

//For start MENU

void displaySplash()
{
 
    lcd.inverseMode();      // change colour mode
    lcd.setBrightness(0.5); // put LED backlight on 50%

    //Draw S
    lcd.drawRect(28,10,2,5,1);
    lcd.drawRect(15,10,15,2,1);
    lcd.drawRect(15,10,2,10,1);
    lcd.drawRect(15,20,15,2,1);
    lcd.drawRect(28,20,2,10,1);
    lcd.drawRect(15,28,15,2,1);
    lcd.drawRect(15,25,2,3,1);

    lcd.printString("NAKE ",34,3);
    lcd.printString("By M.Birney",10,5);
    lcd.drawRect(10,5,65,30,0); // outline for splash

    // need to refresh display after setting pixels

    lcd.refresh();
}



void easySelected() // display when easy is selected
{
    currentDifficulty=EASY;
    lcd.clear();
    lcd.printString("Please Select",2,0);
    lcd.printString("Difficulty:",2,1);
    lcd.printString("Easy",20,3);
    lcd.printString("Medium",20,4);
    lcd.printString("Hard",20,5);
    lcd.refresh();
    lcd.drawCircle(10,27,2,1);
    lcd.drawCircle(10,35,2,0);
    lcd.drawCircle(10,43,2,0);

    gameSpeed= 1.0/5; // set easy game speed(for game time)
}
void mediumSelected() // display when medium is selected 
{
    currentDifficulty=MEDIUM;
    lcd.clear();
    lcd.printString("Please Select",2,0);
    lcd.printString("Difficulty:",2,1);
    lcd.printString("Easy",20,3);
    lcd.printString("Medium",20,4);
    lcd.printString("Hard",20,5);
    lcd.refresh();
    lcd.drawCircle(10,27,2,0);
    lcd.drawCircle(10,35,2,1);
    lcd.drawCircle(10,43,2,0);
    gameSpeed=1.0/7; // set medium game speed 
}

void hardSelected() // display when hard is selected
{
    currentDifficulty=HARD;
    lcd.clear();
    lcd.printString("Please Select",2,0);
    lcd.printString("Difficulty:",2,1);
    lcd.printString("Easy",20,3);
    lcd.printString("Medium",20,4);
    lcd.printString("Hard",20,5);
    lcd.refresh();
    lcd.drawCircle(10,27,2,0);
    lcd.drawCircle(10,35,2,0);
    lcd.drawCircle(10,43,2,1);
    gameSpeed=1.0/12; // set hard game speed
}


void checkSelectedDifficulty()
{

    switch(currentDifficulty) {
        case EASY:

            switch (joystick.direction) {

                case UP:
                    hardSelected();
                    break;


                case DOWN:
                    mediumSelected();
                    break;
            }
            break;


        case MEDIUM:

            switch (joystick.direction) {

                case UP:
                    easySelected();
                    break;


                case DOWN:
                    hardSelected();
                    break;
            }



            break;
        case HARD:
            switch (joystick.direction) {

                case UP:
                    mediumSelected();
                    break;


                case DOWN:
                    easySelected();
                    break;
            }
            break;
    }
    wait(0.2);
}




//for gamePLAY



void startingSnake()
{
   snakeX.resize(5);
   snakeY.resize(5);
    snakeX[0]=20;
    snakeX[1]=22;
    snakeX[2]=24;
    snakeX[3]=26;
    snakeX[4]=28;
    snakeY[0]=27;
    snakeY[1]=27;
    snakeY[2]=27;
    snakeY[3]=27;
    snakeY[4]=27;
    

    for (int i=0; i<5; i++) {
        // lcd.setPixel(snakeX[i],snakeY[i]);
        lcd.drawRect(snakeX[i],snakeY[i],1,1,1);
    }

}


void randomiseFood()
{
//   http://stackoverflow.com/questions/3383286/create-a-random-even-number-between-range


    srand(time(NULL));

    int randomX = 2 * (1 + rand() % (40 - 1 + 1)) ; //generate random even number between 2 and 80

    int randomY = (2 * (4 + rand() % (22 - 4 + 1))) +1; // generate random even number between 8 and 44 then plus 1 for odd number in range of 9-45


    while(lcd.getPixel(randomX,randomY)==1) { // if that pixel is already filled keep generating till a empty space is found

        int randomX = 2 * (1 + rand() % (40 - 1 + 1)) ;
        int randomY = (2 * (4 + rand() % (22 - 4 + 1))) +1; // generate random even number between 8 and 44 then plus 1 for odd number in range of 9-45


    }
    // lcd.setPixel(randomX,randomY) ;// set the food
    lcd.drawRect(randomX,randomY,1,1,1);
    //lcd.setPixel(randomX,randomY);

    foodX[0]=randomX; // update food position
    foodY[0]=randomY;// update food position
    lcd.refresh();
//serial.printf("%d",randomX);
}

void Boundary()
{


    for(int x = 1; x< 83; x++) { // draw 1 to 82 at y=8
        lcd.setPixel(x,8);
    }
    for(int x = 1; x< 83; x++) { // draw 1 to 82 at y=47
        lcd.setPixel(x,47);
    }
    for(int y = 8; y< 48; y++) {// draw 8 tp 47 at x=1
        lcd.setPixel(1,y);
    }
    for(int y = 8; y< 48; y++) {// draw 8 to 47 at x =82
        lcd.setPixel(82,y);
    }

    lcd.refresh();

}





void updateSnakeArray()
{

    if (joystick.direction==LEFT && previousDirection==RIGHT) {
        joystick.direction=RIGHT;
    }

    if (joystick.direction==RIGHT && previousDirection==LEFT) {
        joystick.direction=LEFT;
    }

    if (joystick.direction==UP && previousDirection==DOWN) {
        joystick.direction=DOWN;
    }

    if (joystick.direction==DOWN && previousDirection==UP) {
        joystick.direction=UP;
    }

    if (joystick.direction==UNKNOWN || joystick.direction==CENTRE) {
        joystick.direction= previousDirection;
    }


    // lcd.clearPixel(snakeX[0],snakeY[0]);//delete tail
    lcd.drawRect(snakeX[0],snakeY[0],1,1,2);

    for (int i =0; i<snakeX.size(); i++) {  // shift elements
        snakeX[i]=snakeX[i + 1]; // apart from head
        snakeY[i]=snakeY[i+ 1];
    }

    switch(joystick.direction) {

        case UP:
            snakeX[snakeX.size()-1]=snakeX[snakeX.size()-2];
            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2]-2;
            
 if(snakeY[snakeY.size()-1] <9) snakeY[snakeY.size()-1]=45;
            break;

        case DOWN:
          snakeX[snakeX.size()-1]=snakeX[snakeX.size()-2];
            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2]+2;
            
            if(snakeY[snakeY.size()-1] >45) snakeY[snakeY.size()-1]=9;
            break;

        case LEFT:
            snakeX[snakeX.size()-1]=snakeX[snakeX.size()-2]-2;
            
            if(snakeX[snakeX.size()-1] <2) snakeX[snakeX.size()-1]=80;
    
            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2];
            break;

        case RIGHT:
            snakeX[snakeX.size()-1]= snakeX[snakeX.size()-2]+2;
          
          if(snakeX[snakeX.size()-1] >80) snakeX[snakeX.size()-1]=2;
         
            
            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2];
          
            break;

        case CENTRE:
            snakeX[snakeX.size()-1]=snakeX[snakeX.size()-2]+2;
            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2];
            break;
        case UNKNOWN:
            snakeX[snakeX.size()-1]=snakeX[snakeX.size()-2]+2;
            snakeY[snakeY.size()-1]=snakeY[snakeY.size()-2];
            break;

    }
}
void playTune()
{
    
    //float frequency[]={440,659};
   // float beat[]={1,1,};
    // Buzzer=0.3; 
      //  Buzzer.period(1/(440));// time =1/f 
        //wait(1);
        //Buzzer.period(1/(659));
     
        //Buzzer=0;
        
           // set PWM period
             
// set duty cycle 
     //wait(0.5*beat[i]);     
}
void gameOver()
{
    leds=1;
    startGame.detach();
    lcd.drawRect(snakeX.back(),snakeY.back(),1,1,2);
    wait(0.2);
    lcd.refresh();
    lcd.drawRect(snakeX.back(),snakeY.back(),1,1,1);
    wait(0.3);
    lcd.refresh();
    lcd.drawRect(snakeX.back(),snakeY.back(),1,1,2);
    wait(0.2);
    lcd.refresh();
    lcd.drawRect(snakeX.back(),snakeY.back(),1,1,1);
    wait(0.2);
    lcd.refresh();
    lcd.clear();
    lcd.inverseMode();


    lcd.printString("Your Score" ,12,0);
    lcd.printString("=" ,34,1);

    int updatedScore=score;
    int length = sprintf(buffer,"%2d",updatedScore);

    if (length <= 14)  // if string will fit on display
        lcd.printString(buffer,40,1);

    lcd.printString("Press Reset" ,2,3);
    lcd.printString("Button To" ,10,4);
    lcd.printString("Play Again" ,20,5);
    
    //
    lcd.refresh();
   playTune();
    
    //gamePlaying=0;



}



void checkForCollision()
{

    if (snakeX.back()==0|| snakeX.back()==82 || snakeY.back()==7 ||snakeY.back()>=47) {
        myleds=15;

        gameOver();
    }
}



void checkForFood()
{

    if (snakeX.back()==foodX[0] && snakeY.back()==foodY[0]) {   // if  x and y of head match food


        switch(joystick.direction) {

            case RIGHT:
                snakeX.insert (snakeX.begin() +0,foodX[0]-2 );
                snakeY.insert (snakeY.begin() ,foodY[0]);
                //snakeX.push_back(foodX[0]+2);
                // snakeY.push_back(foodY[0]);
                break;
            case LEFT:

                snakeX.insert (snakeX.begin() +0,foodX[0]+2 );
                snakeY.insert (snakeY.begin() ,foodY[0]);

                //  snakeX.push_back(foodX[0]-2);
                // snakeY.push_back(foodY[0]);
                break;


            case UP:

                snakeX.insert (snakeX.begin() +0,foodX[0] );
                snakeY.insert (snakeY.begin() ,foodY[0]+2);
                //  snakeX.push_back(foodX[0]);
                // snakeY.push_back(foodY[0]-2);
                break;

            case DOWN:
                snakeX.insert (snakeX.begin() +0,foodX[0] );
                snakeY.insert (snakeY.begin() ,foodY[0]-2);
                // snakeX.push_back(foodX[0]);
                // snakeY.push_back(foodY[0]+2);
                break;
        }
        lcd.drawRect(snakeX[0],snakeY[0],1,1,1);

        int updatedScore;
        // snakeX.insert (snakeX.begin() + 0, );
        //snakeY.insert (snakeY.begin() + 0, );

        updatedScore= score+5;
        score=updatedScore;
        int length = sprintf(buffer,"%2d",updatedScore);

        if (length <= 14)  // if string will fit on display
            lcd.printString(buffer,0,0);
        // lcd.refresh();

        randomiseFood();

    }


}

void startButtonPressed()
{
    gamePlaying=1;
    // myleds=15;
}



void updateBrightness()
{
    float ain ;
    ain=pot.read();
    lcd.setBrightness(1-ain);

}
void updateGameISR()
{
    updateGameFlag=1;
}

void printVectorContent()
{

    //for( int i=0; i<snakeX.size(); i++)
    // serial.printf( "%d \n \r"  ,snakeX[i]);

}



void pauseButtonPressed()
{

    if (gamePaused==0) {

        startGame.detach();

        gamePaused=1;
        leds=2;

    }

    else {


        startGame.attach(&updateGameISR,gameSpeed);

        gamePaused=0;
    }



}

void checkForCollisionWithSelf(int i)
{
    if(snakeX.back()==snakeX[i] && snakeY.back()==snakeY[i]) {
        gameOver();
    }


}
void startUpMenu()
{
lcd.inverseMode();
    easySelected();
    joystick.direction=UNKNOWN;
    calibrateJoystick();  // get centred values of joystick
     
}

void resetButtonPressed()
{
    gamePlaying=0;
}


int main()
{
    leds=1;
    lcd.init();
    resetButton.mode(PullDown);
    startButton.mode(PullDown);
    button.mode(PullDown);
    startButton.rise(&startButtonPressed);
    resetButton.rise(&resetButtonPressed);
    button.rise(&pauseButtonPressed);
      displaySplash();
    wait(4);
//serial.printf("starting");
    while(1) {
        startUpMenu();
        while (gamePlaying==0) {
            updateJoystick();
            checkSelectedDifficulty();
            updateBrightness();
            //serial.printf("check difficulty loop");
        }

         if (gamePlaying==1) {

            lcd.clear();
            lcd.normalMode();      // normal colour mode
            Boundary();
            previousDirection=RIGHT;
            joystick.direction=RIGHT; // make sure when game reset that joystick is reset to right 
            startingSnake();
            randomiseFood();
            int score=5;
    int length = sprintf(buffer,"%2d",score);
            if (length <= 14)  // if string will fit on display
                lcd.printString(buffer,0,0);
            // lcd.drawRect(0,0,83,7,0);
            lcd.refresh();    
             startGame.attach(&updateGameISR,gameSpeed);
           
            while (gamePlaying==1) {

                //  serial.printf("enter game loop");
                if(updateGameFlag==1) {
                    leds=4;
                    //updateJoystick();
                    updateGameFlag=0;
                    updateJoystick();
                    // lcd.clearPixel(snakeX[0],snakeY[0]);
                    // updateSnakeDirection();
                    updateSnakeArray();
                    for (int i=0; i<snakeX.size(); i++) {
                        lcd.drawRect(snakeX[i],snakeY[i],1,1,1);
                  // lcd.setPixel(snakeX[i],snakeY[i]);


                    }
                    lcd.refresh();
                    previousDirection=joystick.direction;

                    //checkForCollision();
                    checkForFood();


                    for (int i=0; i<snakeX.size()-1; i++) {
                        checkForCollisionWithSelf(i);
                         updateBrightness();
                        //serial.printf("%d",snakeX.size());
                        // printVectorContent();

                    }

                }

            }
        }



    }
}