Owen Cavender 201159294

Dependencies:   mbed Gamepad2

snake.cpp

Committer:
el17oc
Date:
2020-05-30
Revision:
14:7fb3c93343b6
Parent:
13:b37dde18bfdc
Child:
16:9500059ad5d8

File content as of revision 14:7fb3c93343b6:

#include "snake.h"

Snake::Snake()
{

}

Snake::~Snake()
{
}



void Snake::init()//int x, int y)
{
    _x0 = 48;                           //initialises the snake and apple position
    _x1 = 48;
    _x2 = 48;
    _x3 = 48;
    _x4 = 48;
    _x5 = 48;

    _y0 = 20;
    _y1 = 19;
    _y2 = 18;
    _y3 = 17;
    _y4 = 16;
    _y5 = 15;

    _apx = 48;                         //initial apple position - directly in front of snake
    _apy = 25;
    _gameover = false;                //when _gameover = true, game cannot be played
    _reset_apple = false;
    _score = 0;
    _direction = up;
    _countdown = 12;                  //initial number of moves is lower than the reset value in order to keep the number of moves low to increase difficulty

    //  Vector2D *_snakebody = new Vector2D [_length];
}

Vector2D Snake::get_Snakehead()
{
    Vector2D Snakehead;
    Snakehead.x = _x0;
    Snakehead.y = _y0;

    return Snakehead;

}





void Snake::apple_collected(N5110 &lcd, Gamepad &pad)
{

    //need to code clear apple and make sure apple isnt spawning every time
    if((_x0 == _apx) && (_y0 == _apy)) {       // directly comparing position of the apple and the Snakehead - if they are the same: the score increases, countdown timer is reset, a new apple position is generated, LEDS and Speaker are triggered

        //   _countdown = _reset_value;
        _score++;
        _reset_apple = true;                   //causes new apple position to be generated - _reset _apple is compared to a bool true - when an apple is collected a new apple position is generated
        _countdown = _countdown + 38;          //38 is added to the current countdown timer - this larger _countdown is, the further the snake can travel to collect apples.
        pad.tone(1500.0,0.5);                  //if the counter is reset to just 38, there will be some distances the snake cannot as it is further than 38 pixels away - unless the player collects accumulates their available moves
        pad.led(2, 1);                         //
        pad.led(4, 1);
        wait(0.1);
        pad.led(2, 0);
        pad.led(4, 0);



    } else {
        _countdown = _countdown - 1;           //for each change in position, counter decreases by 1

    }
}

int Snake::get_countdown()
{
    //allows _countdown value to be called from other classes
    return _countdown;
}


void Snake::check_gameover(N5110 &lcd)
{
    if (_x0 == 15 ||_x0 == 69 || _y0 == 32 || _y0 == 0) {   // the snakehead coordinate is on any edge of the rectangle, it is gameover
        //the second condition is the game is over if the snake head cooroinate is equal to one of the snake body bits coordinate
        _gameover = true;                                   // the third conditios is game is over if the counter = 0, indicating you've ran out of moves.
    }
    if ((_x0 == _x1 && _y0 == _y1) || (_x0 == _x2 && _y0 == _x2) || (_x0 == _x2 && _y0 == _y2) || (_x0 == _x3 && _y0 == _y3) || (_x0 == _x4 && _y0 == _y4)|| (_x0 == _x5 && _y0 == _y5)|| (_x0 == _x6 && _y0 == _y6)|| (_x0 == _x7 && _y0 == _y7)) {
        _gameover = true;
    }
    if(_countdown == 0) {
        _gameover = true;

    }
}

void Snake::gameover_true(N5110 &lcd, Gamepad &pad)
{

    while (_gameover == true) {                                    //As _gameover is a member variable, if the condition is the previous function is met, the true value will be stored in _gameover and can be accessed in this function
        lcd.clear();
        pad.tone(500,1);
        lcd.printString( "  Game Over  ", 0, 1 );
        lcd.printString( " ~~~~~~~<:>-<", 0, 3 );
        char buffer1[14];
        sprintf(buffer1,"  Score: %2d", _score);                          //prints your score - cannot simply use N5110::printString as we need to output a value and the No. of inputs wouldnt match up to the function declaration
        lcd.printString(buffer1,0,4);  // font is 8 wide, so leave 4 pixel gape from middle assuming two digits    ///print score

        lcd.refresh();
    }
}

void Snake::render(N5110 &lcd)                     //final function in the main function's while loop as the screen updatesbased on all any changes which occur in the functions
{
    lcd.clear();

    //apple
    lcd.setPixel(_apx, _apy,1);                     //plot apple position -whether it is a new position or the same position

    lcd.drawRect(15, 0, 54, 32, FILL_TRANSPARENT);  //plots border of snake map

    lcd.setPixel(_x0, _y0,1);                       //plots snake body's new position changed by move_snake() function
    lcd.setPixel(_x1, _y1,1);
    lcd.setPixel(_x2, _y2,1);
    lcd.setPixel(_x3, _y3,1);
    lcd.setPixel(_x4, _y4,1);
    lcd.setPixel(_x5, _y5,1);
    lcd.setPixel(_x6, _y6,1);
    lcd.setPixel(_x7, _y7,1);                        //new position of the end bit of the snake is plotted - its old position cleared
    //NOTES CHANGLE LED VALUES SO IT IS TOP RIHGT OF THE BOX NOT TOP HALF OF THE SCREEN    //CHANGE APPLE POSITION COORDINATES SO ITS IN BOX // GET SCORE IN THE SAME PLACE WHEN IT PRINTS AT END

    char buffer1[14];
    sprintf(buffer1,"   %2d   %2d",_score, _countdown);    //prints score and counter on the same line
    lcd.printString(buffer1,0,5);  // font is 8 wide, so leave 4 pixel gape from middle assuming two digits


//   char buffer2[14];
    // sprintf(buffer2,"%2d",_score);
    // lcd.printString(buffer2,0,3);  // font is 8 wide, so leave 4 pixel gape from middle assuming two digits

    lcd.refresh();                                       //applies plotting commands togeher
}





