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