Bunny Tamagotchi With Arduino

by Ribbon_bee in Circuits > Arduino

415 Views, 1 Favorites, 0 Comments

Bunny Tamagotchi With Arduino

image.jpg
image.jpg

( I can’t get some of the images to upload right, so some of them will be upside down. If I uploaded them correctly Instructables would flip them upside down, and if I flipped them myself before uploading it would still be upside down somehow )


For school I had to make something with the Arduino, so I decided to make a little portable pet similar to a Tamagotchi

Here are two video's to showcase the final product:

After a short while ( if it’s not wet ) the Bunny will fall alseep. In this state it won’t lose any hunger or happiness. You can wake it up by holding the Middle Button.

Left button is feeding, Right button is petting.

When the Bunny is awake, the Middle Button will make it Wet. The Bunny doesn’t like being wet, so the happiness and hunger bar will go down faster. Its movement speed will also be reduced. You also won’t be able to feed or pet it, and it won’t fall asleep either.

To dry the Bunny off, you simply press the Middle Button again. The bunny will be grateful and it will gain a bit of happiness. This will make the Bunny go back to its default/dry state, and you’ll be able to feed and pet it again.


Materials needed:

- Arduino Uno

- Piezo Buzzer

- 3x 10 Ohm resistors

- Wires

- 3 buttons

- OLED i2c Display

Testing Materials

F08EECE1-90AA-4EE6-B408-B977ADC42D6D.jpeg
B4464540-2F2C-43EE-9651-B73171B4A8FE.jpeg
08C67063-EF47-4C5A-B3DC-B36840C0664B.jpeg

Before I did any programming I started off with testing the screen and the buzzer.

For the screen I used this tutorial, where I got most of the bits for my own code as well.

https://randomnerdtutorials.com/guide-for-oled-dis...

for the buzzer I used this tutorial.

https://www.instructables.com/How-to-use-a-Buzzer-...

Wiring

Knipsel.PNG
2F813C8E-902C-4DD6-9A5B-2F4E2F395D44.jpeg
CDCFD1F4-6F78-4F3C-8DF0-ACE42D62D817.jpeg
E78ABB6D-B249-4B52-841C-AB45AE39CEA7.jpeg
044B7CA5-AFA6-44BF-B326-607C1CEAF56F.jpeg

I wired it roughly the same way as the simulation, with some minor placement differences. Since the simulation doesn't have the display, I marked it with colored dots.

Adding Code

With some help from the tutorial, I could finally get started on the code.

// Lisa Xu - 1D - GART - 2020/2021 
// ITTT Bunny tamagotchi with Arduino

#include
#include
#include

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define SPEAKER 6
#define POT A0

int HUNGER = 29; // fullness hunger bar ( 0 t/m 38 )
int HAPPINESS = 20; // fullness happiness bar ( 0 t/m 38 )

int BUNNY_X = 32; // x location of bunny ( 0 t/m 103 to stay on-screen )
int BUNNY_Y = 30; // 16 t/m 30 ( to stay in the blue zone without cutting parts off )

int frame_counter = 0;
long ani_timer = 0;
int ani_duration = 0;

bool AWAKE = true;
int sleepiness = 0;

bool EATING = false;
bool BEING_PET = false;
bool WET = false;

bool facing_left = true;

const int buttonR = 4; //Rechts knopje
const int buttonC = 3; //Center / Middenknopje
const int buttonL = 2; //Links knopje

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

