305 lines
5.7 KiB
C++
305 lines
5.7 KiB
C++
#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();
|
|
}
|
|
}
|