Erts

Dependencies:   BSP_DISCO_F413ZH

main.cpp

Committer:
ajdincatic
Date:
2022-02-06
Revision:
0:a3870e86460b

File content as of revision 0:a3870e86460b:

#include "mbed.h"
#include "stm32f413h_discovery_lcd.h"

#define SCREEN_REFRESH_PERIOD 0.15
#define START_SNAKE_LENGTH 4
#define GAME_BG (uint16_t)0x010200

enum Mode{
    MAIN_MENU,
    GAME,
    END_GAME
};

enum Dirrection {
    LEFT, UP, RIGHT, DOWN
};

// simulator
// InterruptIn bLeft(p5);
// InterruptIn bUp(p6);
// InterruptIn bRight(p7);
// InterruptIn bDown(p8);
// PwmOut speaker(p21);
// PwmOut led(p9);
// DigitalIn toggglePause(p10);
// real device
InterruptIn bLeft(PA_1);
InterruptIn bUp(PA_2);
InterruptIn bRight(PA_3);
InterruptIn bDown(PA_4);
PwmOut speaker(PA_5);
PwmOut led(PA_6);
DigitalIn toggglePause(PA_7);

Timeout alertTimeout;
Ticker gameTicker;
Ticker mainTicker;

Mode mode = MAIN_MENU;
Dirrection direction = UP;

#define MAX_X 34
#define MAX_Y 34

int X[MAX_X*MAX_Y] = {5, 5, 5, 5};
int Y[MAX_X*MAX_Y] = {30, 29, 28, 27};

int targetX, targetY;

int snakeLength = START_SNAKE_LENGTH;
int score = 0;

bool isEndGame = true;

void drawSquare(int x, int y){
    BSP_LCD_FillRect(x*231/MAX_X+1, y*231/MAX_Y+1, 5, 5);
}

void drawTarget(int x, int y){
    BSP_LCD_FillRect(x*231/MAX_X+1, y*231/MAX_Y+1, 5, 5);
}

void turnOffToneAndLed(void) {
  led = 0;
  speaker = 0;
}

void playToneAndLed(float frequency, float volume) {
    led = 1.0;
    speaker.period(1.0 / frequency);
    speaker = volume;
}

void turnOnForTime(float time) {
  playToneAndLed(400.0, 0.5);
  alertTimeout.attach(&turnOffToneAndLed,time);
}

void initGame(){
    direction = UP;
    snakeLength = START_SNAKE_LENGTH;
    score = 0;
    mode = GAME;
}

void initMainMenuScreen(){
    snakeLength = START_SNAKE_LENGTH;
    score = 0;
    
    BSP_LCD_Clear(GAME_BG);
    BSP_LCD_SetBackColor (GAME_BG);
    BSP_LCD_SetTextColor(LCD_COLOR_GRAY);

    BSP_LCD_SetTextColor (LCD_COLOR_YELLOW);
    BSP_LCD_SetFont(&Font20);
    BSP_LCD_DisplayStringAt(0, 40, (uint8_t*)"SNAKE GAME", CENTER_MODE);
    BSP_LCD_SetFont(&Font16);
    BSP_LCD_DisplayStringAt(0, 80, (uint8_t*)"Start game", CENTER_MODE);
    BSP_LCD_DisplayStringAt(0, 100, (uint8_t*)"Press any key", CENTER_MODE);

    BSP_LCD_SetTextColor(LCD_COLOR_GRAY);
    BSP_LCD_FillRect (130, 155, 5, 5);
    
    BSP_LCD_SetTextColor(LCD_COLOR_GRAY);
    BSP_LCD_FillRect (112, 155, 5, 5);
    BSP_LCD_SetTextColor(LCD_COLOR_YELLOW);
    BSP_LCD_FillRect (100, 155, 5, 5);
    BSP_LCD_FillRect (106, 155, 5, 5);
    BSP_LCD_FillRect (100, 162, 5, 5);
    BSP_LCD_FillRect (100, 169, 5, 5);
    BSP_LCD_FillRect (100, 176, 5, 5);
    BSP_LCD_FillRect (94, 176, 5, 5);
    BSP_LCD_FillRect (88, 176, 5, 5);
    BSP_LCD_FillRect (82, 176, 5, 5);
    BSP_LCD_FillRect (76, 176, 5, 5);
    BSP_LCD_FillRect (70, 176, 5, 5);
    BSP_LCD_FillRect (64, 176, 5, 5);
    BSP_LCD_FillRect (58, 176, 5, 5);
    BSP_LCD_FillRect (52, 176, 5, 5);
    BSP_LCD_FillRect (52, 183, 5, 5);
    BSP_LCD_FillRect (52, 190, 5, 5);
}

void initGameScreen(){
    BSP_LCD_Clear(GAME_BG);
    BSP_LCD_SetBackColor(GAME_BG);
    BSP_LCD_SetTextColor(LCD_COLOR_GRAY);
    BSP_LCD_SetFont(&Font8);
    
    BSP_LCD_SetTextColor(LCD_COLOR_YELLOW);

    for(int i = 0; i < snakeLength - 1; i++)
        drawSquare(X[i], Y[i]);
    
    char buffer[64];
    sprintf(buffer, "Score: %d", score);
    BSP_LCD_DisplayStringAt(10, 10, (uint8_t*)buffer, LEFT_MODE);
    
    BSP_LCD_SetTextColor(LCD_COLOR_GRAY);
    drawSquare(X[snakeLength - 1], Y[snakeLength - 1]);

    drawTarget(targetX, targetY);
}


