Simple (basic) snake game

Dependencies:   N5110 mbed

main.cpp

Committer:
MsTee
Date:
2016-05-08
Revision:
0:9eb93eff2469
Child:
1:ab8ceac59e71

File content as of revision 0:9eb93eff2469:

/**
Thokozile M Tembo 200822004
@file main.cpp
@brief Snake Game

*/
#include "main.h"

int main() {

    lcd.init(); // Initialise LCD
    init_K64F(); // Initialise connection with buttons
    welcomeScreen(); // Display welcome screen
    calibrateJoystick(); // Calibrate the joystick 
    
    // Read joystick values every 20 ms (50 Hz)
    joystick_update_ticker.attach(&updateJoystick,0.02);
    
    // Initialising random number generator
    srand(time(NULL));
            
    snake_game();
}

void init_K64F() {
    // Configure serial comms
    pc.baud(115200);
    // Call pcb_button_isr function
    pcb_button.rise(&pcb_button_isr); 
    pcb_button.mode(PullDown); // use PullDown
}

void welcomeScreen() {
    lcd.printString("Welcome to" ,15,0); //inserts text for welcome on the first line hence the '1'
    lcd.printString("Snake Game",15,1); // prints the text in the brackets on the secondline hence '2'
    lcd.printString("Thokozile",0,3); //prints text in the third line
    lcd.printString("Tembo",0,4); // prints name in fifth line
    lcd.printString("200822004",0,5); // prints name in fifth line
    wait(2); // waits for 2 seconds
    lcd.clear(); 
    lcd.refresh(); // resets the screen
}
void calibrateJoystick() {
    // must not move during calibration
    joystick.x0 = joy_x;  // initial positions in the range 0.0 to 1.0 (0.5 if centred exactly)
    joystick.y0 = joy_y;
}

void updateJoystick() {
    // read current joystick values relative to calibrated values (in range -0.5 to 0.5, 0.0 is centred)
    joystick.x = joy_x - joystick.x0;
    joystick.y = joy_y - joystick.y0;
    joystick.button = joy_button; // read button state

    // 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 = UP;
    } else if ( joystick.y < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
        joystick.direction = DOWN;
    } else if ( joystick.x > DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
        joystick.direction = LEFT;
    } else if ( joystick.x < DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
        joystick.direction = RIGHT;
    } else {
        joystick.direction = UNKNOWN;
    }
}

/* Snake Game Logic */