void Snake::get_direction(Gamepad &pad)
{
    // int x;
    Directions direction = _direction;   //"direction" stores the previous value of _direction to stop the snake going in the opposite direction to the way its travelling

    if(direction != left) {             //if current direction is left, the not statement is false blocking access to the next command from the 'A' button preventing _direction being set to right
        if (pad.A_pressed()) {

            _direction = right;
            //       x=1;
        }
    }
    if(direction != right) {
        if (pad.Y_pressed()) {

            _direction = left;
            //      x=2;
        }

    }
    if(direction != down) {
        if (pad.B_pressed()) {
            //       x=3;
            _direction = up;
        }
    }
    if(direction != up) {
        if (pad.X_pressed()) {

            _direction = down;
            //       x=4;
        }
    } else {
        _direction = _direction;            // setting the direction equal to itself if no button is pressed means the snake will move automatically once direction is set

    }
    //  printf("direction %d ", x);        //printf statements used in CoolTerm to check whether the input commands where working correctly
}



void Snake::move_snake()
{
    if (_direction == up) {       //shifting the snake position bit by bit, with respect to _x0 and _y0;
        _x7 = _x6;                //coordinate _x[i], _y[i] = _x[i-1], _y[i-1]
        _y7 = _y6;
        _x6 = _x5;
        _y6 = _y5;
        _x5 = _x4;
        _y5 = _y4;
        _x4 = _x3;
        _y4 = _y3;
        _x3 = _x2;
        _y3 = _y2;
        _x2 = _x1;
        _y2 = _y1;
        _x1 = _x0;
        _y1 = _y0;               //_x1 ,_y1 and  must be assingned to _x0,_y0 before its own position updates otherwise bit 0 and bit 1 would be plotted as 1 pixel

        _x0 = _x0;
        _y0 = _y0 + 1;          //changes the position one bit at a time so the snake can only move horizontally or vertically
    }
    if (_direction == down) {
        _x7 = _x6;
        _y7 = _y6;
        _x6 = _x5;
        _y6 = _y5;
        _x5 = _x4;
        _y5 = _y4;
        _x4 = _x3;
        _y4 = _y3;
        _x3 = _x2;
        _y3 = _y2;
        _x2 = _x1;
        _y2 = _y1;
        _x1 = _x0;
        _y1 = _y0;

        _x0 = _x0;
        _y0 = _y0 - 1;

    }
    if (_direction == left) {
        _x7 = _x6;
        _y7 = _y6;
        _x6 = _x5;
        _y6 = _y5;
        _x5 = _x4;
        _y5 = _y4;
        _x4 = _x3;
        _y4 = _y3;
        _x3 = _x2;
        _y3 = _y2;
        _x2 = _x1;
        _y2 = _y1;
        _x1 = _x0;
        _y1 = _y0;

        _x0 = _x0 - 1;       //changes x=x-1 , y remains the same to move left
        _y0 = _y0;



    }

    if (_direction == right) {
        _x7 = _x6;
        _y7 = _y6;
        _x6 = _x5;
        _y6 = _y5;
        _x5 = _x4;
        _y5 = _y4;
        _x4 = _x3;
        _y4 = _y3;
        _x3 = _x2;
        _y3 = _y2;
        _x2 = _x1;
        _y2 = _y1;
        _x1 = _x0;
        _y1 = _y0;

        _x0 = _x0 + 1;
        _y0 = _y0;


    }
}


void Snake::render_clear_tail(N5110 &lcd)
{

    lcd.setPixel(_x7, _y7, false);                       //sets the end pixel to 0. it must be set to 0 before its position updates otherwise the snakebody will grow continually from _x7, _y7 coordinate
}

bool Snake::get_gameover()                               //methods to access member variables of the class
{
    return _gameover;
}
int Snake::get_score()
{
    return _score;
}





void Snake::get_Apple_position(N5110 &lcd)
{
    if(_reset_apple == true) {      // _reset_apple is a triggered when an apple is collected and causes a new Apple position to be randomly generated
        _reset_apple = false;         // returned to false immediately so another position can be generated function can be triggered again in the next loop
        lcd.setPixel(_apx, _apy,0);     //sets the exisiting apple position to 0 to remove it from lcd.
        _apx = rand()%52+16;         //54 = width of the rectangle on the lcd. - the x value of the apple has a range of 52 so it cannot spawn in either side of the wall
        // the range is from 16 to 69 as the lowest x coordinate of the rectangle is 15 and the highest is 69
        _apy = rand()%28+2;
    }


}