u/Easy_Ingenuity5811

OLED SPI Display keeps on glitching

OLED SPI Display keeps on glitching

I successfully uploaded the code on this project Arduboy Pocket Watch from https://www.hackster.io/tusharmagar/arduboy-pocket-watch-d19a1c to my Arduino Pro Micro but it only works when I reset it. I've tried burning the bootloader but the screen keeps on glitching and crashing and looking not at all coherent. Attached below is the code, photo of OLED display's current state and the circuit diagram I followed. For the circuit diagram I've only connected the OLED, RTC, button and Pro Micro on a breadboard. Battery charging module and LIPO battery should be ignored.

https://preview.redd.it/ethylga4ng2h1.jpg?width=1039&format=pjpg&auto=webp&s=17686e2bb94cbcf1f093647629ed23d0fd90901a

#include <Arduboy2.h>

#include <SPI.h>
#include <Wire.h>
#include <Time.h>
#include <TimeLib.h>
#include <DS1307RTC.h>

#include "Tinyfont.h"
#include "limits.h"

#define GROUND_HEIGHT       46
#define OBSTACLE_DELAY_MAX  512
#define OBSTACLE_DELAY_MIN  96
#define BONUS_DELAY_MAX     1024
#define BONUS_DELAY_MIN     512

tmElements_t tm;

enum State {
    Intro,
    Play,
    Pause,
    Over,
    Credits
};

struct Position {
    int x;
    int y;
};
struct Velocity {
    int x;
    int y;
};
struct Size {
    unsigned int width;
    unsigned int height;
};

struct Object {
    Position pos;
    Velocity vel;
    Rect     box;
    unsigned int frame;
    unsigned int type;
    boolean action;
};
struct Star {
    Position pos;
    unsigned int frame;
};
struct Particle {
    Position pos;
    unsigned int life;
    unsigned int lifeCount;
};

const byte spriteLogoA[] PROGMEM = {
    0x3e, 0x63, 0xc9, 0x9d, 0x39, 0x7b, 0xf2, 0xf6, 0xf4, 0xe4, 0xc8, 0xd8, 0x90, 0xb0, 0xa0, 0x20, 0x60, 0xc0, 0x80, 0x80, 0xc0, 0x60, 0x20, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x20, 0x60, 0x40, 0x40, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1, 0x7, 0xc, 0x19, 0x73, 0xc7, 0x9f, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfc, 0xfd, 0xfd, 0xfc, 0xff, 0xff, 0xff, 0x9f, 0xf, 0xf, 0xf, 0xf, 0x1f, 0x1f, 0x1e, 0x3c, 0x3d, 0x7d, 0xf9, 0xfb, 0xf2, 0xe6, 0xcc, 0x98, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xf0, 0x1f, 0xc3, 0xf8, 0xff, 0xff, 0xf3, 0x5, 0x3, 0x45, 0x8b, 0x17, 0xaf, 0x5f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfc, 0xfc, 0xf8, 0xf8, 0xf0, 0xe0, 0xc0, 0x1, 0x3, 0xf, 0x1f, 0x7f, 0xff, 0xfe, 0xf8, 0xf3, 0xc6, 0x1c, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf0, 0x1f, 0xc0, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfc, 0xfc, 0xfc, 0xfe, 0xff, 0x7f, 0x3f, 0x9f, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xf0, 0x80, 0x00, 0x1, 0xf, 0xff, 0xff, 0xff, 0xfc, 0x1, 0xff, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7, 0x70, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x8f, 0xe3, 0xf9, 0xfc, 0xfe, 0x3f, 0x87, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, 0xf0, 0xff, 0xff, 0xff, 0x1f, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0xc0, 0x41, 0x47, 0x4c, 0x49, 0x6b, 0x2b, 0xab, 0xab, 0xbb, 0x99, 0xdd, 0xcc, 0xee, 0xe7, 0xf7, 0xf3, 0xf9, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x9f, 0xc7, 0xf0, 0xf8, 0xfe, 0x7f, 0x3f, 0x8f, 0xe7, 0x31, 0x1c, 0x7, 0x00, 0x00, 0x00, 0x00, 0x7, 0xc, 0x19, 0x13, 0x37, 0x27, 0x6f, 0xcf, 0x9f, 0xbf, 0xbf, 0x3f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x7f, 0x3f, 0xbf, 0xbf, 0xbf, 0x9f, 0xcf, 0x67, 0x27, 0x33, 0x19, 0xc, 0x6, 0x3, 0x1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1, 0x1, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x3, 0x1, 0x1, 0x1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

const byte spriteBackgroundA[] PROGMEM  = {
    0xc0, 0xf0, 0xf8, 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xfc, 0xf8, 0xf0, 0xc0, 0x00, 0xc0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
};
const byte spriteBackgroundB[] PROGMEM  = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x4, 0x2, 0x2, 0x2, 0x4, 0x18, 0x20, 0x10, 0x10, 0x10, 0x20, 0x18, 0x4, 0x2, 0x2, 0x2, 0x4, 0x18, 0x20, 0x10, 0x10, 0x10, 0x20, 0x8a, 0x55, 0xa2, 0x54, 0x8a, 0x55, 0xa2, 0x54, 0x8a, 0x55, 0xa2, 0x54, 0x8a, 0x55, 0xa2, 0x54, 0x8a, 0x55, 0xa2, 0x54, 0x8a, 0x55, 0xa2, 0x54,
};