void initEndGameScreen(){
    BSP_LCD_Clear(GAME_BG);
    BSP_LCD_SetBackColor (GAME_BG);
    BSP_LCD_SetTextColor(LCD_COLOR_GRAY);
    
    BSP_LCD_SetFont(&Font24);
    BSP_LCD_SetTextColor(LCD_COLOR_RED);
    BSP_LCD_DisplayStringAt(0, 20, (uint8_t*)"GAME OVER", CENTER_MODE);
    
    BSP_LCD_SetFont(&Font16);
    BSP_LCD_SetTextColor(LCD_COLOR_YELLOW);
    char buffer[64];
    sprintf(buffer, "Score: %d", score);
    BSP_LCD_DisplayStringAt(0, 80, (uint8_t*)buffer, CENTER_MODE);

    BSP_LCD_SetFont(&Font16);
    BSP_LCD_SetTextColor(LCD_COLOR_YELLOW);
    BSP_LCD_DisplayStringAt(120, 215, (uint8_t*)"Play again",LEFT_MODE);
    BSP_LCD_DisplayStringAt(8, 215, (uint8_t*)"Home", LEFT_MODE);
}

void initScreen(){
    switch (mode) {
        case MAIN_MENU:
            initMainMenuScreen();
            break;
        case GAME:
            initGameScreen();
            break;
        case END_GAME:
            initEndGameScreen();
            break;
    }
}

void initTarget(){
    bool isSet = true;
    do{
        isSet = true;
        srand (time(NULL));
        targetX = (rand() % (MAX_X - 2)) + 1;
        targetY = (rand() % (MAX_Y - 2)) + 1;
        
        for(int i = 0; i < snakeLength; i++)
            if(X[i] == targetX && Y[i] == targetY)
                isSet = false;
    }while(!isSet);
}

void initPause(){
    BSP_LCD_SetTextColor (LCD_COLOR_YELLOW);
    BSP_LCD_SetFont(&Font16);
    BSP_LCD_DisplayStringAt(0, 100, (uint8_t*)"Game paused", CENTER_MODE);
}

void gameTick(){
    if(!toggglePause){
        if(mode != GAME) return;

        int headX = X[snakeLength - 1];
        int headY = Y[snakeLength - 1];
        
        switch(direction){
            case UP:
                Y[snakeLength - 1] = Y[snakeLength - 1] - 1;
                if(Y[snakeLength - 1] == 0)
                    Y[snakeLength - 1] = MAX_Y - 1;
                break;
            case DOWN:
                Y[snakeLength - 1] = (Y[snakeLength - 1] + 1) % MAX_Y;
                if(Y[snakeLength - 1] == 0) Y[snakeLength - 1] = 1;
                break;
            case LEFT:
                X[snakeLength - 1] = X[snakeLength - 1] - 1;
                if(X[snakeLength - 1] == 0)
                    X[snakeLength - 1] = MAX_X - 1;
                break;
            case RIGHT:
                X[snakeLength - 1] = (X[snakeLength - 1] + 1) % MAX_X;
                if(X[snakeLength - 1] == 0) X[snakeLength - 1] = 1;
                break;
        }

        if(X[snakeLength - 1] == targetX && Y[snakeLength - 1] == targetY){
            turnOnForTime(0.5);
            score++;
            snakeLength++;
            X[snakeLength - 1] = X[snakeLength - 2];
            Y[snakeLength - 1] = Y[snakeLength - 2];
            initTarget();
        }else
            for(int i = 0; i < snakeLength - 2; i++){
                X[i] = X[i+1];
                Y[i] = Y[i+1];
            }
        X[snakeLength - 2] = headX;
        Y[snakeLength - 2] = headY;
        
        for(int i = 0; i < snakeLength; i++){
            if(X[snakeLength - 1] == X[i] && Y[snakeLength - 1] == Y[i] && i != snakeLength - 1){
                isEndGame = false;
                mode = END_GAME;
                break;
            }
        }
    }
    else{
        if(mode != GAME) return;
        initPause();
    }
}

void controller(Dirrection newDirection){
    switch (mode) {
        case MAIN_MENU:
            mode = GAME;
            break;
        case GAME:
            if(abs(direction - newDirection) != 2)
                direction = newDirection;
            break;
        case END_GAME:
            if(newDirection == LEFT)
                mode = MAIN_MENU;
            else if(newDirection == RIGHT)
                initGame();
            break;
    }
}

void clickLeft(){
    controller(LEFT);
}

void clickUp(){
    controller(UP);
}

void clickRight(){
    controller(RIGHT);
}

void clickDown(){
    controller(DOWN);
}

int main() {
    BSP_LCD_Init();

    bLeft.rise(&clickLeft);
    bUp.rise(&clickUp);
    bRight.rise(&clickRight);
    bDown.rise(&clickDown);
    gameTicker.attach(&gameTick, SCREEN_REFRESH_PERIOD);
    mainTicker.attach(&initScreen, SCREEN_REFRESH_PERIOD);
    
    initTarget();
}