#include <LiquidCrystal.h>
// components
const int rs = 12, en = 11, d4 = 6, d5 = 5, d6 = 4, d7 = 3;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
int btnStart = 10, btnDash = 9;
// joystick
int joystickX = A0, joystickY = A1, joystickB = 2;
int JOYSTICK_MIN = 1023, JOYSTICK_MAX = 0;
// game variables
bool gravity = true;
bool canToggle = false;
bool isGameOver = true;
int spawner = 0;
int score = 0;
// anim frames
byte playerChar_right[] = {
B00000,
B00000,
B00000,
B01111,
B11001,
B11111,
B01111,
B01001 };
byte playerChar_right1[] = {
B00000,
B00000,
B01111,
B11001,
B11111,
B01111,
B01001,
B00000 };
byte playerChar_left[] = {
B00000,
B00000,
B00000,
B11110,
B10011,
B11111,
B11110,
B10010 };
byte playerChar_left1[] = {
B00000,
B00000,
B11110,
B10011,
B11111,
B11110,
B10010,
B00000 };
byte cuboidChar[] = {
B00000,
B00000,
B00000,
B11111,
B10101,
B11111,
B01011,
B11000 };
byte cuboidChar1[] = {
B00000,
B00000,
B00000,
B11111,
B10101,
B11111,
B11001,
B00011 };
byte batChar[] = {
B00000,
B10001,
B01010,
B00100,
B00000,
B00000,
B00000,
B00000 };
byte batChar1[] = {
B00000,
B00000,
B00100,
B01010,
B10001,
B00000,
B00000,
B00000 };
byte skullChar[] = {
B00000,
B00000,
B01110,
B10101,
B11011,
B01110,
B01110,
B00000 };
// graphics
int PLAYER_CHAR_RIGHT = 1,
PLAYER_CHAR_RIGHT1 = 1,
PLAYER_CHAR_LEFT = 2,
PLAYER_CHAR_LEFT1 = 2,
CUBOID_CHAR = 3,
CUBOID_CHAR1 = 4,
BAT_CHAR = 5,
BAT_CHAR1 = 6,
SKULL_CHAR = 7;
void lcdPrint(int x, int y, String str) {
lcd.setCursor(x, y);
lcd.print(str);
}
class Player {
public:
int x = 2, y = 1, anim = 0, direction = 1; // direction 1 = right, 0 = left;
bool canDash = true;
void reset() {
// reset self
lcdPrint(x, y, " ");
x = 1, y = 1, anim = 0, direction = 1;
}
void render() {
// erase current player position
lcdPrint(x, y, " ");
// horizontal axis handler
if (analogRead(joystickX) == JOYSTICK_MIN && x > 0){
x--;
direction = 0;
}
if (analogRead(joystickX) == JOYSTICK_MAX && x < 14){
x++;
direction = 1;
}
// vertical axis handler
if (analogRead(joystickY) == JOYSTICK_MIN && y > 0){
y--;
}
if (analogRead(joystickY) == JOYSTICK_MAX && y < 1){
y++;
}
if (digitalRead(btnDash) == LOW && canDash) {
if (direction == 1) {
x+=3;
if (x > 15) {
x = 15;
}
}
else {
x-=3;
if (x < 0) {
x = 0;
}
}
canDash = false;
}
if (digitalRead(btnDash) == HIGH && !canDash) {
canDash = true;
}
// write new player position
lcd.setCursor(x, y);
// assign animation frame
anim++;
if (anim > 5) {
anim = 0;
}
if (anim < 3) {
if (direction == 1){
lcd.write(byte(PLAYER_CHAR_RIGHT));
}
else {
lcd.write(byte(PLAYER_CHAR_LEFT));
}
}
else {
if (direction == 1){
lcd.write(byte(PLAYER_CHAR_RIGHT1));
}
else {
lcd.write(byte(PLAYER_CHAR_LEFT1));
}
}
}
};
Player player;
class Cuboid {
private:
int x = 16, y = 1, anim = 0, cycle = 0; // 1 cycle = 100ms
public:
void reset() {
// reset self
lcdPrint(x, y, " ");
x = 16, y = 1, anim = 0, cycle = 0, spawner = 0;
}
void render(){
cycle++;
if (cycle >= 3){
// reset cycle
cycle = 0;
// erase current position
lcdPrint(x, y, " ");
// assign new position
x--;
if (x < 0) {
score += 7;
x = 16;
y = player.y;
}
lcd.setCursor(x, y);
// render animation frame
if (anim == 0) {
lcd.write(byte(CUBOID_CHAR));
anim = 1;
}
else {
lcd.write(byte(CUBOID_CHAR1));
anim = 0;
}
}
// on collision with player
if (x == player.x && y == player.y) {
isGameOver = true;
}
}
};
Cuboid cuboid, cuboid2;
class Bat {
private:
int x = 16, y = 1, anim = 0, cycle = 0; // 1 cycle = 100ms
public:
void reset() {
// reset self
lcdPrint(x, y, " ");
x = 16, y = 1, anim = 0, cycle = 0, spawner = 0;
}
void render(){
cycle++;
// begin move
if (cycle >= 5) {
// erase current position
lcdPrint(x, y, " ");
// reset cycle
cycle = 0;
if (y == 0) {
y = 1;
}
else {
y = 0;
}
x--;
if (x < 0) {
score += 13;
x = 16;
y = player.y;
}
}
// end move
// begin animate
if (cycle % 2 == 0){
lcd.setCursor(x, y);
if (anim == 0) {
lcd.write(byte(BAT_CHAR));
anim = 1;
}
else {
lcd.write(byte(BAT_CHAR1));
anim = 0;
}
}
// end animate
// begin collision detection
if (x == player.x && y == player.y) {
isGameOver = true;
}
// end collision detection
}
};
Bat bat, bat2;
class Skull {
private:
int x = 16, y = 0, anim = 0, cycle = 0; // 1 cycle = 100ms
public:
void reset() {
// reset self
lcdPrint(x, y, " ");
x = 16, y = 0, anim = 0, cycle = 0, spawner = 0;
}
void render(int paramY){
y = paramY;
cycle++;
// begin move
if (cycle >= 7) {
// erase current position
lcdPrint(x, y, " ");
// reset cycle
cycle = 0;
x--;
if (x < 0) {
score += 9;
x = 20;
}
// render
lcd.setCursor(x, y);
lcd.write(byte(SKULL_CHAR));
}
// end move
// begin collision detection
if (x == player.x && y == player.y) {
isGameOver = true;
}
// end collision detection
}
};
Skull skull, skull2;
void setup() {
// render graphics
lcd.createChar(PLAYER_CHAR_RIGHT, playerChar_right);
lcd.createChar(PLAYER_CHAR_RIGHT1, playerChar_right1);
lcd.createChar(PLAYER_CHAR_LEFT, playerChar_left);
lcd.createChar(PLAYER_CHAR_LEFT1, playerChar_left1);
lcd.createChar(CUBOID_CHAR, cuboidChar);
lcd.createChar(CUBOID_CHAR1, cuboidChar1);
lcd.createChar(BAT_CHAR, batChar);
lcd.createChar(BAT_CHAR1, batChar1);
lcd.createChar(SKULL_CHAR, skullChar);
pinMode(13, INPUT);
lcd.begin(16, 2);
}
void printScore(){
if (score < 9) {
lcd.setCursor(13, 1);
lcd.print(score);
}
else if (score < 99) {
lcd.setCursor(12, 1);
lcd.print(score);
}
else if (score < 999) {
lcd.setCursor(11, 1);
lcd.print(score);
}
else if (score < 9999) {
lcd.setCursor(10, 1);
lcd.print(score);
}
}
void loop() {
if (digitalRead(btnStart) == LOW && isGameOver) {
lcdPrint(2, 0, " ");
lcdPrint(2, 1, " ");
isGameOver = false;
score = 0;
delay(100);
}
if (!isGameOver) {
// game running ---------------------------
spawner++;
player.render();
if (spawner > 2) {
cuboid.render();
}
if (spawner > 80) {
cuboid2.render();
}
if (spawner > 130) {
bat.render();
}
if (spawner > 180) {
bat2.render();
}
if (spawner > 258) {
skull.render(0);
skull2.render(1);
}
delay(100);
// game running ---------------------------
}
else if (isGameOver) {
lcdPrint(2, 0, "PRESS START!");
lcdPrint(2, 1, "SCORE:");
printScore();
spawner = 0;
player.reset();
cuboid.reset();
cuboid2.reset();
bat.reset();
bat2.reset();
skull.reset();
skull2.reset();
}
}