static const unsigned char PROGMEM image_data_BUNNY[] = { // bunny neutral state
0x60, 0xc0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x31, 0x80, 0x03, 0x00,
0x7f, 0xff, 0x07, 0x80,
0xff, 0xff, 0xf7, 0x80,
0xff, 0xff, 0xfb, 0x00,
0xff, 0xff, 0xfc, 0x00,
0xff, 0xff, 0xfc, 0x00,
0xff, 0xff, 0xfc, 0x00,
0xdd, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0x7f, 0xff, 0xfc, 0x00
};
static const unsigned char PROGMEM image_data_BUNNY_FLIPPED[] = { // bunny neutral state mirrored
0x00, 0x01, 0x83, 0x00,
0x00, 0x03, 0xc7, 0x80,
0x00, 0x03, 0xc7, 0x80,
0x00, 0x03, 0xc7, 0x80,
0x00, 0x03, 0xc7, 0x80,
0x00, 0x03, 0xc7, 0x80,
0x00, 0x01, 0xc7, 0x00,
0x00, 0x01, 0xc7, 0x00,
0x00, 0x01, 0xc7, 0x00,
0x60, 0x00, 0xc6, 0x00,
0xf0, 0x7f, 0xff, 0x00,
0xf7, 0xff, 0xff, 0x80,
0x6f, 0xff, 0xff, 0x80,
0x1f, 0xff, 0xff, 0x80,
0x1f, 0xff, 0xff, 0x80,
0x1f, 0xff, 0xff, 0x80,
0x3f, 0xff, 0xdd, 0x80,
0x3f, 0xff, 0xff, 0x80,
0x3f, 0xff, 0xff, 0x80,
0x3f, 0xff, 0xff, 0x80,
0x1f, 0xff, 0xff, 0x00
};

