Initial working version
This commit is contained in:
commit
438b31085f
|
@ -0,0 +1,37 @@
|
|||
# Classic Snake game for the STM32 board
|
||||
## Hardware prerequisities
|
||||
* stm32duino (should work on generic Arduino boards)
|
||||
* Philips PCD8544 (Nokia 3310) LCD
|
||||
|
||||
## Software prerequisities
|
||||
* Arduino Software
|
||||
* [Arduino Core for STM32](https://github.com/stm32duino/Arduino_Core_STM32)
|
||||
* [Adafruit PCD8544 Library](https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library)
|
||||
* [Adafruit GFX Library](https://github.com/adafruit/Adafruit-GFX-Library)
|
||||
* [SimpleTimer Library for Arduino](https://playground.arduino.cc/Code/SimpleTimer#Download)
|
||||
* [Standard C++ for Arduino](https://github.com/maniacbug/StandardCplusplus)
|
||||
|
||||
## Building and flashing
|
||||
Just as with normal Arduino codes, build and flash it from the Arduino Software.
|
||||
* Board: Generic STM32F103C series
|
||||
* Variant: STM32F103C8 (20K RAM. 64K Flash)
|
||||
* CPU Speed: 72MHz
|
||||
|
||||
## Note
|
||||
If using a different board, then change the configuration and modify the pins accordingly.
|
||||
For the STM32 board the following changes are necessary:
|
||||
|
||||
Adafruit_PCD8544.h:
|
||||
```
|
||||
#define PCD8544_SPI_CLOCK_DIV SPI_CLOCK_DIV4 -> #define PCD8544_SPI_CLOCK_DIV SPI_CLOCK_DIV8
|
||||
```
|
||||
|
||||
```
|
||||
#ifdef __SAM3X8E__
|
||||
typedef volatile RwReg PortReg;
|
||||
typedef uint8_t PortMask; -> typedef uint32_t PortMask;
|
||||
#else
|
||||
typedef volatile uint32_t PortReg;
|
||||
typedef uint8_t PortMask; -> typedef uint32_t PortMask;
|
||||
#endif
|
||||
```
|
|
@ -0,0 +1,304 @@
|
|||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_PCD8544.h>
|
||||
#include <vector>
|
||||
#include <SimpleTimer.h>
|
||||
|
||||
#define clk PB13
|
||||
#define din PB15
|
||||
#define dc PB14
|
||||
#define cs PB12
|
||||
#define rst PA15
|
||||
// Software SPI (slower updates, more flexible pin options):
|
||||
// pin 7 - Serial clock out (SCLK)
|
||||
// pin 6 - Serial data out (DIN)
|
||||
// pin 5 - Data/Command select (D/C)
|
||||
// pin 4 - LCD chip select (CS)
|
||||
// pin 3 - LCD reset (RST)
|
||||
Adafruit_PCD8544 display = Adafruit_PCD8544(clk, din, dc, cs, rst);
|
||||
|
||||
//speed in ms
|
||||
#define SPEED 250
|
||||
SimpleTimer timer;
|
||||
|
||||
#define SNAKE_INIT_LENGTH 10 //Initial length of snake
|
||||
#define SNAKE_START_X 42 //Initial x position
|
||||
#define SNAKE_START_Y 20 //Initial y position
|
||||
|
||||
//Pin setup according to the board
|
||||
#define left PA1
|
||||
#define right PB8
|
||||
#define up PA0
|
||||
#define down PB9
|
||||
#define center PC13
|
||||
#define left_led PB6
|
||||
#define right_led PB7
|
||||
|
||||
//Store the coordinates in a structure
|
||||
struct coordinates
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
std::vector<coordinates> snake; //store the snake points
|
||||
coordinates snake_last_piece; //store the last point | needed for visualisation
|
||||
|
||||
coordinates food; //food coordinates
|
||||
|
||||
bool leds = true; //for LED blink
|
||||
|
||||
int direction = 0;
|
||||
int last_direction = 0;
|
||||
|
||||
int points = 0;
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
//Serial port
|
||||
Serial.begin(9600);
|
||||
|
||||
//Set inputs and outputs
|
||||
pinMode(left, INPUT_PULLUP);
|
||||
pinMode(right, INPUT_PULLUP);
|
||||
pinMode(up, INPUT_PULLUP);
|
||||
pinMode(down, INPUT_PULLUP);
|
||||
pinMode(center, INPUT_PULLUP);
|
||||
pinMode(left_led, OUTPUT);
|
||||
pinMode(right_led, OUTPUT);
|
||||
|
||||
display.begin();
|
||||
display.setContrast(63);
|
||||
|
||||
display.display(); //show splashscreen
|
||||
delay(2000);
|
||||
display.clearDisplay();
|
||||
|
||||
init_game();
|
||||
|
||||
timer.setInterval(SPEED, TimerCallbackFunc); //Timer for moving the snake
|
||||
}
|
||||
|
||||
void init_game()
|
||||
{
|
||||
/*
|
||||
* This function initializes the snake, clears the points and direction, and generate a new food.
|
||||
* Can be used to reset the game.
|
||||
*/
|
||||
|
||||
//init the snake
|
||||
direction = 0;
|
||||
|
||||
points = 0;
|
||||
|
||||
snake.clear(); //clear the vector
|
||||
for(int i = 0; i < SNAKE_INIT_LENGTH; i++)
|
||||
{
|
||||
coordinates helper;
|
||||
helper.x = SNAKE_START_X - i;
|
||||
helper.y = SNAKE_START_Y;
|
||||
snake.push_back(helper);
|
||||
}
|
||||
|
||||
snake_last_piece.x = 0;
|
||||
snake_last_piece.y = 0;
|
||||
|
||||
generate_food();
|
||||
}
|
||||
|
||||
void TimerCallbackFunc()
|
||||
{
|
||||
//blinks the 2 LED
|
||||
digitalWrite(left_led, leds);
|
||||
digitalWrite(right_led, !leds);
|
||||
leds = !leds;
|
||||
|
||||
//Moving in the given direction
|
||||
snake_move(direction);
|
||||
}
|
||||
|
||||
void generate_food()
|
||||
{
|
||||
/*
|
||||
* Generates random x and y points until it's out of the snake's points.
|
||||
*/
|
||||
bool equal = true;
|
||||
while(equal)
|
||||
{
|
||||
equal = false;
|
||||
food.x = random(0, 83);
|
||||
food.y = random(0,47);
|
||||
for(int i = 0; i < snake.size(); i++)
|
||||
{
|
||||
if(snake[0].x == food.x && snake[0].y == food.y)
|
||||
{
|
||||
equal = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
display.drawPixel(food.x, food.y, BLACK);
|
||||
display.display();
|
||||
}
|
||||
|
||||
void draw_snake()
|
||||
{
|
||||
/*
|
||||
* Draw the snake points.
|
||||
*/
|
||||
for(int i = 0; i < snake.size(); i++)
|
||||
{
|
||||
display.drawPixel(snake[i].x, snake[i].y, BLACK);
|
||||
}
|
||||
display.drawPixel(snake_last_piece.x, snake_last_piece.y, WHITE);
|
||||
display.display();
|
||||
}
|
||||
|
||||
bool check_crash()
|
||||
{
|
||||
/*
|
||||
* Returns true if the snake crashing into itself.
|
||||
*/
|
||||
for(int i = 1; i < snake.size(); i++)
|
||||
{
|
||||
if(snake[0].x == snake[i].x && snake[0].y == snake[i].y)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void snake_move(int direction)
|
||||
{
|
||||
/*
|
||||
* Handling the moving directions and next points.
|
||||
*/
|
||||
last_direction = direction;
|
||||
|
||||
snake_last_piece.x = snake[snake.size()-1].x;
|
||||
snake_last_piece.y = snake[snake.size()-1].y;
|
||||
|
||||
coordinates helper;
|
||||
|
||||
if(direction == 0) //right
|
||||
{
|
||||
helper = snake[0];
|
||||
helper.x++;
|
||||
if(helper.x > 83)
|
||||
{
|
||||
helper.x = 0;
|
||||
}
|
||||
}
|
||||
else if(direction == 1) //left
|
||||
{
|
||||
helper = snake[0];
|
||||
helper.x--;
|
||||
if(helper.x < 0)
|
||||
{
|
||||
helper.x = 83;
|
||||
}
|
||||
}
|
||||
else if(direction == 2) //up
|
||||
{
|
||||
helper = snake[0];
|
||||
helper.y--;
|
||||
if(helper.y < 0)
|
||||
{
|
||||
helper.y = 47;
|
||||
}
|
||||
}
|
||||
else if(direction == 3) //down
|
||||
{
|
||||
helper = snake[0];
|
||||
helper.y++;
|
||||
if(helper.y > 47)
|
||||
{
|
||||
helper.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//move forward every coordinate and replace the first with the new one
|
||||
for(int i = snake.size(); i > 0; i--)
|
||||
{
|
||||
snake[i] = snake [i-1];
|
||||
}
|
||||
snake[0] = helper;
|
||||
draw_snake();
|
||||
|
||||
//if the snake ate the food, then increment by one and generate a new one
|
||||
if(snake[0].x == food.x && snake[0].y == food.y)
|
||||
{
|
||||
increment_snake();
|
||||
generate_food();
|
||||
}
|
||||
}
|
||||
|
||||
void increment_snake()
|
||||
{
|
||||
snake.push_back(snake[snake.size()]);
|
||||
points++;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
timer.run();
|
||||
if(digitalRead(left) == 0)
|
||||
{
|
||||
Serial.print("Left button pressed");
|
||||
if(last_direction != 0)
|
||||
{
|
||||
direction = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(digitalRead(right) == 0)
|
||||
{
|
||||
Serial.print("Right button pressed");
|
||||
if(last_direction != 1)
|
||||
{
|
||||
direction = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(digitalRead(up) == 0)
|
||||
{
|
||||
Serial.print("Up button pressed");
|
||||
if(last_direction != 3)
|
||||
{
|
||||
direction = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(digitalRead(down) == 0)
|
||||
{
|
||||
Serial.print("Down button pressed");
|
||||
if(last_direction != 2)
|
||||
{
|
||||
direction = 3;
|
||||
}
|
||||
}
|
||||
|
||||
if(digitalRead(center) == 0)
|
||||
{
|
||||
Serial.print("Center button pressed");
|
||||
display.drawPixel(food.x, food.y, BLACK);
|
||||
display.display();
|
||||
}
|
||||
if(check_crash())
|
||||
{
|
||||
display.clearDisplay();
|
||||
display.setTextSize(1);
|
||||
display.setTextColor(BLACK);
|
||||
display.setCursor(0,0);
|
||||
display.println("Game over!");
|
||||
//display.setCursor(0,10);
|
||||
display.println("Score: ");
|
||||
display.print(points, DEC);
|
||||
display.display();
|
||||
|
||||
while(digitalRead(center) != 0)
|
||||
{
|
||||
}
|
||||
display.clearDisplay();
|
||||
init_game();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue