// https://www.reddit.com/user/ferrybig
/* OLED SSD1306 <-> Arduino (nano/uno)
D0--------------10
D1--------------9
RST-------------13
DC--------------11
VCC-------------5V
GND-------------GND
CS--------------12
Others:
Button active low: 2
> Used for placing the blocks
Led active high: A5 (Optional)
> Used for death indication
Buzzer: 3 (Optional)
> Feedback for button press
*/
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for SSD1306 display connected using software SPI (default case):
#define OLED_MOSI 9
#define OLED_CLK 10
#define OLED_DC 11
#define OLED_CS 12
#define OLED_RESET 13
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
const int pin_button = 2;
const int pin_led = A5;
const int pin_buzzer = 3;
const int initial_delay_timer = 32;
const int initial_x = 32;
const int initial_width = 8;
const int height = 4;
const int initial_y = 128 - height;
const int speed = 2;
int valid_x = 0;
int x = initial_x;
int width = initial_width;
int y = initial_y;
bool direction_inverse = false;
bool has_released = false;
bool first_block = true;
int delayTimer = initial_delay_timer;
bool game_over = false;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(pin_button, INPUT_PULLUP);
pinMode(pin_led, OUTPUT);
pinMode(pin_buzzer, OUTPUT);
ADCSRA = 0; // We don't need analog read functionality in this project
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay();
//display.invertDisplay(true);
draw();
}
void restart() {
//digitalWrite(pin_reset, LOW); // Reset arduino
//pinMode(pin_reset, OUTPUT);
y = initial_y;
x = initial_x;
width = initial_width;
delayTimer = initial_delay_timer;
first_block = true;
display.clearDisplay();
//display.invertDisplay(true);
}
void gameOver() {
game_over = true;
digitalWrite(pin_led, HIGH);
// Wait till button is released
while(digitalRead(pin_button) == LOW);
while(true) {
fillRect(x, y, width, height, SSD1306_INVERSE);
display.display();
delay(100);
if(digitalRead(pin_button) == LOW) {
restart();
break;
}
}
digitalWrite(pin_led, LOW);
}
void fillRect(int x, int y, int width, int height, int color) {
// Perform screen rotation here
display.fillRect(128 - y - height, x, height, width, color);
}
void input() {
if (digitalRead(pin_button) == LOW) {
if(has_released) {
if(first_block) {
valid_x = x;
first_block = false;
} else {
const int old_width = width;
if(x + width < valid_x) {
// ##
// ##
gameOver();
} else if (x + width < valid_x + width) {
// ##
// ##
width = width - (valid_x - x);
} else if (x < valid_x + width) {
// ##
// ##
width = valid_x + width - x;
valid_x = x;
} else {
// ##
// ##
gameOver();
}
if(width == 0) {
// strange bug
width = old_width;
gameOver();
}
}
has_released = false;
if(!game_over) {
fillRect(valid_x, y, width, height, SSD1306_INVERSE);
if(y == 0) {
// win
}
y -= height;
delayTimer--;
} else {
game_over = false;
}
tone(pin_buzzer, 3000, 10);
}
} else {
has_released = true;
}
}
void update() {
if(direction_inverse) {
if(x == 0) {
direction_inverse = false;
} else {
x -= speed;
}
} else {
if(x == 64 - width) {
direction_inverse = true;
} else {
x += speed;
}
}
}
void draw() {
fillRect(x, y, width, height, SSD1306_INVERSE);
}
void clearDraw() {
fillRect(x, y, width, height, SSD1306_INVERSE);
}
void loop() {
// put your main code here, to run repeatedly:
clearDraw();
input();
update();
draw();
display.display();
if(delayTimer > 1) {
delay(delayTimer);
}
}