static const unsigned char PROGMEM image_data_BUNNY_BITE[] = { // bunny eatin sprite
0x60, 0xc0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x3f, 0xe0, 0x03, 0x00,
0x7f, 0xff, 0x07, 0x80,
0xff, 0xff, 0xf7, 0x80,
0xff, 0xff, 0xfb, 0x00,
0xff, 0xff, 0xfc, 0x00,
0xbd, 0xff, 0xfc, 0x00,
0xff, 0xff, 0xfc, 0x00,
0x83, 0xff, 0xfe, 0x00,
0x83, 0xff, 0xfe, 0x00,
0x83, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0x7f, 0xff, 0xfc, 0x00
};
static const unsigned char PROGMEM image_data_BUNNY_HAPPY[] = {
0x60, 0xc0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe2, 0x80, 0x00,
0x71, 0xc3, 0x80, 0x00,
0x71, 0xc1, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x31, 0x80, 0x03, 0x00,
0x7f, 0xff, 0x07, 0x80,
0xff, 0xff, 0xf7, 0x80,
0xff, 0xff, 0xfb, 0x00,
0xff, 0xff, 0xfc, 0x00,
0xff, 0xff, 0xfc, 0x00,
0xbe, 0xff, 0xfc, 0x00,
0x5d, 0x7f, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0x7f, 0xff, 0xfc, 0x00
};
static const unsigned char PROGMEM image_data_BUNNY_HAPPY2[] = {
0x60, 0xc0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x50, 0x00,
0xf1, 0xe0, 0x70, 0x00,
0xf1, 0xe0, 0x20, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x3f, 0xf0, 0x03, 0x00,
0x7f, 0xff, 0x07, 0x80,
0xff, 0xff, 0xf7, 0x80,
0xff, 0xff, 0xfb, 0x00,
0xff, 0xff, 0xfc, 0x00,
0xbe, 0xff, 0xfc, 0x00,
0x5d, 0x7f, 0xfc, 0x00,
0xff, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0x7f, 0xff, 0xfe, 0x00,
0x3f, 0xff, 0xfc, 0x00
};
static const unsigned char PROGMEM image_data_BUNNY_REFUSE[] = {
0x60, 0xc0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x31, 0x80, 0x03, 0x00,
0x7f, 0xff, 0x07, 0x80,
0xff, 0xff, 0xf7, 0x80,
0xff, 0xff, 0xfb, 0x00,
0xff, 0xff, 0xfc, 0x00,
0xff, 0xff, 0xfc, 0x00,
0xbe, 0xff, 0xfc, 0x00,
0xdd, 0xff, 0xfe, 0x00,
0xbe, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0x7f, 0xff, 0xfc, 0x00
};
static const unsigned char PROGMEM image_data_BUNNY_WET[] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xf3, 0xe0, 0x00, 0x00,
0xf3, 0xe0, 0x00, 0x00,
0xf3, 0xe0, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x31, 0x80, 0x00, 0x00,
0x7f, 0xff, 0x03, 0x00,
0xff, 0xff, 0xf7, 0x80,
0xf5, 0xff, 0xfb, 0x80,
0xfb, 0xfa, 0xfd, 0x00,
0xff, 0xfd, 0xfc, 0x00,
0xff, 0xff, 0xfc, 0x00,
0x9c, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xae, 0x00,
0xff, 0xd7, 0xde, 0x00,
0xff, 0xef, 0xfe, 0x00,
0x7f, 0xff, 0xfc, 0x00
};
static const unsigned char PROGMEM image_data_BUNNY_WET_FLIPPED[] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0xc7, 0x80,
0x00, 0x03, 0xe7, 0x80,
0x00, 0x03, 0xe7, 0x80,
0x00, 0x03, 0xe7, 0x80,
0x00, 0x03, 0xc7, 0x80,
0x00, 0x01, 0xc7, 0x00,
0x00, 0x00, 0xc6, 0x00,
0x60, 0x7f, 0xff, 0x00,
0xf7, 0xff, 0xff, 0x80,
0xef, 0xff, 0xd7, 0x80,
0x5f, 0xaf, 0xef, 0x80,
0x1f, 0xdf, 0xff, 0x80,
0x1f, 0xff, 0xff, 0x80,
0x3f, 0xff, 0x9c, 0x80,
0x3a, 0xff, 0xff, 0x80,
0x3d, 0xf5, 0xff, 0x80,
0x3f, 0xfb, 0xff, 0x80,
0x1f, 0xff, 0xff, 0x00
};
static const unsigned char PROGMEM image_data_BUNNY_BLINK[] = { // eyes closed without 'z'
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xfb, 0xf0, 0x00, 0x00,
0xfb, 0xf0, 0x00, 0x00,
0xfb, 0xe0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x31, 0x80, 0x03, 0x00,
0x7f, 0xff, 0x07, 0x80,
0xff, 0xff, 0xf7, 0x80,
0xff, 0xff, 0xfb, 0x00,
0xff, 0xff, 0xfc, 0x00,
0xff, 0xff, 0xfc, 0x00,
0xff, 0xff, 0xfc, 0x00,
0x9c, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0x7f, 0xff, 0xfc, 0x00
};
static const unsigned char PROGMEM image_data_BUNNY_SLEEP[] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0xf1, 0xe1, 0xe0, 0x00,
0xfb, 0xf0, 0x40, 0x00,
0xfb, 0xf0, 0x80, 0x00,
0xfb, 0xe1, 0xe0, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x31, 0x80, 0x03, 0x00,
0x7f, 0xff, 0x07, 0x80,
0xff, 0xff, 0xf7, 0x80,
0xff, 0xff, 0xfb, 0x00,
0xff, 0xff, 0xfc, 0x00,
0xff, 0xff, 0xfc, 0x00,
0xff, 0xff, 0xfc, 0x00,
0x9c, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0x7f, 0xff, 0xfc, 0x00
};
static const unsigned char PROGMEM image_data_BUNNY_SLEEP2[] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0xf1, 0xe0, 0x00, 0x00,
0xfb, 0xf1, 0xe0, 0x00,
0xfb, 0xf0, 0x40, 0x00,
0xfb, 0xe0, 0x80, 0x00,
0x71, 0xc1, 0xe0, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00,
0x31, 0x80, 0x03, 0x00,
0x7f, 0xff, 0x07, 0x80,
0xff, 0xff, 0xf7, 0x80,
0xff, 0xff, 0xfb, 0x00,
0xff, 0xff, 0xfc, 0x00,
0xff, 0xff, 0xfc, 0x00,
0xff, 0xff, 0xfc, 0x00,
0x9c, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0xff, 0xff, 0xfe, 0x00,
0x7f, 0xff, 0xfc, 0x00
};
static const unsigned char PROGMEM image_data_BUNNY_BLOW[] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0xe0, 0x80, 0x00,
0x07, 0x06, 0x00, 0x00,
0x0f, 0x9f, 0x9a, 0x00,
0x1f, 0xbf, 0x00, 0x00,
0x3f, 0x7e, 0x00, 0x00,
0x3e, 0x7f, 0x00, 0x00,
0x38, 0xf0, 0x00, 0x00,
0x70, 0xc3, 0xd0, 0x00,
0x30, 0xc0, 0x01, 0x80,
0x7f, 0xff, 0x0b, 0xc0,
0xf9, 0xff, 0xf3, 0xc0,
0xfd, 0xfe, 0x79, 0x80,
0xfb, 0xff, 0x7c, 0x00,
0xff, 0xfe, 0xfc, 0x00,
0xbe, 0xff, 0xfc, 0x80,
0xdd, 0xff, 0xe6, 0x00,
0xbe, 0xf3, 0xf6, 0x00,
0xff, 0xfb, 0xee, 0x00,
0xff, 0xf7, 0xfe, 0x00,
0x7f, 0xff, 0xfc, 0x00
};
static const unsigned char PROGMEM image_data_BUNNY_BLOW2[] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x38, 0x5c, 0x00,
0x00, 0x00, 0x00, 0x00,
0xc0, 0x00, 0x00, 0x00,
0x01, 0xe0, 0x00, 0x00,
0x07, 0xe3, 0xc7, 0x40,
0x0f, 0xdf, 0xe0, 0x00,
0x0f, 0x7f, 0xc0, 0x00,
0x1c, 0xff, 0x00, 0x00,
0x18, 0xe0, 0x80, 0x00,
0x7f, 0xff, 0x01, 0x80,
0xfb, 0xff, 0xf3, 0xc0,
0xfd, 0xfe, 0xfb, 0xc0,
0xf9, 0xff, 0x7d, 0x80,
0xff, 0xfe, 0x7c, 0x00,
0xbe, 0xff, 0xfd, 0x00,
0xdd, 0xff, 0xee, 0x00,
0xbe, 0xf7, 0xf6, 0x00,
0xff, 0xfb, 0xe7, 0x80,
0xff, 0xf3, 0xfe, 0x00,
0x7f, 0xff, 0xfc, 0x00
};