void snake_game() {
    
    // Game Variables
    int snake_x[220]; // Snake parts X
    int snake_y[220]; // Snake parts Y
    
    AppleType apple; // Creating an apple
        
    int snake_size = 5; // Initial size of snake
    int x_direction = 0;
    int y_direction = 0;
    int next_x;
    int next_y;
    int score = 0;

    while(1) {
        switch(game_state) {
            case INIT:
                x_direction = 0;
                y_direction = 0;
                score = 0;
                // Clear Screen
                lcd.clear();
                // Draw border                        
                lcd.drawRect(1,1,81,45,0);
                
                // Reset snake parts
                for (int i = 0; i < 220; i++) {
                    snake_x[i] = 0;
                    snake_y[i] = 0;
                }
                // Draw Initial snake
                for (int i = 0; i < snake_size; i++) {
                    snake_x[i] = (snake_size-1) - i;
                    snake_y[i] = 0;
                    drawBlock(snake_x[i], snake_y[i]);
                }
                
                apple = placeRandomApple();
                
                lcd.refresh();
                
                game_state = WAIT_FOR_USER;
                break;
            case WAIT_FOR_USER:
                // Wait until user moves joystick to the right or down
                while ((joystick.direction != RIGHT) && (joystick.direction != DOWN)) {
                    sleep();
                }
                // Go to Play state
                game_state = PLAY;                
                break;            
            case PLAY:
                while (game_state == PLAY) {
                    
                    switch (joystick.direction) {
                        case RIGHT:
                            if (x_direction != -1) { // If not opposite
                                x_direction = 1;
                                y_direction = 0;
                            }
                            break;
                        case LEFT:
                            if (x_direction != 1) { // If not opposite
                                x_direction = -1;
                                y_direction = 0;
                            }
                            break;
                        case DOWN:
                            if (y_direction != -1) { // If not opposite
                                x_direction = 0;
                                y_direction = 1;
                            }
                            break;
                        case UP:
                            if (y_direction != 1) { // If not opposite
                                x_direction = 0;
                                y_direction = -1;
                            }
                            break;
                    }
                    
                    next_x = snake_x[0] + x_direction;
                    next_y = snake_y[0] + y_direction;
                    
                    if (getBlock(next_x, next_y) && (next_x != apple.x) && (next_y != apple.y)) {                      
                        // Hit the snake body
                        game_state = GAME_OVER;
                    } else if ((next_x > 19) || (next_y > 10) || (next_x < 0) || (next_y < 0)) {
                        // Hit the border
                        game_state = GAME_OVER;
                    } else {
                        
                        if ((next_x == apple.x) && (next_y == apple.y)) {
                            // Apple eaten
                            // Increment snake size and score
                            snake_size++;
                            score++;
                            // Place new apple
                            apple = placeRandomApple();
                            // Don't remove tail
                        } else {                        
                            // Remove tail
                            eraseBlock(snake_x[snake_size-1], snake_y[snake_size-1]);
                        } 
                        
                        // Move all snake parts
                        for (int i = snake_size-1; i > 0; i--)
                        {
                            snake_x[i] = snake_x[i - 1];
                            snake_y[i] = snake_y[i - 1]; 
                        }
                        
                        // Move head in current direction
                        snake_x[0] = next_x;
                        snake_y[0] = next_y;
                                                
                        // Draw new head
                        drawBlock(next_x, next_y);
                        
                        // Redraw things on LCD
                        lcd.refresh();
                                
                        wait_ms(200);
                    }
                }
                break;
            case GAME_OVER:
                g_pcb_button_flag = 0;
                // Clear Screen
                lcd.clear();
                lcd.printString("GAME OVER!",2,0); // prints name in fifth line
                
                while(!g_pcb_button_flag) {
                    sleep();
                }
                
                game_state = INIT;
                break;              
            default:
                game_state = INIT;
        }
    }
}

AppleType placeRandomApple() {
    int good_location = 0;
    AppleType apple;
    // Look for a new location for an apple
    while (!good_location) {
        apple.x = rand() % 20; // 0 to 19
        apple.y = rand() % 10; // 0 to 9
        // Don't put apple on the snake
        if (!getBlock(apple.x, apple.y)) good_location = 1;      
    }
    drawApple(apple.x, apple.y);
    return apple;
}

// field_x (0..19), field_y (0..10)
void drawBlock(int field_x, int field_y) {
    // field_x*(block_size)+(border_offset) 
    lcd.drawRect(field_x*4+2, field_y*4+2, 3, 3, 1);
}

void eraseBlock(int field_x, int field_y) {
    // Draw an empty square on top
    // field_x*(block_size)+(border_offset)    
    lcd.drawRect(field_x*4+2, field_y*4+2, 3, 3, 3);
}

void drawApple(int field_x, int field_y) {
    int offset_x = field_x*4+2;
    int offset_y = field_y*4+2;
    // Drawing an apple pixel by pixel (8 dots)
    lcd.setPixel(offset_x+1,offset_y);
    lcd.setPixel(offset_x+2,offset_y);
    lcd.setPixel(offset_x,offset_y+1);
    lcd.setPixel(offset_x,offset_y+2);
    lcd.setPixel(offset_x+3,offset_y+1);
    lcd.setPixel(offset_x+3,offset_y+2);
    lcd.setPixel(offset_x+1,offset_y+3);
    lcd.setPixel(offset_x+2,offset_y+3);
}

int getBlock(int field_x, int field_y) {
    int offset_x = field_x*4+2;
    int offset_y = field_y*4+2;
    // Pixel at (offset_x+1,offset_y) will be active
    // for both apple and the snake block
    return lcd.getPixel(offset_x+1,offset_y);
}

// This function is called when button is pressed
void pcb_button_isr() {
    g_pcb_button_flag = 1;
}