const byte spriteMoon[] PROGMEM = {
    0xe0, 0xf8, 0xfc, 0xfe, 0xe, 0x3, 0x1, 0x1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7, 0x1f, 0x3f, 0x7f, 0x7f, 0xfc, 0xf8, 0xf8, 0xf0, 0xf0, 0xf0, 0x70, 0x78, 0x38, 0x1c, 0x7,
};

const byte spriteStar_0[] PROGMEM  = { 0x00, 0x00, 0x00, 0x00, 0x8, 0x00, 0x00, 0x00 };
const byte spriteStar_1[] PROGMEM  = { 0x00, 0x00, 0x00, 0x8, 0x1c, 0x8, 0x00, 0x00 };
const byte spriteStar_2[] PROGMEM  = { 0x00, 0x00, 0x00, 0x8, 0x14, 0x8, 0x00, 0x00 };
const byte spriteStar_3[] PROGMEM  = { 0x00, 0x00, 0x8, 0x8, 0x36, 0x8, 0x8, 0x00 };
const byte spriteStar_4[] PROGMEM  = { 0x00, 0x00, 0x8, 0x00, 0x2a, 0x00, 0x8, 0x00 };
const byte *animationFramesStar[] = { spriteStar_0, spriteStar_1, spriteStar_2, spriteStar_3, spriteStar_4 };

const byte spriteUnicorn_0[] PROGMEM  = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x18, 0x8, 0x7c, 0x1c, 0x1c, 0x1e, 0x7f, 0x2, 0x3, 0x3, 0x00, 0x00, 0x00,
};
const byte spriteUnicorn_1[] PROGMEM  = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x20, 0x30, 0x10, 0x38, 0x78, 0x38, 0x38, 0x38, 0x7c, 0x3e, 0x5, 0x6, 0x6, 0x00, 0x00,
};
const byte spriteUnicorn_2[] PROGMEM  = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0xc0, 0xe0, 0x50, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2, 0x3, 0x1, 0xf, 0x3, 0x3, 0x3, 0xf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const byte spriteUnicornMask_0[] PROGMEM  = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0xa0, 0xd0, 0x20, 0x00, 0x00, 0x00, 0x10, 0x28, 0x24, 0x74, 0x82, 0x62, 0x22, 0x61, 0x80, 0x7d, 0x4, 0x4, 0x3, 0x00, 0x00,
};
const byte spriteUnicornMask_1[] PROGMEM  = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0xa0, 0x40, 0x00, 0x20, 0x50, 0x48, 0x28, 0x44, 0x84, 0x44, 0x44, 0x44, 0x82, 0x41, 0x3a, 0x9, 0x9, 0x6, 0x00,
};
const byte spriteUnicornMask_2[] PROGMEM  = {
    0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x10, 0xa8, 0x94, 0x9a, 0x64, 0x00, 0x00, 0x00, 0x2, 0x5, 0x4, 0xe, 0x10, 0xc, 0x4, 0xc, 0x10, 0xf, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const byte *animationFramesUnicorn[] = { spriteUnicorn_0, spriteUnicorn_1, spriteUnicorn_2 };
const byte *animationFramesUnicornMask[] = { spriteUnicornMask_0, spriteUnicornMask_1, spriteUnicornMask_2 };

const byte spriteStar[] PROGMEM  = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4, 0x6c, 0x7c, 0x3f, 0x37, 0x7c, 0x6c, 0x4, 0x00, 0x00, 0x00, 0x00,
};
const byte spriteStarMask[] PROGMEM  = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4, 0x6a, 0x92, 0x83, 0x40, 0x48, 0x83, 0x92, 0x6a, 0x4, 0x00, 0x00, 0x00,
};
const byte spriteGhost[] PROGMEM  = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33, 0x3f, 0x3f, 0x33, 0x3f, 0x3e, 0x18, 0x10, 0x00, 0x00, 0x00,
};
const byte spriteGhostMask[] PROGMEM  = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x21, 0x4c, 0x40, 0x40, 0x4c, 0x40, 0x41, 0x26, 0x28, 0x18, 0x00, 0x00,
};
const byte *spritesObject[] = { spriteGhost, spriteStar };
const byte *spritesObjectMask[] = { spriteGhostMask, spriteStarMask };