static const unsigned char PROGMEM image_data_FOODS[] = { // CARROT
0x38, 0x00,
0x38, 0x00,
0xd0, 0x00,
0xef, 0x00,
0xdf, 0x80,
0x1f, 0xc0,
0x1d, 0xc0,
0x0b, 0xe0,
0x06, 0xe0,
0x01, 0xe0
};
static const unsigned char PROGMEM image_data_HEART[] = { // pet icon
0x77, 0x00,
0xff, 0x80,
0xff, 0x80,
0xff, 0x80,
0xff, 0x80,
0x7f, 0x00,
0x3e, 0x00,
0x1c, 0x00,
0x08, 0x00
};

void setup() {

Serial.begin(115200);

if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
pinMode (buttonR, INPUT);
pinMode (buttonC, INPUT);
pinMode (buttonL, INPUT);
pinMode (SPEAKER, OUTPUT);

sleepiness = 38;
}

void OVERLAY() {
display.drawLine(0, 51, 128, 51, WHITE); // grondlijn y = 51
display.drawBitmap(1, 1, image_data_FOODS, 11, 10, 1); // FOOD ICON
display.drawRoundRect(17, 0, 42, 13, 4, WHITE); //buitenkant bar 1 honger bar
display.fillRoundRect(19, 2, HUNGER, 9, 2, WHITE); //binnenkant bar 1
display.drawBitmap(66, 2, image_data_HEART, 9, 9, 1); // PET ICON AKA HEART
display.drawRoundRect(80, 0, 42, 13, 4, WHITE); // buitenkant bar 2 blijheid bar
display.fillRoundRect(80, 2, HAPPINESS, 9, 2, WHITE); //binnenkant bar 2
// display.fillRoundRect(82, 32, sleepiness, 9, 2, WHITE); // sleepiness
}

void HUNGER_BALANCE() { // zodat de bar niet in het negatieve of overloopt
if (HUNGER >= 38) {
HUNGER = 38;
}
if (HUNGER <= 0) {
HUNGER = 0;
}
}

void HAPPINESS_BALANCE() { //zelfde als hunger balance maar dan voor happiness
if (HAPPINESS >= 38) {
HAPPINESS = 38;
}
if (HAPPINESS <= 0) {
HAPPINESS = 0;
}
}

void HUNGER_DRAIN() {
static uint32_t previousTime = 0;
uint32_t currentTime = millis();

if ( currentTime - previousTime >= 10 * 1000UL ) { // hunger drain
previousTime = currentTime;
HUNGER = HUNGER - 1;
}
}

void HAPPINESS_DRAIN() {
static uint32_t previousTime = 0;
uint32_t currentTime = millis();

if (HUNGER <= 0 && (currentTime - previousTime >= 3 * 1000UL)) { // no hunger
previousTime = currentTime;
HAPPINESS = HAPPINESS - 1;
}
if (WET == true && (currentTime - previousTime >= 4 * 1000UL)) {
previousTime = currentTime;
HAPPINESS = HAPPINESS - 1;
}
}

