touchscreengames/Core/Src/snake.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;
}