boolean btnPressed, dpadPressed;

unsigned int counterState, counterBackgroundA, counterBackgroundB = 0;
int scoreBonusDuration = 0;

long score, scoreHI = 0;

Arduboy2 arduboy;
Tinyfont arduboyTinyFont = Tinyfont(arduboy.sBuffer, Arduboy2::width(), Arduboy2::height());

State state = Intro;

Object unicorn, objects[3];
Particle particles[24];
Star stars[9] = {
    { { 2,  13  }, 1 },
    { { 23,  3  }, 4 },
    { { 27,  24 }, 2 },
    { { 42,  7  }, 0 },
    { { 59,  16 }, 4 },
    { { 77,  8  }, 1 },
    { { 92,  21 }, 0 },
    { { 109, 9  }, 3 },
    { { 116, 17 }, 0 }
};

// ------------------------------------------------------------------------------------
void setup() {
  RTC.read(tm);
    arduboy.begin();
    particlesReset();
    statePlayReset();

    scoreHI = EEPROM.read(EEPROM_STORAGE_SPACE_START);
}
void loop() {
    arduboy.clear();
    if (!arduboy.nextFrame()) {
        return;
    }

    if (arduboy.everyXFrames(32)) {
        randomSeed(analogRead(0)); // reset random
    }

    stateUpdate();

    arduboy.display();
}

// ------------------------------------------------------------------------------------
void stateUpdate() {
    counterState = ((counterState + 1) > UINT_MAX) ? 0 : counterState;

    switch (state) {

        case State::Play:
            statePlayUpdate();
            break;

        case State::Over:
            stateOverUpdate();
            break;

        default:
            stateIntroUpdate();
            break;
    }
}
void stateSwitch(State stateNew) {
    counterState = 0;
    counterBackgroundA, counterBackgroundB = 0;

    switch (stateNew) {
        case State::Intro:
            statePlayReset();
            break;
    }

    state = stateNew;
};

// STATE INTRO: -----------------------------------------------------------------------
void stateIntroUpdate() {
    counterState += 1;

    arduboy.drawBitmap(10, 0, spriteLogoA, 50, 58, WHITE);

    arduboyTinyFont.setCursor(15, 60);
    for (byte i = (8 - intLength(scoreHI)); i > 0; i--) {
        arduboyTinyFont.print("0");
    }

    arduboyTinyFont.print(scoreHI);

//////////////////////////////////////////////////////////////////////////////
arduboy.setCursor(70,15);
arduboy.setTextSize(2);
arduboy.print(tm.Hour);
arduboy.print(":");
arduboy.print(tm.Minute);
arduboy.setCursor(70,40);
arduboy.setTextSize(1);
arduboy.print(tm.Day);
arduboy.write('/');
arduboy.print(tm.Month);
arduboy.write('/');
arduboy.print(tmYearToCalendar(tm.Year));
arduboy.display();

    if ((arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON)) && !btnPressed) {
            stateSwitch(State::Play);
    }
    btnPressed = (arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON));
}



// STATE Over: ---------------------------------------------------------------------
void stateOverUpdate() {
    arduboy.setCursor(37, 18);
    arduboy.print("GAME OVER");

    for (byte i = 0; i < 3; i++) {
        if (objects[i].type == 0) {
            objectRender(objects[i]);
        }
    }

    unicornRender();
    scoreRender();

    if (arduboy.pressed(B_BUTTON) && !btnPressed) {
        if (score > scoreHI) {
            scoreHI = score;
            EEPROM.update(EEPROM_STORAGE_SPACE_START, scoreHI);
        }

        stateSwitch(State::Intro);
    }
    btnPressed = arduboy.pressed(B_BUTTON);
}

