1
0
This repository has been archived on 2021-11-13. You can view files and clone it, but cannot push or open issues or pull requests.
2019-12-07 14:14:58 +01:00

282 lines
8.5 KiB
C

/*
* game_engine.c
*
* Created on: 29 nov. 2019
* Author: JackCarterSmith
*/
#include "game_engine.h"
#include "string.h"
#include "stm32412g_discovery.h"
#include "stm32412g_discovery_lcd.h"
RNG_HandleTypeDef RngHandle;
PP_BallTypeDef ballDatas;
PP_BallTypeDef displayedBall;
MenuTypdef currMenu = MENU_MAIN;
Game_ModeTypdef currGameMode = SOLO_MODE;
uint16_t currScore;
uint32_t oldTicks = 0;
/**
* @brief Main control byte for game engine
*/
struct gameControlByte {
unsigned start_disp:1;
unsigned scoreUpdFlag:1;
unsigned playerFail:1;
unsigned reserved3:1;
unsigned reserved4:1;
unsigned reserved5:1;
unsigned reserved6:1;
unsigned reserved7:1;
} gCtrlByte;
/**
* @brief Generate new ball's pos and acc from random seed
*/
void generateNewBall(Game_ModeTypdef type, uint32_t seed) {
switch (type) {
case MULTI_MODE:
break;
case SOLO_MODE:
default:
ballDatas.posX = (seed & 0xFF) % 240;
ballDatas.posY = ((seed & 0xFF00 >> 7) % 180) + 60;
if (ballDatas.posX < 0) ballDatas.posX = -ballDatas.posX;
if (ballDatas.posY < 0) ballDatas.posY = -ballDatas.posY;
ballDatas.accX = ((seed & 0xFF0000 >> 15) % 8) + 4;
ballDatas.accY = ((seed & 0xFF000000 >> 31) % 8) + 4;
if (seed & 0x1) ballDatas.accX = -ballDatas.accX;
if (seed & 0x2 >> 1) ballDatas.accY = -ballDatas.accY;
break;
}
}
/**
* @brief Collision and animation engine for the ball/bar
*/
void ballRayTracingEngine(PP_BarTypeDef *barDatas) {
if (ballDatas.posX + ballDatas.accX > 236) {
ballDatas.posX = 236;
ballDatas.accX = -ballDatas.accX;
} else if (ballDatas.posX + ballDatas.accX < 0) {
ballDatas.posX = 0;
ballDatas.accX = -ballDatas.accX;
} else {
ballDatas.posX += ballDatas.accX;
}
if ((ballDatas.posY + ballDatas.accY > BSP_LCD_GetYSize() - 16) && ballDatas.posX > barDatas->pos - 19 && ballDatas.posX < barDatas->pos + 19) {
currScore++;
gCtrlByte.scoreUpdFlag = 1;
ballDatas.accY = -ballDatas.accY;
} else {
if (ballDatas.posY + ballDatas.accY > 236) {
ballDatas.posY = 236;
ballDatas.accY = -ballDatas.accY;
} else if (ballDatas.posY + ballDatas.accY < 26) {
ballDatas.posY = 26;
ballDatas.accY = -ballDatas.accY;
} else {
ballDatas.posY += ballDatas.accY;
}
}
}
/**
* @brief Refresh ball displayed on screen
*/
void updateBallDisplay() {
BSP_LCD_SetTextColor(LCD_COLOR_BLACK);
BSP_LCD_FillRect(displayedBall.posX, displayedBall.posY, 4, 4); //Clean previous ball
BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
BSP_LCD_FillRect(ballDatas.posX, ballDatas.posY, 4, 4); //Draw the ball at new pos
displayedBall.posX = ballDatas.posX;
displayedBall.posY = ballDatas.posY;
if (ballDatas.posY >= 236) displayEndMenu();
}
/**
* @brief Refresh bar displayed on screen
*/
void updatePongBar(PP_BarTypeDef *barDatas) {
BSP_LCD_SetTextColor(LCD_COLOR_BLACK);
BSP_LCD_FillRect(0, BSP_LCD_GetYSize() - 12, BSP_LCD_GetXSize(), 7); //Clean previous bar
BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
if (barDatas->pos + barDatas->acc > BSP_LCD_GetXSize() - 20) {
barDatas->pos = BSP_LCD_GetXSize() - 20;
} else if (barDatas->pos + barDatas->acc < 20) {
barDatas->pos = 20;
} else {
barDatas->pos += barDatas->acc;
}
BSP_LCD_FillRect(barDatas->pos - 20, BSP_LCD_GetYSize() - 12, 40, 7); //Draw the bar at new pos
}
/**
* @brief Refresh displayed score on game screen
*/
void updateScoreArea(Game_ModeTypdef type, uint16_t newScore) {
char sTextBuffer[32];
BSP_LCD_SetFont(&Font24);
BSP_LCD_SetTextColor(LCD_COLOR_BLACK);
BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
sprintf(sTextBuffer, "%d", newScore);
BSP_LCD_DisplayStringAt(6, 2, (uint8_t *)sTextBuffer, RIGHT_MODE);
BSP_LCD_FillRect(10, 24, BSP_LCD_GetXSize() - 20, 1);
}
/**
* @brief Get a new random number
*/
uint32_t genSeed() {
uint32_t tmp = 0;
if (HAL_RNG_Init(&RngHandle) == HAL_OK) {
tmp = HAL_RNG_GetRandomNumber(&RngHandle);
} else BSP_LED_On(LED_RED);
if (HAL_RNG_DeInit(&RngHandle) != HAL_OK) BSP_LED_On(LED_RED);
return tmp;
}
/**
* @brief Main function called when need to update screen
*/
void refreshCurrScreen(uint32_t _t, PP_BarTypeDef *_barDatas) {
char sTextBuffer[32];
if (currMenu == MENU_GAME) {
if (currGameMode == SOLO_MODE) {
if (_t - oldTicks >= 10 || _t - oldTicks < 0) {
ballRayTracingEngine(_barDatas);
if (gCtrlByte.scoreUpdFlag) {
gCtrlByte.scoreUpdFlag = 0;
updateScoreArea(SOLO_MODE, currScore);
}
updateBallDisplay();
updatePongBar(_barDatas);
oldTicks = _t;
}
} else if (currGameMode == MULTI_MODE) {
//Nothing
}
} else if (currMenu == MENU_MAIN || currMenu == MENU_END) {
if (_t - oldTicks >= 30 || _t - oldTicks < 0) {
if (gCtrlByte.start_disp) {
strcpy(sTextBuffer, " \0");
gCtrlByte.start_disp = 0;
} else if (!gCtrlByte.start_disp) {
strcpy(sTextBuffer, "Press START\0");
gCtrlByte.start_disp = 1;
}
BSP_LCD_DisplayStringAt(BSP_LCD_GetXSize() / 2 - 5 * 12, BSP_LCD_GetYSize() / 2 + 40, (uint8_t *)sTextBuffer, LEFT_MODE);
oldTicks = _t;
}
}
}
/**
* @brief Just a cool screen to display when the board start
*/
void displayLoadingScreen() {
char sTextBuffer[32];
BSP_LCD_SetBackColor(LCD_COLOR_BLACK);
BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
BSP_LCD_SetFont(&Font16);
strcpy(sTextBuffer, "2P - ProjectPong\0");
BSP_LCD_DisplayStringAt(BSP_LCD_GetXSize() / 2 - (strlen(sTextBuffer)/2 * BSP_LCD_GetFont()->Width), BSP_LCD_GetYSize() / 2 - 48, (uint8_t *)sTextBuffer, LEFT_MODE);
/* Print loading screen */
strcpy(sTextBuffer, "Loading...\0");
BSP_LCD_DisplayStringAt(BSP_LCD_GetXSize() / 2 - (strlen(sTextBuffer)/2 * BSP_LCD_GetFont()->Width), BSP_LCD_GetYSize() / 2 + 40, (uint8_t *)sTextBuffer, LEFT_MODE);
HAL_Delay(2000);
}
void displayStartMenu(PP_HighScoresTypeDef hsDatas) {
char sTextBuffer[32];
currMenu = MENU_MAIN;
BSP_LCD_Clear(LCD_COLOR_BLACK);
BSP_LCD_SetBackColor(LCD_COLOR_BLACK);
BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
BSP_LCD_SetFont(&Font16);
strcpy(sTextBuffer, "High Scores:\0");
BSP_LCD_DisplayStringAt(BSP_LCD_GetXSize() / 2 - (strlen(sTextBuffer)/2 * BSP_LCD_GetFont()->Width), BSP_LCD_GetYSize() / 2 - 70, (uint8_t *)sTextBuffer, LEFT_MODE);
sprintf(sTextBuffer, "Solo - %d", hsDatas.Solo_HS);
BSP_LCD_DisplayStringAt(BSP_LCD_GetXSize() / 2 - (strlen(sTextBuffer)/2 * BSP_LCD_GetFont()->Width), BSP_LCD_GetYSize() / 2 - 54, (uint8_t *)sTextBuffer, LEFT_MODE);
sprintf(sTextBuffer, "Multi - %d", hsDatas.Multi_HS);
BSP_LCD_DisplayStringAt(BSP_LCD_GetXSize() / 2 - (strlen(sTextBuffer)/2 * BSP_LCD_GetFont()->Width), BSP_LCD_GetYSize() / 2 - 40, (uint8_t *)sTextBuffer, LEFT_MODE);
BSP_LCD_FillRect(BSP_LCD_GetXSize() / 2 - 20, BSP_LCD_GetYSize() - 12, 40, 7);
/* READY TO START GAME! */
strcpy(sTextBuffer, "Press START\0");
BSP_LCD_DisplayStringAt(BSP_LCD_GetXSize() / 2 - 5 * 12, BSP_LCD_GetYSize() / 2 + 40, (uint8_t *)sTextBuffer, LEFT_MODE);
}
/**
* @brief Generate and display new game
*/
void displayGameArea(Game_ModeTypdef type, PP_BarTypeDef *_barDatas) {
uint32_t seed = 0;
currScore = 0;
_barDatas->pos = BSP_LCD_GetXSize() / 2;
gCtrlByte.scoreUpdFlag = 1;
gCtrlByte.playerFail = 0;
currMenu = MENU_GAME;
BSP_LCD_Clear(LCD_COLOR_BLACK);
BSP_LCD_FillRect(BSP_LCD_GetXSize() / 2 - 20, BSP_LCD_GetYSize() - 12, 40, 7);
seed = genSeed();
switch (type) {
case MULTI_MODE:
break;
case SOLO_MODE:
default:
BSP_LCD_SetBackColor(LCD_COLOR_BLACK);
BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
updateScoreArea(type, 0);
break;
}
generateNewBall(type,seed);
updateBallDisplay();
}
void displayEndMenu() {
char sTextBuffer[32];
currMenu = MENU_END;
BSP_LCD_SetFont(&Font16);
strcpy(sTextBuffer, "YOU HAVE FAILED!\0");
BSP_LCD_DisplayStringAt(BSP_LCD_GetXSize() / 2 - (strlen(sTextBuffer)/2 * BSP_LCD_GetFont()->Width), BSP_LCD_GetYSize() / 2 - 54, (uint8_t *)sTextBuffer, LEFT_MODE);
sprintf(sTextBuffer, "SCORE: %d", currScore);
BSP_LCD_DisplayStringAt(BSP_LCD_GetXSize() / 2 - (strlen(sTextBuffer)/2 * BSP_LCD_GetFont()->Width), BSP_LCD_GetYSize() / 2 - 40, (uint8_t *)sTextBuffer, LEFT_MODE);
//TODO: Save new HighScore in EEPROM if greather than the old one
/* READY TO START NEW GAME! */
strcpy(sTextBuffer, "Press START\0");
BSP_LCD_DisplayStringAt(BSP_LCD_GetXSize() / 2 - 5 * 12, BSP_LCD_GetYSize() / 2 + 40, (uint8_t *)sTextBuffer, LEFT_MODE);
}
MenuTypdef getCurrMenu() {
return currMenu;
}