#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#define PIN_BUTTON 2
LiquidCrystal_I2C lcd(0x27,16,2);
bool buttonPushed = false;
bool game_running = false;
int bird_position = 0; // Initial position of the bird on line 1
int score = 0;
//int pipe_x = 15; // Initial x position of the pipe on the LCD
#define BIRD_WIDTH 2
#define BIRD_HEIGHT 7
#define PIPE_WIDTH 3
#define PIPE_HEIGHT 7
// Coordinates of the bird and the pipe
int bird_x = 1; // X coordinate of the bird
int bird_y = 0; // Y coordinate of the bird
//int pipe_x = 15; // X coordinate of the pipe
int pipe_y = 0; // Y coordinate of the pipe
// Defining bird character
uint8_t bird_char[] = {
0b00000,
0b01010,
0b00100,
0b11111,
0b01110,
0b01010,
0b01010,
0b10001
};
// Define pipe character
uint8_t pipe_char[] = {
0b11100,
0b11100,
0b11100,
0b11100,
0b11100,
0b11100,
0b11100,
0b11100
};
const int numPipes = 2; // Number of pipes
int pipe_x[numPipes]; // Array to store x-positions of pipes
bool pipeActive[numPipes]; // Array to track active/inactive state of pipes
const int numPipesDown = 1; // Number of pipes
int pipe_x_Down[numPipesDown]; // Array to store x-positions of pipes
bool pipeActiveDown[numPipesDown]; // Array to track active/inactive state of pipes
// Draw the bird at its current position
void drawBird() {
lcd.setCursor(1, bird_y);
lcd.write(0); // Draw the bird character
}
void drawPipe(int index) {
lcd.setCursor(pipe_x[index], 0);
lcd.write(1); // Custom character for pipe
}
void pipeRow_Zero(){
for (int i = 0; i < numPipes; i++) {
if (!pipeActive[i]) {
pipeActive[i] = true;
break;
}
}
// Move and redraw active pipes
for (int i = 0; i < numPipes; i++) {
if (pipeActive[i]) {
// Move the active pipe leftward
pipe_x[i]--;
// Check if the pipe is off the screen
if (pipe_x[i] < 0) { // Adjust the condition based on the pipe size
// Reset pipe position to the right edge and mark as inactive
pipe_x[i] = 16; // Reset pipe position to the right edge
pipeActive[i] = false;
}
// Display the active pipe
drawPipe(i);
}
}
}
void pipeRow_One(){
for (int i = 0; i < numPipesDown; i++) {
if (!pipeActiveDown[i]) {
pipeActiveDown[i] = true;
break;
}
}
// Move and redraw active pipes
for (int i = 0; i < numPipesDown; i++) {
if (pipeActiveDown[i]) {
// Move the active pipe leftward
pipe_x_Down[i]--;
// Check if the pipe is off the screen
if (pipe_x_Down[i] < 0) { // Adjust the condition based on the pipe size
// Reset pipe position to the right edge and mark as inactive
pipe_x_Down[i] = 16; // Reset pipe position to the right edge
pipeActiveDown[i] = false;
}
// Display the active pipe
drawPipeDown(i);
}
}
}
void drawPipeDown(int indexDown) {
lcd.setCursor(pipe_x_Down[indexDown], 1);
lcd.write(1); // Custom character for pipe
}
bool checkCollisionRowZero() {
// Bird boundaries
int birdLeft = bird_x;
int birdRight = bird_x + BIRD_WIDTH - 1;
int birdTop = bird_y;
int birdBottom = bird_y + BIRD_HEIGHT - 1;
// Check collision for each active pipe in row one
for (int i = 0; i < numPipes; i++) {
if (pipeActive[i]) {
// Pipe boundaries for row one
int pipeLeft = pipe_x[i];
int pipeRight = pipe_x[i] + PIPE_WIDTH - 1; // Subtract 1 as it starts from 0
// Check for collision in the x-axis
bool xCollision = (birdRight >= pipeLeft) && (birdLeft <= pipeRight);
// Check for collision in the y-axis
bool yCollision = (birdBottom >= pipe_y + 1) || (birdTop <= pipe_y + 1 + PIPE_HEIGHT - 1);
// If there's a collision in both axes, it's a collision
if (xCollision && yCollision) {
// Collision detected in row one
return true;
}
}
}
// No collision in row one
return false;
}
bool checkCollisionRowOne() {
// Bird boundaries
int birdLeft = bird_x;
int birdRight = bird_x + BIRD_WIDTH - 1;
int birdTop = bird_y;
int birdBottom = bird_y + BIRD_HEIGHT - 1;
// Check collision for each active pipe in row one
for (int i = 0; i < numPipesDown; i++) {
if (pipeActiveDown[i]) {
// Pipe boundaries for row one
int pipeLeft = pipe_x_Down[i];
int pipeRight = pipe_x_Down[i] + PIPE_WIDTH - 1; // Subtract 1 as it starts from 0
// Check for collision in the x-axis
bool xCollision = (birdRight >= pipeLeft) && (birdLeft <= pipeRight);
// Check for collision in the y-axis
bool yCollision = (birdBottom >= pipe_y + 1) || (birdTop <= pipe_y + 1 + PIPE_HEIGHT - 1);
// If there's a collision in both axes, it's a collision
if (xCollision && yCollision) {
// Collision detected in row one
return true;
}
}
}
// No collision in row one
return false;
}
// Display score on the LCD at position (14, 0)
void displayScore() {
lcd.setCursor(14, 0);
lcd.print(score);
}
// Handle the button push as an interrupt
void buttonPush() {
buttonPushed = true;
}
void setup(){
pinMode(PIN_BUTTON, INPUT);
digitalWrite(PIN_BUTTON, HIGH);
lcd.init();
lcd.backlight();
// Digital pin 2 maps to interrupt 0
attachInterrupt(0/*PIN_BUTTON*/, buttonPush, FALLING);
// Initialize pipes
for (int i = 0; i < numPipes; i++) {
pipe_x[i] = 20 + i * 4; // Initial x-positions of pipes (spaced out)
pipeActive[i] = false; // Start with pipes inactive
}
for (int i = 0; i < numPipesDown; i++) {
pipe_x_Down[i] = 16 + i * 3; // Initial x-positions of pipes (spaced out)
pipeActiveDown[i] = false; // Start with pipes inactive
}
//lcd.begin();
}
bool gameStarted = false;
void loop(){
lcd.createChar(0, bird_char);
lcd.createChar(1, pipe_char);
lcd.clear();
if(!gameStarted){
lcd.setCursor(0, 0);
lcd.print("Push button");
if(buttonPushed){
gameStarted = true;
}
}
else{
if((bird_y == 0 && !checkCollisionRowZero()) || bird_y == 1 && !checkCollisionRowOne() ){
drawBird(); // Draw the bird at its updated position
pipeRow_One();
pipeRow_Zero();
score++;
displayScore();
}
else {
lcd.clear();
lcd.print("Game Over");
displayScore();
//gameStarted = false;
}
}
delay(500);
}