// https://forum.arduino.cc/t/lcd-16-x-2-car-game/1179302
#include "LcdControl.h"
const byte rs = 13, en = 12, d4 = 7, d5 = 6, d6 = 5, d7 = 4;
LcdControl myLcd(rs, en, d4, d5, d6, d7);
const int turnLeftButton = 2;
const int turnRightButton = 3;
const int speakerPin = 8;
int notes[] = {165, 208, 220, 277};
const int rowsCount = 2;
const int columnsCount = 40;
unsigned screenUpdateInterval;
const int gameTimeout = 1000;
unsigned long lastStepTime = 0;
int carColumn;
volatile int carRow;
volatile bool isGameOver = true;
int prevCarRow = carRow;
int board[rowsCount][columnsCount];
byte car[8] = {
0b00000,
0b00000,
0b01010,
0b11111,
0b11111,
0b01010,
0b00000,
0b00000
};
void onLeftButtonPress() {
if (isGameOver) {
prepareBoard();
} else {
carRow = 0;
}
}
void onRightButtonPress() {
if (isGameOver) {
prepareBoard();
} else {
carRow = 1;
}
}
void showGameOver() {
isGameOver = true;
lastStepTime = millis();
myLcd.clear();
myLcd.selectPosition(0, 3);
myLcd.write("** GAME **");
myLcd.selectPosition(1, 4);
myLcd.write("* OVER *");
const int delayVal = 100;
tone(speakerPin, notes[3], delayVal);
delay(delayVal);
tone(speakerPin, notes[2], delayVal);
delay(delayVal);
tone(speakerPin, notes[1], delayVal);
delay(delayVal);
tone(speakerPin, notes[0], delayVal);
}
void prepareBoard() {
if (millis() - lastStepTime > gameTimeout) {
myLcd.clear();
for (int r = 0; r < rowsCount; r++) {
for (int c = 0; c < columnsCount; c++) {
board[r][c] = 32;
}
}
screenUpdateInterval = 100;
carColumn = 1;
carRow = 0;
isGameOver = false;
}
}
void setup() {
pinMode(turnLeftButton, INPUT_PULLUP);
pinMode(turnRightButton, INPUT_PULLUP);
pinMode(speakerPin, OUTPUT);
randomSeed(analogRead(A0));
myLcd.createChar(0, car);
myLcd.selectPosition(0, 5);
myLcd.write("PRESS");
myLcd.selectPosition(1, 4);
myLcd.write("ANY KEY");
attachInterrupt(digitalPinToInterrupt(turnLeftButton), onLeftButtonPress, CHANGE);
attachInterrupt(digitalPinToInterrupt(turnRightButton), onRightButtonPress, CHANGE);
}
void loop() {
if (!isGameOver) {
if ((millis() - lastStepTime) > screenUpdateInterval) {
lastStepTime = millis();
myLcd.shiftLeft();
if (prevCarRow != carRow) {
prevCarRow = carRow;
tone(speakerPin, notes[3] * 2, 1);
}
int columnToUpdate = (columnsCount + carColumn - 1) % columnsCount;
int rowWithObstacle = random(100) > 50 ? 0 : 1;
int obstacle = (carColumn % 5) || (random(100) > 50) ? 32 : 42;
for (int row = 0; row < rowsCount; row++) {
board[row][columnToUpdate] = rowWithObstacle == row ? obstacle : 32;
myLcd.selectPosition(row, columnToUpdate);
myLcd.write(board[row][columnToUpdate]);
}
if (board[carRow][carColumn] != 32) {
showGameOver();
} else {
myLcd.selectPosition(carRow, carColumn);
myLcd.write((byte) 0);
}
carColumn = (carColumn + 1) % columnsCount;
screenUpdateInterval =
carColumn == 39 && screenUpdateInterval > 50 ? screenUpdateInterval - 5 : screenUpdateInterval;
}
}
}