#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "bitmap.h" // Include the bitmap header file
#include "specialbitmap.h"
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Function to display the emoji on the OLED
void displayEmoji(const uint8_t *bitmap);
// Struct to hold animation details
struct Animation {
const uint8_t (*frames)[1024];
int frameCount;
union {
int *arrayDelays;
int singleDelay;
};
bool singleDelayFlag;
bool loop;
unsigned long loopDuration;
bool happy; // Flag to indicate if it's a happy animation
bool trigger;
unsigned long (*triggerFunction)();
// Constructor for arrayDelays
Animation(const uint8_t (*f)[1024], int fc, int* ad, bool sdFlag, bool l, unsigned long ld, bool h, bool t, unsigned long (*tf)())
: frames(f), frameCount(fc), arrayDelays(ad), singleDelayFlag(sdFlag), loop(l), loopDuration(ld), happy(h), trigger(t), triggerFunction(tf) {}
// Constructor for singleDelay
Animation(const uint8_t (*f)[1024], int fc, int sd, bool sdFlag, bool l, unsigned long ld, bool h, bool t, unsigned long (*tf)())
: frames(f), frameCount(fc), singleDelay(sd), singleDelayFlag(sdFlag), loop(l), loopDuration(ld), happy(h), trigger(t), triggerFunction(tf) {}
};
// Define animations
int blinkDelays[] = {100};
int moveDelays[] = {random(2000, 3000), 100};
int animation3Delays[] = {100, 100, 100};
int animation4Delays[] = {random(2000, 4000)};
int eyebrowDelays[] = {100};
int happyMoveDelays[] = {100, 100, 100};
int eacheyeDelays[] = {100,100,100,random(1000, 2500)};
Animation animations[] = {
{left_move_eye, sizeof(left_move_eye) / sizeof(left_move_eye[0]), moveDelays, false, false, 0, false, false, 0},
{right_move_eye, sizeof(right_move_eye) / sizeof(right_move_eye[0]), moveDelays, false, false, 0, false, false, 0},
{happytonormal_transition, sizeof(happytonormal_transition) / sizeof(happytonormal_transition[0]), animation3Delays, false, false, 0, false, false, 0},
{eye_brow_bitmap, sizeof(eye_brow_bitmap) / sizeof(eye_brow_bitmap[0]), eyebrowDelays, false, true, 2000, false, false, 0},
{shy_bitmapp, sizeof(shy_bitmapp) / sizeof(shy_bitmapp[0]), animation4Delays, false, false, 0, false, false, 0},
{blink_right_eye, sizeof(blink_right_eye) / sizeof(blink_right_eye[0]), eacheyeDelays, false, false, 0, false, false, 0},
{blink_left_eye, sizeof(blink_right_eye) / sizeof(blink_right_eye[0]), eacheyeDelays, false, false, 0, false, false, 0},
};
int birdDelays = 50; // Change birdDelays to a single int
Animation specialAnimations[] = {
{the_bird_bitmap, sizeof(the_bird_bitmap) / sizeof(the_bird_bitmap[0]), birdDelays, true, false, 0, false, false, 0},
};
// Separate happy animations for easy random selection
Animation happyAnimations[] = {
{happy_left_move, sizeof(happy_left_move) / sizeof(happy_left_move[0]), happyMoveDelays, false, false, 0, true, false, 0},
{happy_right_move, sizeof(happy_right_move) / sizeof(happy_right_move[0]), happyMoveDelays, false, false, 0, true, false, 0}
};
// Variables and functions declarations
const int buzzer = 33;
unsigned long lastInteractionTime;
bool eyesmove;
bool happy;
bool normal = true;
bool special = false;
unsigned long blinkInterval;
unsigned long lastBlinkTime;
unsigned long lastmovetime;
unsigned long moveinterval;
unsigned long lasthappytime;
unsigned long lastspecialtime;
unsigned long happyInterval;
unsigned long lastHappyMoveTime;
unsigned long happyMoveInterval;
unsigned long specialanimationInterval;
void playsound();
void playAnimation(const uint8_t frames[][1024], int frameCount, int delays[]);
void playAnimationLoop(const uint8_t frames[][1024], int frameCount, int delays[], unsigned long duration);
void setup() {
Serial.begin(115200);
pinMode(buzzer, OUTPUT);
// Initialize the OLED display with I2C address 0x3C (for the 128x64)
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
// Clear the buffer
display.clearDisplay();
displayEmoji(normal_bitmap); // Display normal emoji after blink animation
playsound();
// Set the last interaction time to the current time
lastInteractionTime = millis();
}
void loop() {
// Check for blink animation
if ((millis() - lastBlinkTime >= blinkInterval) && !eyesmove && !happy && !special) {
playsound();
playAnimation(blink_bitmap, sizeof(blink_bitmap) / sizeof(blink_bitmap[0]), blinkDelays);
lastBlinkTime = millis();
blinkInterval = random(2000, 6000);
displayEmoji(normal_bitmap); // Display normal emoji after blink animation
}
if ((millis() - lastspecialtime >= specialanimationInterval) && !eyesmove && !happy && !special) {
special = true;
playsound();
int chooseAnim = random(0, sizeof(specialAnimations) / sizeof(specialAnimations[0])); // Choose a random special animation
Animation anim = specialAnimations[chooseAnim];
if (anim.loop) {
playAnimationLoop(anim.frames, anim.frameCount, anim.arrayDelays, anim.loopDuration);
} else if (anim.singleDelayFlag) {
playSpecialAnimation(anim.frames, anim.frameCount, anim.singleDelay); // Use singleDelay here
} else {
playSpecialAnimation(anim.frames, anim.frameCount, *anim.arrayDelays); // Use arrayDelays here
}
lastspecialtime = millis();
specialanimationInterval = random(10000, 20000);
special = false;
displayEmoji(normal_bitmap); // Display normal emoji after special animation
}
// Check for eye movement animation
if ((millis() - lastmovetime >= moveinterval) && !happy && !special) {
eyesmove = true;
playsound();
int chooseAnim = random(0, sizeof(animations) / sizeof(animations[0])); // Choose a random animation
Animation anim = animations[chooseAnim];
if (anim.happy) {
// Skip happy animations in this section
do {
chooseAnim = random(0, sizeof(animations) / sizeof(animations[0]));
anim = animations[chooseAnim];
} while (anim.happy);
}
if (anim.loop) {
playAnimationLoop(anim.frames, anim.frameCount, anim.arrayDelays, anim.loopDuration);
} else {
playAnimation(anim.frames, anim.frameCount, anim.arrayDelays);
}
lastmovetime = millis();
moveinterval = random(4000, 8000);
displayEmoji(normal_bitmap); // Display normal emoji after animation
eyesmove = false;
}
// Check for happy state activation
if ((millis() - lasthappytime >= happyInterval) && !happy && normal && !special) {
if (random(0, 3) == 0) { // 50% chance to enter happy state
happy = true;
normal = false; // Set normal to false when in happy state
int happyDelays[] = {10}; // Delays for happy transition animation
playAnimation(happy_transition, sizeof(happy_transition) / sizeof(happy_transition[0]), happyDelays);
lasthappytime = millis();
happyInterval = random(10000, 20000);
displayEmoji(happy_bitmap); // Display happy emoji
} else {
lasthappytime = millis(); // Reset happy interval without changing state
happyInterval = random(10000, 20000);
}
}
// Check for happy eye movement animation within happy state
if (happy && !eyesmove && !special && (millis() - lastHappyMoveTime >= happyMoveInterval)) {
int chooseAnim = random(0, sizeof(happyAnimations) / sizeof(happyAnimations[0])); // Choose a random happy animation
Animation anim = happyAnimations[chooseAnim];
playAnimation(anim.frames, anim.frameCount, anim.arrayDelays);
lastHappyMoveTime = millis();
happyMoveInterval = random(2000, 5000); // Reset happy move interval
displayEmoji(happy_bitmap); // Display happy emoji again after eye movement
}
// Return to normal state after the happy state duration
if (happy && !special && (millis() - lasthappytime >= 30000)) {
displayEmoji(normal_bitmap);
happy = false;
normal = true; // Set normal to true after returning from happy state
}
// Delay for a short time to avoid rapid triggering
delay(100);
}
void displayEmoji(const uint8_t *bitmap) {
display.clearDisplay();
display.drawBitmap(0, 0, bitmap, SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE);
display.display();
}
void playsound() {
for (int i = 1400; i < 1800; i += 20) {
tone(buzzer, i); // Play tone at current frequency
delay(10); // Hold the tone for 10 milliseconds
noTone(buzzer); // Turn off the tone
}
}
void playAnimation(const uint8_t frames[][1024], int frameCount, int delays[]) {
for (int i = 0; i < frameCount; i++) {
display.clearDisplay();
display.drawBitmap(0, 0, frames[i], SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE);
display.display();
if (i < frameCount - 1) { // Avoid array out-of-bounds for the last delay
delay(delays[i]);
}
}
}
void playSpecialAnimation(const uint8_t frames[][1024], int frameCount, int delayValue) {
for (int i = 0; i < frameCount; i++) {
display.clearDisplay();
display.drawBitmap(0, 0, frames[i], SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE);
display.display();
if (i < frameCount - 1) { // Avoid array out-of-bounds for the last delay
delay(delayValue);
}
}
}
void playAnimationLoop(const uint8_t frames[][1024], int frameCount, int delays[], unsigned long duration) {
unsigned long startTime = millis();
while (millis() - startTime < duration) {
playAnimation(frames, frameCount, delays);
}
}