// STATE PLAY: ------------------------------------------------------------------------
void statePlayUpdate() {
    counterState += 1;
    
        if (arduboy.pressed(B_BUTTON) && unicorn.action) {
            unicorn.vel.y = -3;
            counterState = 0;
        }
        
    btnPressed = (arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON));

    backgroundLayerOneRender();
    backgroundLayerTwoRender();
    backgroundLayerThreeRender();

    objectsUpdate();
    unicornUpdate();

    scoreUpdate();
}
void statePlayReset() {
    score = 0;
    scoreBonusDuration = 0;

    unicornSetup();
    objectsSetup();
}


// UNICORN ----------------------------------------------------------------------------
void unicornSetup() {
    unicorn = { { 48, GROUND_HEIGHT }, { 0, 0 }, { 0, 0, 7, 8 }, 0, 7, true };
}
 void unicornUpdate() {

    if (counterState%10 == 0) {
        unicorn.vel.y += 1;
    }

    unicorn.pos.y = min(unicorn.pos.y + unicorn.vel.y, GROUND_HEIGHT);
    unicorn.pos.x = min(unicorn.pos.x + unicorn.vel.x, arduboy.width() - 12);
    unicorn.pos.x = max(unicorn.pos.x + unicorn.vel.x, -4);

    unicorn.box.x = unicorn.pos.x + 4;
    unicorn.box.y = unicorn.pos.y - 9;

    if (unicorn.pos.y >= GROUND_HEIGHT) {
        unicorn.action = true;
        unicorn.vel.y = 0;
    }
    else {
        unicorn.action = false;
    }

    unicornRender();
    particlesRender();
}
void unicornRender() {
    if (unicorn.action) {
        if (arduboy.everyXFrames(6)) {
            unicorn.frame = ((unicorn.frame + 1) > 2) ? 0 : unicorn.frame + 1;
        }
    }
    else {
        unicorn.frame = 0;
    }

    arduboy.drawBitmap(unicorn.pos.x, unicorn.pos.y - 15, animationFramesUnicornMask[unicorn.frame], 16, 16, BLACK);
    arduboy.drawBitmap(unicorn.pos.x, unicorn.pos.y - 15, animationFramesUnicorn[unicorn.frame], 16, 16, WHITE);
}

// OBJECTS ---------------------------------------------------------------------------
void objectsSetup() {
    objects[0] = { { -16, GROUND_HEIGHT }, { -1, 0 }, { 0, 0, 8, 8 }, 0, 0, true };
    objects[1] = { { -16, GROUND_HEIGHT }, { -1, 0 }, { 0, 0, 8, 8 }, 0, 0, true };
    objects[2] = { { -16, 22 },            { -1, 0 }, { 0, 0, 8, 8 }, 0, 1, true };

    for (byte i = 0; i < 3; i++) {
        objects[i] = objectReset(objects[i]);
    }
}
void objectsUpdate() {
    for (byte i = 0; i < 3; i++) {
        objects[i].pos.x += objects[i].vel.x;
        objects[i].box.x = objects[i].pos.x + 4;
        objects[i].box.y = objects[i].pos.y - 8;

        if (objects[i].pos.x >= -8) {
            Rect boxA = { unicorn.box.x, unicorn.box.y, unicorn.box.width, unicorn.box.height };
            Rect boxB = { objects[i].box.x, objects[i].box.y, objects[i].box.width, objects[i].box.height };

            if (arduboy.collide(boxA, boxB)) {
                if (objects[i].type == 0) {
                    state = State::Over;
                }
                else if (objects[i].type == 1){
                    objects[i] = objectReset(objects[i]);

                    if (scoreBonusDuration <= 0) {
                        particlesReset();
                    }
                    scoreBonusDuration += 50;
                }
            }

            objectRender(objects[i]);
        }
        else {
            objects[i] = objectReset(objects[i]);
        }
    }
}
void objectRender(Object object) {
    arduboy.drawBitmap(object.pos.x, object.pos.y - 15, spritesObjectMask[object.type], 16, 16, BLACK);
    arduboy.drawBitmap(object.pos.x, object.pos.y - 15, spritesObject[object.type], 16, 16, WHITE);
    // arduboy.drawRect(object.box.x, object.box.y, object.box.width, object.box.height, 1); // Collision Box Debug
}
Object objectReset(Object object){
    if (object.type == 0) {
        object.pos.x = arduboy.width() + random(OBSTACLE_DELAY_MIN, OBSTACLE_DELAY_MAX);

        for (byte i = 0; i < 3; i++) {
            if (objects[i].type == 0) {
                if (objects[i].pos.x >= arduboy.width()) {
                    if ((rand()%4) > 2) {
                        object.pos.x = objects[i].pos.x + 10;
                        object.pos.y = GROUND_HEIGHT;
                    }
                    else {
                        object.pos.x = objects[i].pos.x + random(OBSTACLE_DELAY_MIN, OBSTACLE_DELAY_MAX);
                        object.pos.y = GROUND_HEIGHT - random(0, 12);
                    }
                }
            }
        }
    }
    if (object.type == 1) {
        object.pos.x = arduboy.width() + random(BONUS_DELAY_MIN, BONUS_DELAY_MAX);
    }

    return object;
}

