Tushar Magar
Published

Arduboy Pocket Watch!

Ever wanted a pocket watch that you can play one click games on? Well then this is the project you were looking for!

BeginnerFull instructions provided5 hours2,385

Things used in this project

Hardware components

Leonardo Pro Micro
×1
DS1307 RTC I2C Module
×1
0.96" OLED 64x128 SPI
×1
Double-Side Prototype PCB
×1
TP 4056 Li battery charging board
×1
Li-ion battery 500mAh
×1
Arduboy Compatible
Arduboy Compatible
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires

Story

Read more

Schematics

Arduboy Pocket Watch Schematics

Use this as a reference why connecting the components to each other

Code

Arduboy Pocket Watch Code

Arduino
before uploading this code to the pocket watch make sure the time on the DS1307 module is set to the right time.
#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 };
    }
};

Credits

Tushar Magar

Tushar Magar

4 projects • 7 followers
Currently pursuing a bachelors degree in electronics and communication.
Thanks to Kirill Korolkov.

Comments