void check_position() { // bunny will 'turn around' at x=32 and x=60 so it doesnt walk off-screen ( it does sometimes tho :/ )
if (BUNNY_X <= 32) {
facing_left = false;
}
if (BUNNY_X >= 60) {
facing_left = true;
}
}

void idle() { // standard idle -> dry
static uint32_t previousTime = 0;
uint32_t currentTime = millis();

if (currentTime - previousTime >= 1000UL ) {
previousTime = currentTime;
if (facing_left == false) {
BUNNY_X = BUNNY_X + 2;
}
if (facing_left == true) {
BUNNY_X = BUNNY_X - 2;
}
sleepiness = sleepiness + 1; // every 'step' adds to the sleepiness counter/timer
}
display.clearDisplay();
OVERLAY();
if (facing_left == true) {
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY, 25, 21, 1); // faces left
}
else {
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_FLIPPED, 25, 21, 1); // faces right
}
display.display();

}

void wet_idle() {
static uint32_t previousTime = 0;
uint32_t currentTime = millis();

if (currentTime - previousTime >= 1750UL ) {
previousTime = currentTime;
if (facing_left == false && (WET == true)) {
BUNNY_X = BUNNY_X + 1;
}
if (facing_left == true && (WET == true)) {
BUNNY_X = BUNNY_X - 1;
} // no added sleepiness so can't fall asleep when wet
}
display.clearDisplay();
OVERLAY();
if (facing_left == true) {
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_WET, 25, 21, 1);
}
else {
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_WET_FLIPPED, 25, 21, 1);
}
display.display();
}
void refuse() {
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X + 3, BUNNY_Y, image_data_BUNNY_REFUSE, 25, 21, 1);
display.display();
delay(90);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X - 3, BUNNY_Y, image_data_BUNNY_REFUSE, 25, 21, 1);
display.display();
delay(90);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X + 3, BUNNY_Y, image_data_BUNNY_REFUSE, 25, 21, 1);
display.display();
delay(90);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_REFUSE, 25, 21, 1);
display.display();
delay(700);
BUNNY_X = BUNNY_X - 3;
}
void wet_refuse() {
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X + 3, BUNNY_Y, image_data_BUNNY_WET, 25, 21, 1);
display.display();
delay(90);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X - 3, BUNNY_Y, image_data_BUNNY_WET, 25, 21, 1);
display.display();
delay(90);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X + 3, BUNNY_Y, image_data_BUNNY_WET, 25, 21, 1);
display.display();
delay(90);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_WET, 25, 21, 1);
display.display();
delay(700);
BUNNY_X = BUNNY_X - 3;
};

void is_blow() {
if (WET == true && (digitalRead(buttonC) == HIGH)) {
tone(SPEAKER, 110 );
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_BLOW, 25, 21, 1);
display.display();
delay(90);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_BLOW2, 25, 21, 1);
display.display();
delay(90);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_BLOW, 25, 21, 1);
display.display();
delay(90);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_BLOW2, 25, 21, 1);
display.display();
delay(90);
noTone(SPEAKER); // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY, 25, 21, 1);
display.display();
delay(200);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_BLINK, 25, 21, 1);
display.display();
delay(200);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY, 25, 21, 1);
display.display();
delay(400);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_HAPPY, 25, 21, 1);
display.display();
delay(700);
chirp();
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_HAPPY2, 25, 21, 1);
display.display();
chirp();
delay(600);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_HAPPY, 25, 21, 1);
display.display();
delay(600);
WET = false;
HAPPINESS = HAPPINESS + 4;
}
}

void varyFrequency() {
// use potentiometer to produce one tone per value of pot
// good for getting pitch value to use in making sound routines
int reading;
const uint8_t scale = 1; // 1 for high frequencies, scale up to 15 for lowest freqs

reading = scale * analogRead(POT);
playTone(reading, 1000);
#ifdef SERIAL
Serial.print("Freq = ");
Serial.println(reading);
#endif
}

void playTone(uint16_t tone1, uint16_t duration) {
if (tone1 < 50 || tone1 > 15000) return; // these do not play on a piezo
for (long i = 0; i < duration * 1000L; i += tone1 * 2) {
digitalWrite(SPEAKER, HIGH);
delayMicroseconds(tone1);
digitalWrite(SPEAKER, LOW);
delayMicroseconds(tone1);
}
}

