/*
Dinosaur Game
Arduino implementation of Google Chrome's Dinosaur Game
https://palmacas.com/mesa-automatica
*/
#include <U8g2lib.h>
#include <EEPROM.h>
// SSD1306 constructor using I2C
U8G2_SSD1306_128X64_NONAME_F_HW_I2C display(U8G2_R0);
// Images
// dinosaur, 21x22px
const unsigned char bitmap_dinosaur [] PROGMEM = {
0x00, 0xf8, 0x0f, 0x00, 0xfc, 0x1f, 0x00, 0xec, 0x1f, 0x00,
0xfc, 0x1f, 0x00, 0xfc, 0x1f, 0x00, 0xfc, 0x1f, 0x00, 0x7e,
0x00, 0x01, 0xff, 0x03, 0x81, 0x3f, 0x00, 0xc3, 0x3f, 0x00,
0xe7, 0xff, 0x00, 0xff, 0xbf, 0x00, 0xff, 0x3f, 0x00, 0xff,
0x3f, 0x00, 0xfe, 0x3f, 0x00, 0xfc, 0x1f, 0x00, 0xf8, 0x0f,
0x00, 0xf0, 0x07, 0x00, 0xe0, 0x06, 0x00, 0x60, 0x04, 0x00,
0x20, 0x04, 0x00, 0x60, 0x0c, 0x00 };
// dinosaur left, 21x22px
const unsigned char bitmap_dinosaur_left [] PROGMEM = {
0x00, 0xf8, 0x0f, 0x00, 0xfc, 0x1f, 0x00, 0xec, 0x1f, 0x00,
0xfc, 0x1f, 0x00, 0xfc, 0x1f, 0x00, 0xfc, 0x1f, 0x00, 0x7e,
0x00, 0x01, 0xff, 0x03, 0x81, 0x3f, 0x00, 0xc3, 0x3f, 0x00,
0xe7, 0xff, 0x00, 0xff, 0xbf, 0x00, 0xff, 0x3f, 0x00, 0xff,
0x3f, 0x00, 0xfe, 0x3f, 0x00, 0xfc, 0x1f, 0x00, 0xf8, 0x0f,
0x00, 0xf0, 0x07, 0x00, 0x60, 0x06, 0x00, 0xe0, 0x04, 0x00,
0x00, 0x04, 0x00, 0x00, 0x0c, 0x00, };
// dinosaur right, 21x22px
const unsigned char bitmap_dinosaur_right [] PROGMEM = {
0x00, 0xf8, 0x0f, 0x00, 0xfc, 0x1f, 0x00, 0xec, 0x1f, 0x00,
0xfc, 0x1f, 0x00, 0xfc, 0x1f, 0x00, 0xfc, 0x1f, 0x00, 0x7e,
0x00, 0x01, 0xff, 0x03, 0x81, 0x3f, 0x00, 0xc3, 0x3f, 0x00,
0xe7, 0xff, 0x00, 0xff, 0xbf, 0x00, 0xff, 0x3f, 0x00, 0xff,
0x3f, 0x00, 0xfe, 0x3f, 0x00, 0xfc, 0x1f, 0x00, 0xf8, 0x0f,
0x00, 0xf0, 0x07, 0x00, 0xe0, 0x0c, 0x00, 0x60, 0x00, 0x00,
0x20, 0x00, 0x00, 0x60, 0x00, 0x00, };
// pterodactyl up, 22x14px
const unsigned char bitmap_pterodactyl_up [] PROGMEM = {
0x00, 0x02, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0e, 0x00, 0x00,
0x1e, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x3e, 0x00, 0x30, 0x7e,
0x00, 0x78, 0xfe, 0x00, 0xfc, 0xfe, 0x01, 0xfe, 0xfe, 0x03,
0xff, 0xff, 0x3f, 0xc0, 0xff, 0x07, 0x00, 0xff, 0x1f, 0x00,
0xfc, 0x03, };
// pterodactyl down, 22x15px
const unsigned char bitmap_pterodactyl_down [] PROGMEM = {
0x30, 0x00, 0x00, 0x78, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfe,
0x00, 0x00, 0xff, 0xff, 0x3f, 0xc0, 0xff, 0x07, 0x00, 0xff,
0x1f, 0x00, 0xfe, 0x03, 0x00, 0xfe, 0x00, 0x00, 0x3e, 0x00,
0x00, 0x1e, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x06, 0x00, 0x00,
0x06, 0x00, 0x00, 0x02, 0x00, };
// cactus 1, 12x26px
const unsigned char bitmap_cactus_1 [] PROGMEM = {
0x60, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x04,
0xf2, 0x0e, 0xf7, 0x0e, 0xf7, 0x0e, 0xf7, 0x0e, 0xf7, 0x0e,
0xf7, 0x0e, 0xf7, 0x0e, 0xf7, 0x0e, 0xf7, 0x0e, 0xf7, 0x0e,
0xf7, 0x07, 0xf7, 0x03, 0xf7, 0x00, 0xfe, 0x00, 0xfc, 0x00,
0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
0xf0, 0x00, };
// cactus 2, 12x26px
const unsigned char bitmap_cactus_2 [] PROGMEM = {
0x60, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf2, 0x00,
0xf7, 0x00, 0xf7, 0x00, 0xf7, 0x04, 0xf7, 0x0e, 0xf7, 0x0e,
0xf7, 0x0e, 0xf7, 0x0e, 0xf7, 0x0e, 0xf7, 0x0e, 0xf7, 0x0e,
0xfe, 0x0e, 0xfc, 0x0e, 0xf0, 0x0e, 0xf0, 0x0e, 0xf0, 0x07,
0xf0, 0x03, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
0xf0, 0x00, };
// Button pins
#define BTN 4
int button_state = 0;
unsigned long last_press = 0;
// Buzzer pin
#define BUZ 9
// Variables
char *project = "Dinosaur Game";
char *version = "v1.0";
char *author = "palmacas 2023";
int dino_x = 10; // initial x position of the dinosaur
int dino_y = 62-23; // initial y position of the dinosaur
int jump_height = 20; // height of the dinosaur jump
int obstacle_x = 128; // initial x position of the obstacle
int obstacle_width = 12; // withd of the obstacle
int score = 0; // player's score
int game_speed = 1; // game initial speed
void setup() {
// Project data
display.begin();
display.firstPage();
do {
display.setFont(u8g2_font_t0_15_tr);
display.drawStr(64 - display.getStrWidth(project)/2, 15, project);
display.drawStr(64 - display.getStrWidth(version)/2, 45, version);
display.drawStr(64 - display.getStrWidth(author)/2, 60, author);
} while (display.nextPage());
// Startup sound
pinMode(BUZ, OUTPUT);
tone(BUZ, 1568, 100); // G6
delay(250);
tone(BUZ, 1047, 100); // C6
delay(250);
tone(BUZ, 1568, 100); // G6
delay(100);
noTone(BUZ);
delay(100);
// Splash screen
/*display.firstPage();
do {
display.drawXBM(0, 0, 128, 64, splash_screen);
} while (display.nextPage());*/
delay(1000);
pinMode(BTN, INPUT_PULLUP);
}
void loop() {
button_state = readButton();
// if button is pressed the dinosaur jumps
if (button_state == HIGH)
{
dino_y -= jump_height;
}
// updates obstacle position
obstacle_x -= game_speed;
// collision detection
if (dino_x + 21 >= obstacle_x && dino_x <= obstacle_x + obstacle_width && dino_y + 22 >= 62-26)
{
gameOver();
}
// updates score
if (obstacle_x + obstacle_width < 0)
{
score++;
obstacle_x = 128;
}
display.firstPage();
do {
display.setDrawColor(1);
display.setBitmapMode(1);
display.setFont(u8g2_font_t0_15_tr);
display.setCursor(0, 10);
display.print("Score: ");
display.print(score);
display.drawLine(0, 59, 128, 59); // draws the floor line
display.drawXBMP(dino_x, dino_y, 21, 22, bitmap_dinosaur);
display.drawXBMP(obstacle_x, 62-26, 12, 26, bitmap_cactus_1);
} while (display.nextPage());
//gameOver();
delay(1);
}
// display game over message
void gameOver() {
display.firstPage();
do {
display.setFont(u8g2_font_t0_15_tr);
display.drawStr(64 - display.getStrWidth("Game Over!")/2, 20, "Game Over!");
display.drawStr(64 - display.getStrWidth("Score: ")/2, 35, "Score: ");
display.setCursor(60, 50);
display.print(score);
} while (display.nextPage());
dino_y = 62-23;
obstacle_x = 128;
score = 0;
while (button_state == LOW)
{
button_state = readButton();
}
}
int readButton() {
int btn_state = 0;
if (digitalRead(BTN) == LOW) {
if (millis() - last_press > 100) {
btn_state = 1;
playTone();
}
last_press = millis();
}
delay(1);
return btn_state;
}
int playTone() {
tone(BUZ, 1047, 100); // C6
delay(100);
noTone(BUZ);
}