286 lines
8.2 KiB
C
286 lines
8.2 KiB
C
#include "main.h" // HAL, ILI9341, CMSIS-RTOS handles
|
|
#include "cmsis_os.h" // RTOS types like osMutexAcquire, osMessageQueueGet
|
|
#include "stdlib.h" // For rand()
|
|
#include "stdio.h" // For sprintf()
|
|
#include "snake.h" // Your own header for declarations
|
|
#include "ILI9341_STM32_Driver.h"
|
|
#include "fonts.h"
|
|
|
|
struct Snake snake; // define the global variable here
|
|
#define FLASH_USER_ADDR ((uint32_t)0x0803F000) // Last 4 KB
|
|
void Flash_Write_HighScore(uint32_t highscore) {
|
|
HAL_FLASH_Unlock();
|
|
|
|
// Erase the sector first
|
|
FLASH_EraseInitTypeDef EraseInitStruct;
|
|
uint32_t PageError = 0;
|
|
|
|
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
|
|
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
|
|
EraseInitStruct.Sector = FLASH_SECTOR_5;
|
|
EraseInitStruct.NbSectors = 1;
|
|
|
|
if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK) {
|
|
// Handle error
|
|
return;
|
|
}
|
|
|
|
// Program the word
|
|
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, FLASH_USER_ADDR, highscore)
|
|
!= HAL_OK) {
|
|
// Handle error
|
|
}
|
|
|
|
HAL_FLASH_Lock();
|
|
}
|
|
uint32_t Flash_Read_HighScore(void) {
|
|
return *(uint32_t*) FLASH_USER_ADDR;
|
|
}
|
|
|
|
|
|
// Function to initialize game variables
|
|
void GameInit() {
|
|
|
|
snake.gamesizeheight = 6;
|
|
snake.gamesizewidth = 8;
|
|
snake.isGameOver = 0;
|
|
snake.Dir = RIGHT;
|
|
snake.x = 1; //snake.gamesizewidth / 2;
|
|
snake.y = 1; //snake.gamesizeheight / 2;
|
|
snake.fruitCordX = rand() % snake.gamesizewidth;
|
|
snake.fruitCordY = rand() % snake.gamesizeheight;
|
|
snake.playerScore = 0;
|
|
snake.TailLen = 0;
|
|
snake.TailGrowPending = 0;
|
|
if (osMutexAcquire(displayHandle, osWaitForever) == osOK) {
|
|
ILI9341_FillScreen(WHITE);
|
|
osMutexRelease(displayHandle);
|
|
}
|
|
}
|
|
// Function for updating the game state
|
|
void UpdateGame() {
|
|
|
|
char dir;
|
|
// check the queue non blocking
|
|
osStatus_t status = osMessageQueueGet(pressesHandle, &dir, NULL, 0); // 0 = no wait
|
|
|
|
if (status == osOK) {
|
|
switch (dir) {
|
|
case 'L':
|
|
snake.Dir = LEFT;
|
|
break;
|
|
case 'R':
|
|
snake.Dir = RIGHT;
|
|
break;
|
|
case 'U':
|
|
snake.Dir = UP;
|
|
break;
|
|
case 'D':
|
|
snake.Dir = DOWN;
|
|
break;
|
|
}
|
|
}
|
|
if (!snake.TailGrowPending) {
|
|
if (snake.TailLen > 0) {
|
|
snake.TailPendingDeletionX = snake.TailX[snake.TailLen - 1];
|
|
snake.TailPendingDeletionY = snake.TailY[snake.TailLen - 1];
|
|
} else {
|
|
snake.TailPendingDeletionX = snake.x;
|
|
snake.TailPendingDeletionY = snake.y;
|
|
}
|
|
}
|
|
snake.TailGrowPending = 0;
|
|
// tail movement
|
|
if (snake.TailLen > 0) {
|
|
for (int i = snake.TailLen - 1; i > 0; i--) {
|
|
snake.TailX[i] = snake.TailX[i - 1];
|
|
snake.TailY[i] = snake.TailY[i - 1];
|
|
}
|
|
snake.TailX[0] = snake.x;
|
|
snake.TailY[0] = snake.y;
|
|
}
|
|
|
|
switch (snake.Dir) {
|
|
case LEFT:
|
|
snake.x--;
|
|
break;
|
|
case RIGHT:
|
|
snake.x++;
|
|
break;
|
|
case UP:
|
|
snake.y--;
|
|
break;
|
|
case DOWN:
|
|
snake.y++;
|
|
break;
|
|
}
|
|
|
|
// Checks for snake's collision with the wall
|
|
if (snake.x >= snake.gamesizewidth || snake.x < 0
|
|
|| snake.y >= snake.gamesizeheight || snake.y < 0)
|
|
snake.isGameOver = 1;
|
|
|
|
// Checks for collision with the tail (o)
|
|
for (int i = 0; i < snake.TailLen; i++) {
|
|
if (snake.TailX[i] == snake.x && snake.TailY[i] == snake.y)
|
|
snake.isGameOver = 1;
|
|
}
|
|
|
|
// Checks for snake's collision with the food (#)
|
|
if (snake.x == snake.fruitCordX && snake.y == snake.fruitCordY) {
|
|
snake.playerScore += 10;
|
|
snake.fruitCordX = rand() % snake.gamesizewidth;
|
|
snake.fruitCordY = rand() % snake.gamesizeheight;
|
|
snake.TailLen++;
|
|
snake.TailX[snake.TailLen - 1] = snake.x;
|
|
snake.TailY[snake.TailLen - 1] = snake.y;
|
|
snake.TailGrowPending = 1;
|
|
//snake.TailPendingDeletionX = -1;
|
|
}
|
|
if (snake.isGameOver) {
|
|
if (osMutexAcquire(displayHandle, osWaitForever) == osOK) {
|
|
|
|
if (Flash_Read_HighScore() > snake.playerScore) {
|
|
char str[50];
|
|
sprintf(str, "Highscore Remains: %lu", Flash_Read_HighScore());
|
|
ILI9341_DrawText(str, FONT3, 320 / 2 - 70, 240 / 2, BLACK,
|
|
WHITE);
|
|
// ILI9341_WriteString(320 / 2 - 70, 240 / 2, str, Font_11x18,
|
|
//ILI9341_MAGENTA, ILI9341_WHITE);
|
|
} else {
|
|
char str[50];
|
|
sprintf(str, "New Highscore: %lu", snake.playerScore);
|
|
//ILI9341_WriteString(320 / 2 - 70, 240 / 2, str, Font_11x18,
|
|
//ILI9341_MAGENTA, ILI9341_WHITE);
|
|
ILI9341_DrawText(str, FONT3, 320 / 2 - 70, 240 / 2, BLACK,
|
|
WHITE);
|
|
Flash_Write_HighScore(snake.playerScore);
|
|
}
|
|
osMutexRelease(displayHandle);
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// Function for creating the game board & rendering
|
|
void GameRender() {
|
|
|
|
// Creating top walls
|
|
// Creating side walls
|
|
//ILI9341_FillRectangle(j, i, ILI9341_WIDTH/snake.gamesizewidth, ILI9341_HEIGHT/snake.gamesizeheight, ILI9341_YELLOW);
|
|
//ILI9341_FillScreen(MAGENTA);
|
|
for (int x = 0; x < snake.gamesizewidth; x++) {
|
|
for (int y = 0; y <= snake.gamesizeheight; y++) {
|
|
|
|
if (x == snake.x && y == snake.y) {
|
|
if (osMutexAcquire(displayHandle, osWaitForever) == osOK) {
|
|
ILI9341_DrawFilledRectangleCoord(
|
|
(x * ILI9341_SCREEN_WIDTH) / snake.gamesizewidth,
|
|
(y * ILI9341_SCREEN_HEIGHT) / snake.gamesizeheight,
|
|
(x * ILI9341_SCREEN_WIDTH) / snake.gamesizewidth
|
|
+ ILI9341_SCREEN_WIDTH
|
|
/ snake.gamesizewidth,
|
|
(y * ILI9341_SCREEN_HEIGHT) / snake.gamesizeheight
|
|
+ ILI9341_SCREEN_HEIGHT
|
|
/ snake.gamesizeheight,
|
|
BLACK);
|
|
// ILI9341_FillRectangle(
|
|
// (x * ILI9341_WIDTH) / snake.gamesizewidth,
|
|
// (y * ILI9341_HEIGHT) / snake.gamesizeheight,
|
|
// ILI9341_WIDTH / snake.gamesizewidth,
|
|
// ILI9341_HEIGHT / snake.gamesizeheight,
|
|
// ILI9341_BLACK);
|
|
osMutexRelease(displayHandle);
|
|
}
|
|
}
|
|
|
|
//cout << "O";
|
|
// Creating the sanke's food with '#'
|
|
else if (x == snake.fruitCordX && y == snake.fruitCordY) {
|
|
if (osMutexAcquire(displayHandle, osWaitForever) == osOK) {
|
|
ILI9341_DrawFilledRectangleCoord(
|
|
(x * ILI9341_SCREEN_WIDTH) / snake.gamesizewidth,
|
|
(y * ILI9341_SCREEN_HEIGHT) / snake.gamesizeheight,
|
|
(x * ILI9341_SCREEN_WIDTH) / snake.gamesizewidth
|
|
+ ILI9341_SCREEN_WIDTH
|
|
/ snake.gamesizewidth,
|
|
(y * ILI9341_SCREEN_HEIGHT) / snake.gamesizeheight
|
|
+ ILI9341_SCREEN_HEIGHT
|
|
/ snake.gamesizeheight,
|
|
RED);
|
|
// ILI9341_FillRectangle(
|
|
// (x * ILI9341_WIDTH) / snake.gamesizewidth,
|
|
// (y * ILI9341_HEIGHT) / snake.gamesizeheight,
|
|
// ILI9341_WIDTH / snake.gamesizewidth,
|
|
// ILI9341_HEIGHT / snake.gamesizeheight, ILI9341_RED);
|
|
osMutexRelease(displayHandle);
|
|
}
|
|
}
|
|
|
|
//cout << "#";
|
|
|
|
else if (snake.TailLen >= 0) {
|
|
for (int i = 0; i < snake.TailLen; i++) {
|
|
|
|
if (snake.TailX[0] == x && snake.TailY[0] == y) {
|
|
if (osMutexAcquire(displayHandle, osWaitForever)
|
|
== osOK) {
|
|
ILI9341_DrawFilledRectangleCoord(
|
|
(x * ILI9341_SCREEN_WIDTH)
|
|
/ snake.gamesizewidth,
|
|
(y * ILI9341_SCREEN_HEIGHT)
|
|
/ snake.gamesizeheight,
|
|
(x * ILI9341_SCREEN_WIDTH)
|
|
/ snake.gamesizewidth
|
|
+ ILI9341_SCREEN_WIDTH
|
|
/ snake.gamesizewidth,
|
|
(y * ILI9341_SCREEN_HEIGHT)
|
|
/ snake.gamesizeheight
|
|
+ ILI9341_SCREEN_HEIGHT
|
|
/ snake.gamesizeheight,
|
|
GREEN);
|
|
// ILI9341_FillRectangle(
|
|
// (x * ILI9341_WIDTH) / snake.gamesizewidth,
|
|
// (y * ILI9341_HEIGHT) / snake.gamesizeheight,
|
|
// ILI9341_WIDTH / snake.gamesizewidth,
|
|
// ILI9341_HEIGHT / snake.gamesizeheight,
|
|
// ILI9341_GREEN);
|
|
osMutexRelease(displayHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
if (snake.TailPendingDeletionX == x
|
|
&& snake.TailPendingDeletionY == y) {
|
|
|
|
if (osMutexAcquire(displayHandle, osWaitForever) == osOK) {
|
|
ILI9341_DrawFilledRectangleCoord(
|
|
(x * ILI9341_SCREEN_WIDTH) / snake.gamesizewidth,
|
|
(y * ILI9341_SCREEN_HEIGHT) / snake.gamesizeheight,
|
|
(x * ILI9341_SCREEN_WIDTH) / snake.gamesizewidth
|
|
+ ILI9341_SCREEN_WIDTH
|
|
/ snake.gamesizewidth,
|
|
(y * ILI9341_SCREEN_HEIGHT) / snake.gamesizeheight
|
|
+ ILI9341_SCREEN_HEIGHT
|
|
/ snake.gamesizeheight,
|
|
WHITE);
|
|
// ILI9341_FillRectangle(
|
|
// (x * ILI9341_WIDTH) / snake.gamesizewidth,
|
|
// (y * ILI9341_HEIGHT) / snake.gamesizeheight,
|
|
// ILI9341_WIDTH / snake.gamesizewidth,
|
|
// ILI9341_HEIGHT / snake.gamesizeheight,
|
|
// ILI9341_WHITE);
|
|
osMutexRelease(displayHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
int isGameOver(){
|
|
return snake.isGameOver;
|
|
}
|