void chirp() { // Bird chirp
for (uint8_t i = 200; i > 180; i--)
playTone(i, 9);
}
void ruff() { // dog ruff
uint16_t i;
for (i = 890; i < 910; i += 2) // "rrr" (vary down)
playTone(i, 3);
playTone(1664, 150); // "uuu" (hard to do)
playTone(12200, 70); // "ff" (long, hard to do)
}
void arf() { // dog arf
uint16_t i;
playTone(890, 25); // "a" (short)
for (i = 890; i < 910; i += 2) // "rrr" (vary down)
playTone(i, 5);
playTone(4545, 80); // intermediate
playTone(12200, 70); // "ff" (shorter, hard to do)
}

void being_pet() {
if ( BEING_PET == true && (WET == false)) {
if (HAPPINESS >= 38) {
display.clearDisplay();
OVERLAY();
refuse();
HAPPINESS = 38;
BEING_PET = false;
}
else {
ani_duration = 600;
while (frame_counter < 4) {
if (frame_counter == 0) { // frame 1 onmiddelijk
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_HAPPY, 25, 21, 1);
display.display();
frame_counter = frame_counter + 1;
}
if (millis() - ani_timer >= ani_duration) { // na 600 milli volgende frame
frame_counter = frame_counter + 1;
ani_timer = millis();
if (frame_counter == 2) {
chirp();
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_HAPPY2, 25, 21, 1);
display.display();

}
if (frame_counter == 3) {
chirp();
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_HAPPY, 25, 21, 1);
display.display();
delay(300);
}
}
}
BEING_PET = false;
HAPPINESS = HAPPINESS + 6;
}
}
if (BEING_PET == true && (WET == true)) {
arf();
wet_refuse();
HAPPINESS = HAPPINESS - 2;
BEING_PET = false;
}
}
void eating() {
if (EATING == true && (WET == false)) {
display.clearDisplay();
tone(SPEAKER, 500);
OVERLAY();
display.drawBitmap(BUNNY_X - 15, 21, image_data_FOODS, 11, 10, 1); // food mid-air
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY, 25, 21, 1); //bunny waiting
display.display();
noTone(SPEAKER);
delay(500);
display.clearDisplay();
tone(SPEAKER, 500);
OVERLAY();
display.drawBitmap(BUNNY_X - 15, 31, image_data_FOODS, 11, 10, 1); //food almost hitting ground
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY, 25, 21, 1); //bunny waiting
display.display();
noTone(SPEAKER);
delay(500);
display.clearDisplay();
tone(SPEAKER, 500);
OVERLAY();
display.drawBitmap(BUNNY_X - 15, 41, image_data_FOODS, 11, 10, 1); // food hits ground
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY, 25, 21, 1); //bunny sees food
display.display();
noTone(SPEAKER);
delay(500);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X - 15, 41, image_data_FOODS, 11, 10, 1);
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_BITE, 25, 21, 1); // food decreases and bunny is chewing
display.display();
delay(500);
display.clearDisplay();
OVERLAY();
tone(SPEAKER, 100);
display.drawBitmap(BUNNY_X - 11, 41, image_data_FOODS, 7, 10, 1);
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY, 25, 21, 1);
display.display();
noTone(SPEAKER);
delay(500);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X - 11, 41, image_data_FOODS, 7, 10, 1);
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_BITE, 25, 21, 1);
display.display();
delay(500);
display.clearDisplay();
OVERLAY();
tone(SPEAKER, 70);
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY, 25, 21, 1);
display.display();
noTone(SPEAKER);
delay(500);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_BITE, 25, 21, 1);
display.display();
delay(500);
display.clearDisplay();
OVERLAY();
tone(SPEAKER, 50);
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY, 25, 21, 1);
display.display();
noTone(SPEAKER);
delay(500);
display.clearDisplay();
OVERLAY();
if ( HUNGER > 29) {
display.clearDisplay();
OVERLAY();
arf();
refuse();
EATING = false;
HUNGER = HUNGER + 10;
HAPPINESS = HAPPINESS - 3;
}
else {
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY, 25, 21, 1);
display.display();
delay(1000);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_HAPPY, 25, 21, 1);
display.display();
delay(700);
chirp();
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_HAPPY2, 25, 21, 1);
display.display();
chirp();
delay(600);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_HAPPY, 25, 21, 1);
display.display();
delay(600);
EATING = false;
HUNGER = HUNGER + 10;
HAPPINESS = HAPPINESS + 2;
}
}
if (EATING == true && (WET == true)) {
arf();
wet_refuse();
HAPPINESS = HAPPINESS - 2;
EATING = false;
}
}

