#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
String time = "00:00";
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Structure for raindrop
struct Raindrop {
int x;
int y;
int size;
int speed;
bool splash; // Flag to indicate if there's a splash
unsigned long splashTime; // Time when splash occurred
};
// Array to hold raindrops
Raindrop raindrops[20];
const int numRaindrops = sizeof(raindrops) / sizeof(raindrops[0]);
// Rectangle boundaries
const int rectX = 36;
const int rectY = 34;
const int rectWidth = 60;
const int rectHeight = 30;
void setup() {
Serial.begin(9600);
Serial.println("Initialized");
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.clearDisplay();
display.display(); // Clear the display
// Initialize raindrops
for (int i = 0; i < numRaindrops; i++) {
raindrops[i].x = random(0, SCREEN_WIDTH);
raindrops[i].y = random(-SCREEN_HEIGHT, 0); // Start above the screen
raindrops[i].size = random(1, 3); // Random size
raindrops[i].speed = random(4, 8); // Random speed
raindrops[i].splash = false; // No splash initially
raindrops[i].splashTime = 0; // No splash time initially
}
}
void loop() {
// Handle serial input
if (Serial.available() > 0) { // Check if there's data available
time = Serial.readStringUntil('\n'); // Read until a newline character
}
// Clear the display
display.clearDisplay();
// Update raindrop positions
for (int i = 0; i < numRaindrops; i++) {
raindrops[i].y += raindrops[i].speed; // Move down by speed
// Check if raindrop hits the rectangle
if (raindrops[i].y + raindrops[i].size * 8 >= rectY && // Adjust for size
raindrops[i].y <= rectY + rectHeight &&
raindrops[i].x >= rectX && raindrops[i].x <= rectX + rectWidth) {
raindrops[i].splash = true; // Activate splash
raindrops[i].splashTime = millis(); // Record the time of splash
raindrops[i].y = rectY + rectHeight; // Position at the bottom of rectangle
}
// Reset raindrop to the top if it moves off the bottom of the screen
if (raindrops[i].y > SCREEN_HEIGHT) {
raindrops[i].y = random(-SCREEN_HEIGHT, 0);
raindrops[i].x = random(0, SCREEN_WIDTH);
raindrops[i].size = random(1, 3);
raindrops[i].speed = random(4, 8);
raindrops[i].splash = false; // Reset splash
}
// Draw the raindrop
display.setCursor(raindrops[i].x, raindrops[i].y);
display.setTextSize(1);
display.setTextColor(WHITE);
for (int j = 0; j < raindrops[i].size; j++) {
display.println("|");
}
// Draw splash effect if applicable
if (raindrops[i].splash) {
display.setCursor(raindrops[i].x, rectY + rectHeight); // Position just below the rectangle
display.print("\_/"); // Splash effect
// Check duration of splash effect (e.g., for 200 ms)
if (millis() - raindrops[i].splashTime > 200) {
raindrops[i].splash = false; // Reset splash after duration
// Reset the raindrop to the top after splash
raindrops[i].y = random(-SCREEN_HEIGHT, 0);
raindrops[i].x = random(0, SCREEN_WIDTH);
raindrops[i].size = random(1, 3);
raindrops[i].speed = random(2, 5);
}
}
}
// Draw the rectangle
display.drawRect(rectX, rectY, rectWidth, rectHeight, BLACK);
// Display the time
display.setCursor(50, 40);
display.setTextSize(1);
display.print(time);
display.display(); // Update the display
// Short delay to prevent flickering
delay(50); // Reduced delay for smoother animation
}