/* ==================================== Virtua Pet R1 ================================ Hi. This is a tiny little project I made to get my own Virtual Pet. I hope you like it as much as I do. The code can receive some optimiztion, so feel free to change it as you like. All the bitmap images are on the bitmap.h file. I would be glade to see your project too if you choose to make one pet by yourself. Thank you! HARDWARE: - STM32 F103C8T6 (Blue Pill); (It demands at least 3.5KB RAM and 32KB ROM) - 1.3" OLED I2C Screen 128x64; - 4 push buttons (with 1n4148 diode to prevent debounce); NOTE: Disable the USB serial communication for more ROM space by Gus Costa (GitHub: gusocosta) (Reddit: gu-ocosta) ====================================================================================== */ #include #include "bitmaps.h" //Choose your screen protocol //GyverOLED oled; GyverOLED oled; //Peripheral constants const uint8_t bt_down = PA9; const uint8_t bt_right = PA10; const uint8_t bt_up = PA11; const uint8_t bt_left = PA12; //Time vars and const bool timer_rolling = false; const uint8_t check_pet_time = 5; //in sec uint32_t draw_tick = 0; uint8_t draw_tick_max = 100; uint16_t act_time[4] = {0,0,0,0}; uint32_t current_millis = 0; uint32_t previous_millis = 0; uint32_t ani_tick = 0; uint32_t ani_tick_previous = 0; uint32_t ani_tick_previous_millis = 0; uint32_t screen_tick = 0; uint32_t screen_tick_previous = 0; uint32_t buttom_cooldown_millis = 0; uint8_t buttom_cooldown = 200; uint32_t doing_tick = 0; uint32_t doing_cooldown = 2000; uint32_t sleeping_time = 0; bool ani_icon_playing = false; //Pet vars and const uint8_t pet_species = 0; byte pet_sex = 0; uint8_t pet_lvl = 0; const uint8_t species_amount = 5; String pet_all_species[species_amount] = {"Egg", "Slime", "Bunny", "Dino", "T-Rex"}; uint8_t pet_size[species_amount] = {24, 24, 32, 64, 64}; int pet_eating_vars[species_amount][5][5] ={ //[species][food][status change] //food> 0: eating tomato, 1: eating carrot, 2: eating mushroom, 3: eating chicken, 4: eating candy //status> 0: health, 1: hungry, 2: chean, 3: happy, 4: sleep {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, //egg {{2,10,0,-5,0},{2,10,0,-5,0},{2,15,0,0,0},{2,15,0,10,0},{-10,25,0,20,0}}, //slime {{2,10,0,5,0},{2,25,0,15,0},{2,15,0,0,0},{-10,5,0,-5,0},{-10,20,0,10,0}}, //bunny {{2,25,0,15,0},{2,10,0,0,0},{2,15,0,0,0},{-2,5,0,-5,0},{-10,20,0,10,0}}, //dino {{-2,5,0,-5,0},{-2,5,0,-5,0},{-2,5,0,-5,0},{20,20,0,15,0},{-10,20,0,10,0}}}; //t_rex String pet_age = "0m"; typedef struct { uint8_t health; //0-100 uint8_t hungry; //0-100 uint8_t clean; //0-100 uint8_t happy; //0-100 uint16_t sleep; //0-200 } pet_stats; pet_stats pet = {100,80,80,80,200}; uint8_t pet_mood = 0; //0: normal, 1: happy, 2: sleep, 3:dead uint8_t pet_doing = 0; //0: nothing, 1: eating tomato, 2: eating carrot, 3: eating mushroom, 4: eating chicken, 5: eating candy, 6: cleaning, 7: petting, 8: sleeping, 9: dead bool pet_alive = true; bool pet_sleeping = false; bool pet_poop = true; uint8_t pet_ani = 0; uint8_t food_check[5] = {0,0,0,0,0}; //0: tomato, 1: carrot, 2: mushroom, 3: chicken, 4: candy bool happy_fail = false; //vars to check for evolution bool health_fail = false; //vars to check for evolution //Name vars and consts char ascii_alphabet[63] = {}; //all the alphabet. 26 Uppercases, 26 lowercases, 10 numbers and underscore char name_letters_array[8] = {95,95,95,95,95,95,95,95}; //the characters that compose the pet's name String pet_name = ""; uint8_t ascii_letter_count[8] = {62,62,62,62,62,62,62,62}; uint8_t name_letters_indicator = 0; //0 to 7 for the letters, 8 for the "Next" button //UI vars and consts uint32_t rng_comp = 0; int rng_dir = 1; uint8_t screen = 0; //0: name, 1: main, 2: status uint8_t sel = 0; uint8_t food_sel = 0; //0: tomato, 1: carrot, 2: mushroom, 3: chicken, 4: candy const uint8_t bottom_bar_size = 5; uint8_t bottom_bar_sel_size = 0; uint8_t bottom_bar_pos[bottom_bar_size] ={}; uint8_t explosion_rad = 0; bool evolve_ani = false; //Sprite arrays for the animations const unsigned char* bottom_bar_icons[bottom_bar_size-1] = {icon_hand, icon_clean, icon_sleep, icon_stat}; const unsigned char* bottom_bar_food[5] = {icon_tomato, icon_carrot, icon_mushroom, icon_chickenleg, icon_candy}; const unsigned char* icon_popup[9] = {icon_tomato, icon_carrot, icon_mushroom, icon_chickenleg, icon_candy, icon_clean, icon_hand, icon_sleep, icon_dead}; const unsigned char* slime_bot[1][1] = {{slime_bot1}}; const unsigned char* slime_up[1][2] = {{slime_up1, slime_up2}}; const unsigned char* slime_eyes[3][2] = {{slime_eye_n1, slime_eye_n2},{slime_eye_h1, slime_eye_h2},{slime_eye_s1, slime_eye_s2}}; const unsigned char* bunny_bot[2][2] = {{bunny_bot_n1, bunny_bot_n2},{bunny_bot_h1, bunny_bot_h2}}; const unsigned char* bunny_up[2][2] = {{bunny_up_n1, bunny_up_n2},{bunny_up_h1, bunny_up_h2}}; const unsigned char* bunny_eyes[3][2] = {{bunny_eye_n1, bunny_eye_n2},{bunny_eye_h1, bunny_eye_h2},{bunny_eye_s1, bunny_eye_s2}}; const unsigned char* dino_back[1][2] = {{dino_back1, dino_back2}}; const unsigned char* dino_bot[1][2] = {{dino_bot1, dino_bot2}}; const unsigned char* dino_up[1][2] = {{dino_up1, dino_up2}}; const unsigned char* dino_eyes[3][2] = {{dino_eye_n1, dino_eye_n2},{dino_eye_h1, dino_eye_h2},{dino_eye_s1, dino_eye_s2}}; const unsigned char* trex_back[1][2] = {{trex_back1, trex_back2}}; const unsigned char* trex_bot[1][2] = {{trex_bot1, trex_bot2}}; const unsigned char* trex_up[1][2] = {{trex_up1, trex_up2}}; const unsigned char* trex_eyes[3][2] = {{trex_eye_n1, trex_eye_n2},{trex_eye_h1, trex_eye_h2},{trex_eye_s1, trex_eye_s2}}; void setup() { delay(10); pinMode(bt_left, INPUT_PULLUP); pinMode(bt_right, INPUT_PULLUP); pinMode(bt_up, INPUT_PULLUP); pinMode(bt_down, INPUT_PULLUP); oled.init(); oled.clear(); bottom_bar_gen(); age_gen(); alphabet_gen(); rng_comp = int(millis()+analogRead(PA0)); if (rng_comp % 2 == 0){pet_sex = 1;} } //======================================================================== //============================ Name Functions ============================ //======================================================================== void alphabet_gen(){ uint8_t char_count = 65; for (uint8_t i=0; i<26; i++){ //Uppercase ascii_alphabet[i] = char_count + i; } char_count = 97; for (uint8_t i=0; i<26; i++){ //Lowercase ascii_alphabet[26 + i] = char_count + i; } char_count = 48; for (uint8_t i=0; i<10; i++){ //numbers ascii_alphabet[52 + i] = char_count + i; } ascii_alphabet[62] = 95; //add space } //======================================================================== //============================= Time Function ============================ //======================================================================== void time_check(){ current_millis = millis(); //Check animation tick if (current_millis - ani_tick_previous_millis >= 500){ //check seconds ani_tick_previous_millis = current_millis; ani_tick += 1; //Do Action if (current_millis > doing_tick){ if(pet_doing < 8){ pet_doing = 0; if(pet_mood == 1){ pet_mood = 0; } } } } //Check time change if (current_millis - previous_millis >= 1000){ //check seconds rng_comp = int(analogRead(PA0)) * rng_dir; rng_dir *= -1; previous_millis = current_millis; act_time[0] += 1; if (act_time[0] == 5 && pet_lvl == 0){ evolve_ani = true; } if (act_time[0] >= 60){ //check minutes act_time[0] = 0; act_time[1] += 1; if (act_time[1] % check_pet_time == 0){ check_pet(); } if (act_time[1] >= 60){ //check hours act_time[1] = 0; act_time[2] += 1; } if (act_time[2] >= 24){ //check days act_time[2] = 0; act_time[3] += 1; if (pet_lvl == 1){ evolve_ani = true; } } } } } //======================================================================== //================================ Buttons =============================== //======================================================================== void check_bt(){ //=============================== Button Up ============================== if (digitalRead(bt_up) == LOW){ rng_comp += int(buttom_cooldown_millis - millis()) * rng_dir; rng_dir *= -1; if(millis() > buttom_cooldown_millis + buttom_cooldown){ //debounce buttom_cooldown_millis = millis(); //Name Screen if (screen == 0){ if(name_letters_indicator !=8){ ascii_letter_count[name_letters_indicator] = func_select(ascii_letter_count[name_letters_indicator], 62, 1); name_letters_array[name_letters_indicator] = ascii_alphabet[ascii_letter_count[name_letters_indicator]]; } else{ uint8_t letter_count = 0; for(uint8_t i =0; i < 8; i++){ //Counting the written letters if(name_letters_array[7-i] != 95){ letter_count = 7-i; break; } } for(uint8_t i =0; i <= letter_count; i++){ //Saving the name pet_name += name_letters_array[i]; } timer_rolling = true; screen = 1; } } //Main Screen else if (screen == 1){ if (pet_alive == true && doing_tick < millis()){ if (sel == 0){ //Eating if (pet.hungry < 100){ pet_doing = food_sel + 1; //diferent stats per food pet.health += pet_eating_vars[pet_species][food_sel][0]; pet.hungry += pet_eating_vars[pet_species][food_sel][1]; pet.clean += pet_eating_vars[pet_species][food_sel][2]; pet.happy += pet_eating_vars[pet_species][food_sel][3]; pet.sleep += pet_eating_vars[pet_species][food_sel][4]; food_check[food_sel] += 1; //0: tomato, 1: carrot, 2: mushroom, 3: chicken, 4: candy pet_mood = 1; pet_sleeping = false; } } else if (sel == 1){ //Peting if (pet.happy < 100){ pet_doing = 7; pet.happy += 10; pet_mood = 1; pet_sleeping = false; } } else if (sel == 2){ //Cleaning if (pet_poop == true){ pet_poop = false; } if (pet.clean < 100){ pet_doing = 6; pet.clean = 100; pet_mood = 1; pet_sleeping = false; } } else if (sel == 3){ //Sleeping if (pet_doing == 0 && pet_sleeping == false){ pet_mood = 2; pet_doing = 8; pet_sleeping = true; } else if (pet_doing == 8){ pet_mood = 0; pet_doing = 0; pet_sleeping = false; } } else if (sel == 4){ //status age_gen(); screen = 2; sel = 0; } doing_tick = millis() + doing_cooldown; } } //Status Screen else if (screen == 2){ screen = 1; } clamp_pet(); } } //============================== Button Down ============================= if (digitalRead(bt_down) == LOW){ rng_comp += int(buttom_cooldown_millis - millis()) * rng_dir; rng_dir *= -1; if(millis() > buttom_cooldown_millis + buttom_cooldown){ //debounce buttom_cooldown_millis = millis(); //Name Screen if (screen == 0){ if(name_letters_indicator !=8){ ascii_letter_count[name_letters_indicator] = func_select(ascii_letter_count[name_letters_indicator], 62, 0); name_letters_array[name_letters_indicator] = ascii_alphabet[ascii_letter_count[name_letters_indicator]]; } } //Main Screen else if (screen == 1){ if (pet_alive == true && doing_tick < millis()){ if (sel == 0){ //Eating food_sel = func_select(food_sel, 4, 1); } } } //Status Screen else if (screen == 2){ screen = 1; } } } //============================== Button Left ============================= if (digitalRead(bt_left) == LOW){ rng_comp += int(buttom_cooldown_millis - millis()) * rng_dir; rng_dir *= -1; if(millis() > buttom_cooldown_millis + buttom_cooldown){ //debounce buttom_cooldown_millis = millis(); //Name Screen if (screen == 0){ name_letters_indicator = func_select(name_letters_indicator, 8, 0); } //Main Screen else if (screen == 1){ sel = func_select(sel, bottom_bar_size-1, 0); } //Status Screen else if (screen == 2){ screen = 1; } } } //============================= Button Right ============================= if (digitalRead(bt_right) == LOW){ rng_comp += int(buttom_cooldown_millis - millis()) * rng_dir; rng_dir *= -1; if(millis() > buttom_cooldown_millis + buttom_cooldown){ //debounce buttom_cooldown_millis = millis(); //Name Screen if (screen == 0){ name_letters_indicator = func_select(name_letters_indicator, 8, 1); } //Main Screen else if (screen == 1){ sel = func_select(sel, bottom_bar_size - 1, 1); } //Status Screen else if (screen == 2){ screen = 1; } } } } uint8_t func_select(uint8_t var, uint8_t max, uint8_t dir){ //dir 0: negative, 1:positive if(dir > 0){ if(var < max){var += 1;} else{var = 0;} } else{ if(var > 0){var -= 1;} else{var = max;} } return var; } //======================================================================== //======================= Physiological Functions ======================== //======================================================================== void check_pet(){ if (pet_alive == true){ //awake if (pet_sleeping == false){ pet.sleep -= 1; pet.hungry -= 2; pet.clean -= 1; if (sleeping_time >= 10){sleeping_time -= 10;} else{sleeping_time = 0;} //Random Events if (int(rng_comp % 3) == 0){pet.hungry -= 2;} if (int(rng_comp % 4) == 0){ pet.clean -= 1; pet.happy -= 2; } //poop if (int(rng_comp % 10) == 0){ pet_poop = true; } } //sleeping else{ sleeping_time += 5; if (sleeping_time > 480){ pet.hungry -= 2; pet.clean -= 2; pet.health -= 1; } pet.sleep += 5; if (int(rng_comp % 3) == 0){pet.hungry -= 1;} } if (pet_poop == true){ pet.health -= 2; pet.clean -= 3; pet.happy -= 2; } //happiness calc pet.happy -= ((100 - pet.health) + (100 - pet.clean) + (200 - pet.sleep) + (100 - pet.hungry))/40; //health calc if((pet.happy + pet.clean + (pet.sleep/2) + pet.hungry)/4 > 80){ pet.health += 5; } else if((pet.happy + pet.clean + (pet.sleep/2) + pet.hungry)/4 > 50){ pet.health -= 1; } else if((pet.happy + pet.clean + (pet.sleep/2) + pet.hungry)/4 > 30){ pet.health -= 3; } //check death if (pet.health <=0 || pet.hungry <=0 || pet.sleep <= 0 || pet.clean <=0){ pet_alive= false; pet_doing = 9; pet_mood = 3; } } if (pet.health <= 50){ health_fail = true; } if (pet.happy <= 50){ happy_fail = true; } clamp_pet(); } void evolve(){ switch (pet_lvl){ case 0: pet_species = 1; break; case 1: pet_species = 2; //evolve to Bunny if (happy_fail == false && health_fail == false && food_check[0] == 0 && food_check[1] == 0 && food_check[2] == 0){ //(only eats chicken or candy) - food_check: 0: tomato, 1: carrot, 2: mushroom, 3: chicken, 4: candy pet_species = 4; //evolve to T-Rex } else if (health_fail == false && food_check[0] > 0 && food_check[1] > 0 && food_check[2] > 0 && food_check[3] == 0){ //(eats every vegetable. can eat candy too) - food_check: 0: tomato, 1: carrot, 2: mushroom, 3: chicken, 4: candy pet_species = 3; //evolve to Dino } break; } pet_lvl += 1; } void clamp_pet(){ if(pet.health > 100){pet.health = 100;} if(pet.hungry > 100){pet.hungry = 100;} if(pet.clean > 100){pet.clean = 100;} if(pet.happy > 100){pet.happy = 100;} if(pet.sleep > 200){pet.sleep = 200;} } //======================================================================== //================================ Misc ================================== //======================================================================== void ani_check(){ if (pet_mood == 0) { pet_ani = ani_tick % 2; } else if (pet_mood == 1) { pet_ani = 2 + (ani_tick % 2); } else if (pet_mood == 2) { pet_ani = 4 + (ani_tick % 2); } else if (pet_mood == 3) { pet_ani = 5; } } // Generates the bottom bar void bottom_bar_gen(){ bottom_bar_sel_size = 127 / bottom_bar_size; for(uint8_t i = 0; i < bottom_bar_size; i++){ bottom_bar_pos[i] = (i* bottom_bar_sel_size) + ((bottom_bar_sel_size - 8)/2); } } // Make the age string on the status screen void age_gen(){ if (pet_alive == true){ if (act_time[3]!=0){ pet_age = String(act_time[3]) + "D"; } else if (act_time[2]!=0){ pet_age = String(act_time[2]) + "H"; } else if (act_time[1]!=0){ pet_age = String(act_time[1]) + "m"; } else{ pet_age = "0m"; } } } void resize(const uint8_t* bmp, uint16_t w, uint16_t h, int16_t x0, int16_t y0, uint8_t scale) { if (!scale) return; // avoid divide-by-zero for (uint16_t sy = 0; sy < h; sy++) { uint16_t pageOffset = (sy >> 3) * w; // which 8‑pixel row page uint8_t mask = 1 << (sy & 7); // bit inside that page for (uint16_t sx = 0; sx < w; sx++) { uint8_t b = pgm_read_byte(bmp + pageOffset + sx); if (b & mask) { int16_t dx = x0 + sx * scale; int16_t dy = y0 + sy * scale; // draw the scale×scale block for (uint8_t yy = 0; yy < scale; yy++) { int16_t py = dy + yy; if (py < 0 || py >= 64) continue; for (uint8_t xx = 0; xx < scale; xx++) { int16_t px = dx + xx; if (px < 0 || px >= 128) continue; oled.dot(px, py); } } } } } } //======================================================================== //=========================== Draw Function ============================== //======================================================================== void draw(){ oled.clear(); oled.invertText(false); //print time oled.setCursorXY(2, 0); oled.print("Day:"); oled.print(act_time[3]); oled.setCursorXY(96, 0); if (act_time[2] < 10){oled.print("0");} oled.print(act_time[2]); oled.print(":"); if (act_time[1] < 10){oled.print("0");} oled.print(act_time[1]); //print R.I.P. if (pet_alive == false){ oled.setCursorXY(48, 0); oled.print("R.I.P."); } //print upper bar oled.setCursorXY(0, 0); oled.line(0, 10, 127, 10); //======================================================================== //===============================Name Screen============================== //======================================================================== if (screen == 0){ draw_sex(1, 16); oled.setCursor(16,3); oled.setScale(2); draw_letter_scroll(); oled.setScale(1); if (name_letters_indicator == 8){ oled.invertText(true); } oled.setCursorXY(91,55); oled.print("Start!"); oled.invertText(false); oled.rect(89,53,127,63,2); if (name_letters_indicator == 8){ oled.line(90,54,90,63); oled.line(90,54,127,54); } } //======================================================================== //===============================Main Screen============================== //======================================================================== if (screen == 1){ //print char ani_check(); draw_pet(); //draw icon if (pet_doing > 0){ if (pet_alive == true){ //0: nothing, 1: eating tomato, 2: eating carrot, 3: eating mushroom, 4: eating chicken, 5: eating candy, 6: petting, 7: cleaning, 8: sleeping, 9: dead resize(icon_popup[pet_doing-1], 8, 8, (68 + (pet_size[pet_species]/2) + (ani_tick % 2)), (16 + ((ani_tick % 2)*2)), 2); //const uint8_t* bmp, uint16_t w, uint16_t h, int16_t x0, int16_t y0, uint8_t scale } else{ resize(icon_popup[8],8 ,8 ,68 + (pet_size[pet_species]/2) + (ani_tick % 2), 16 + ((ani_tick % 2)*2), 2); } } if (pet_poop == true){ resize(icon_poop, 8, 8, 104, 32, 2); //bmp, w, h, x0, y0, scale } //draw bottom bar for (uint8_t i = 0; i < bottom_bar_size; i++){ uint8_t invert_sprite = 0; //print selection if (i == sel){ oled.rect((i*bottom_bar_sel_size), 54, ((i+1)*bottom_bar_sel_size), 63); invert_sprite = 1; } if (i == 0 ){ oled.drawBitmap(bottom_bar_pos[i], 55, bottom_bar_food[food_sel], 8, 8, 0, invert_sprite); } else{ oled.drawBitmap(bottom_bar_pos[i], 55, bottom_bar_icons[i-1], 8, 8, 0, invert_sprite); } } if (evolve_ani == true){ draw_explosion(); } } //======================================================================== //=============================Status Screen============================== //======================================================================== else if(screen == 2){ //Draw Infos draw_sex(1, 16); oled.setCursorXY(12, 16); oled.print(pet_name); oled.setCursorXY(1, 28); oled.print(pet_all_species[pet_species]); oled.setCursorXY(1, 40); oled.print("Age: "); oled.print(pet_age); oled.setCursorXY(1, 52); oled.print("Lvl: "); if(pet_lvl < 2){oled.print(pet_lvl);} else{oled.print("MAX");} //Draw graffics for (uint8_t i = 0; i < 5; i++){ oled.rect(64 + (i*13), 16, 72 + (i*13), 54,2); if(i==0){ oled.drawBitmap(64 + (i*13), 56, icon_health, 8, 8); oled.rect(66 + (i*13), 18 + (34 - (34 * pet.health)/100), 70 + (i*13), 52); } else if(i==1){ oled.drawBitmap(64 + (i*13), 56, icon_sleep, 8, 8); oled.rect(66 + (i*13), 18 + (34 - (34 * pet.sleep)/200), 70 + (i*13), 52); } else if(i==2){ oled.drawBitmap(64 + (i*13), 56, icon_chickenleg, 8, 8); oled.rect(66 + (i*13), 18 + (34 - (34 * pet.hungry)/100), 70 + (i*13), 52); } else if(i==3){ oled.drawBitmap(64 + (i*13), 56, icon_clean, 8, 8); oled.rect(66 + (i*13), 18 + (34 - (34 * pet.clean)/100), 70 + (i*13), 52); } else if(i==4){ oled.drawBitmap(64 + (i*13), 56, icon_happiness, 8, 8); oled.rect(66 + (i*13), 18 + (34 - (34 * pet.happy)/100), 70 + (i*13), 52); } } } oled.update(); } void draw_sex(uint8_t x, uint8_t y){ if (pet_sex == 0) {oled.drawBitmap(x, y, icon_fem, 8, 8);} else {oled.drawBitmap(x, y, icon_male, 8, 8);} } //Solving the sprite puzzle void draw_pet(){ uint8_t animation_eyes; uint8_t animation_body; if (pet_alive == true){ animation_eyes = pet_mood; animation_body = ani_tick%2; } else{ animation_eyes = 3; animation_body = 0; } switch (pet_species){ //Egg case 0: resize(egg,12,13,52,22,2); //bmp, w, h, x0, y0, scale break; //Slime case 1: resize(slime_up[0][animation_body],12,4,52,30,2); //bmp, w, h, x0, y0, scale resize(slime_eyes[animation_eyes][animation_body],12,3,52,38,2); resize(slime_bot[0][0],12,2,52,44,2); break; //Bunny case 2: if (pet_alive == true){ if(pet_mood != 1){ resize(bunny_up[0][animation_body],16,6,48,16,2); resize(bunny_bot[0][animation_body],16,7,48,34,2); } else{ resize(bunny_up[1][animation_body],16,6,48,16,2); resize(bunny_bot[1][animation_body],16,7,48,34,2); } resize(bunny_eyes[animation_eyes][animation_body],16,3,48,28,2); } break; //Dino case 3: resize(dino_back[0][animation_body],16,16,32,16,2); //bmp, w, h, x0, y0, scale resize(dino_up[0][animation_body],16,7,64,16,2); resize(dino_eyes[animation_eyes][animation_body],16,3,64,30,2); resize(dino_bot[0][animation_body],16,6,64,36,2); break; //Dino case 4: resize(trex_back[0][animation_body],16,16,32,16,2); //bmp, w, h, x0, y0, scale resize(trex_up[0][animation_body],16,4,64,16,2); resize(trex_eyes[animation_eyes][animation_body],16,3,64,24,2); resize(trex_bot[0][animation_body],16,9,64,30,2); break; } } //Explosion animation and evolve call void draw_explosion(){ explosion_rad += 3; if (explosion_rad < 85){ draw_tick_max = 0; oled.circle(64, 32, explosion_rad + 10, 2); oled.circle(64, 32, explosion_rad + 3, 2); oled.circle(64, 32, explosion_rad, 1); oled.circle(64, 32, explosion_rad -10, 0); } else{ draw_tick_max = 100; evolve_ani = false; evolve(); explosion_rad = 0; } } void draw_letter_scroll(){ for(uint8_t i=0; i<8; i++){ if (i == name_letters_indicator){ oled.invertText(true); } oled.print(name_letters_array[i]); oled.invertText(false); } } void loop() { check_bt(); if (timer_rolling == true){ time_check(); } if(millis() > draw_tick + draw_tick_max){ //controls the screens refresh to save some battery draw_tick = millis(); draw(); } }