void sleep_check() { // when 38 seconds pass it'll fall asleep, since it takes 1 step per second in the standard idle
if (sleepiness >= 38 ) {
AWAKE = false;
while (AWAKE == false) { // it'll stay in the loop until awake = true
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_SLEEP, 25, 21, 1);
display.display();
delay(1000);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_SLEEP2, 25, 21, 1);
display.display();
delay(1000);

if (digitalRead(buttonC) == HIGH) { // you have to hold the C button since it still has to go through the entire while loop before reaching the if statement
AWAKE = true;
}
}
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_BLINK, 25, 21, 1);
display.display();
delay(500);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY, 25, 21, 1);
display.display();
delay(100);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_BLINK, 25, 21, 1);
display.display();
delay(100);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY, 25, 21, 1);
display.display();
delay(1200);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_HAPPY, 25, 21, 1);
display.display();
delay(700);
chirp();
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_HAPPY2, 25, 21, 1);
display.display();
chirp();
delay(600);
display.clearDisplay();
OVERLAY();
display.drawBitmap(BUNNY_X, BUNNY_Y, image_data_BUNNY_HAPPY, 25, 21, 1);
display.display();
delay(600);
sleepiness = 0;
}
}


void loop() {

display.clearDisplay(); // clear buffer
if (digitalRead(buttonC) == HIGH && (WET == false) && ( AWAKE == true)) {
ani_timer = millis();
frame_counter = 0; // middelknopje maakt nat
ruff();
wet_refuse();
WET = true;
}

if (digitalRead(buttonL) == HIGH && (digitalRead(buttonR)) == LOW) { // linkerknopje geeft voedsel
EATING = true;
}

if (digitalRead(buttonR) == HIGH && (digitalRead(buttonL)) == LOW) { // rechterknopje aait
ani_timer = millis();
frame_counter = 0;
BEING_PET = true;
}

if (digitalRead(buttonR) == HIGH && (digitalRead(buttonL)) == HIGH) { // R + L reset bunny
BUNNY_X = 36;
HUNGER = 28;
HAPPINESS = 28;
WET = false;
AWAKE = true;
sleepiness = 0;
}

sleep_check();
OVERLAY();
eating();
is_blow();
being_pet();
HUNGER_DRAIN();
HUNGER_BALANCE();
HAPPINESS_DRAIN();
HAPPINESS_BALANCE();
check_position();
if (WET == true) {
wet_idle();
}
else {
idle();
}
}

There were some more things I wanted to add/refine but I couldn't since I ran out of time.

For some of the noises I used this library:

https://learn.adafruit.com/adafruit-trinket-modded...

The tutorial I linked before used this to convert images into code, and I used it for the carrot, heart, and all of the bunny sprites.

https://sourceforge.net/projects/lcd-image-convert...

Soldering

E3255E74-CD41-482D-829F-CA8C6ACF29F7.jpeg

I soldered it at school with the help of a classmate. I soldered the display and buzzer directly to the wires without a board, so I can freely put them wherever I want.

Making the Housing

8B296F3C-F1AD-41A9-9465-63671925048C.jpeg
A1330C05-6D32-4D30-8FF4-2F2B0BBE23DE.jpeg
9301BE9A-288A-4751-AEDF-23D43E5841B9.jpeg
A47235E5-C266-44AE-92B0-18288EEDC754.jpeg
8E28D10B-4A83-4B75-9E7E-71B0D2D1515C.jpeg
84A08649-C15F-400F-88E9-DFABBE2AA37A.jpeg

I made the Housing of cardboard, and in the shape of an arcade machine. The three buttons are at the front, the display directly above it and the buzzer inside the box. I didn’t completely plan this through so both left and right have pins sticking out. I covered it with cardboard so the user can’t hurt themselves with it.