// BACKGROUND -------------------------------------------------------------------------
void backgroundLayerOneRender() {
    arduboy.drawBitmap(12, 4, spriteMoon, 16, 16, WHITE);

    for (byte i = 0; i < 9; i++) {
        if (arduboy.everyXFrames(8)) {
            stars[i].frame = ((stars[i].frame + 1) > 4) ? 0 : stars[i].frame + 1;
        }

        arduboy.drawBitmap(stars[i].pos.x, stars[i].pos.y, animationFramesStar[stars[i].frame], 8, 8, WHITE);
    }
}
void backgroundLayerTwoRender() {
    if (arduboy.everyXFrames(2)) {
        counterBackgroundA = ((counterBackgroundA + 1) >= 24) ? 0 : counterBackgroundA + 1;
    }

    for (byte i = 0; i <= 6; i++) {
        arduboy.drawBitmap(((i * 24) - counterBackgroundA), 28, spriteBackgroundA, 24, 36, WHITE);
    }
}
void backgroundLayerThreeRender() {
    if (arduboy.everyXFrames(1)) {
        counterBackgroundB = ((counterBackgroundB + 1) >= 24) ? 0 : counterBackgroundB + 1;
    }

    for (byte i = 0; i <= 6; i++) {
        arduboy.drawBitmap(((i * 24) - counterBackgroundB), 41, spriteBackgroundB, 24, 24, BLACK);
    }
}

// SCORE -----------------------------------------------------------------------------
void scoreUpdate() {
    if (arduboy.everyXFrames(16)) {
        scoreBonusDuration = max(0, (scoreBonusDuration - 1));

        if (scoreBonusDuration > 0){
            score += 10;
        }

        score = min(99999999, (score + 1));
    }

    scoreRender();
}
void scoreRender() {
    if (score > scoreHI) {
        arduboyTinyFont.setCursor(77, 4);
        arduboyTinyFont.print("HI");
    }
    else {
        arduboyTinyFont.setCursor(87, 4);
    }

    for (byte i = (8 - intLength(score)); i > 0; i--) {
        arduboyTinyFont.print("0");
    }

    arduboyTinyFont.print(score);
}

// HELPERS ----------------------------------------------------------------------------
int intLength(int i) {
    int j = 0;

    for(; i; i /= 10) j++;

    return (j == 0) ? 1 : j;
}

void particlesRender() {
    if (scoreBonusDuration <= 0) {
        return;
    }

    for (byte i = 0; i < 24; i++) {
        particles[i].pos.x -= 1;

        if (particles[i].lifeCount > particles[i].life) {
            particles[i].life = 8 + rand()%32;
            particles[i].lifeCount = 0;

            particles[i].pos.y = unicorn.pos.y - 3 + ((rand()%2 > 0) ? (rand()%4 * -1) : rand()%4);
            particles[i].pos.x = unicorn.pos.x + 4;
        }
        else {
            particles[i].lifeCount += 1;
        }

        arduboy.drawPixel(particles[i].pos.x, particles[i].pos.y - 1, 0);
        arduboy.drawPixel(particles[i].pos.x, particles[i].pos.y, 1);
    }
}
void particlesReset() {
    for (int i = 0; i < 24; ++i) {
        particles[i] = { { 0, 0 }, 0 };
    }
};

https://preview.redd.it/v80nw4q4ng2h1.jpg?width=1039&format=pjpg&auto=webp&s=40350cae872fbb250a22fbe475659bb6ba57cb76

https://reddit.com/link/1tjf572/video/6hqrbwl0lg2h1/player

reddit.com
u/Easy_Ingenuity5811 — 14 hours ago