Making a game
Now that we can detect joystick presses and output to the OLED display, we’ve got all we need to make a simple game.
The code below is a simplified version of Flappy Bird where you have to push the joystick to jump through gaps in pipes that scroll across the screen.
#include <OLEDDisplay.h>
#include <SSD1306.h>
// connect to display using pins D1, D2 for I2C on address 0x3c
SSD1306 display(0x3c, D1, D2);
// flappy dot variables
int x, y, score;
float fy = 0;
float velocity = 0;
float gravity = 0.4;
// joystick pins and presses
byte joystick_pins[] = {D3, D5, D6, D7};
byte joystick_buttons[] = {0, 0, 0, 0};
// joystick pin order constants
const byte JOY_RIGHT = 0;
const byte JOY_PUSH = 1;
const byte JOY_DOWN = 2;
const byte JOY_UP = 3;
// Draws and manages a pipe obstacle (top and bottom)
class Pipe {
public:
int x,y,gap;
// create a new pipe
Pipe(int x, int y, int gap){
this->x = x;
this->y = y;
this->gap = gap;
}
// draw the pipe to the OLED screen
void draw() {
// bottom pipe
display.drawRect(x, y, 2, 63 - y);
display.drawRect(x-2, y-2, 6, 2);
// top pipe
display.drawRect(x, 0, 2, y - gap);
display.drawRect(x-2, y-gap-2, 6, 2);
}
// move the pipe 1px left
void move() {
x--;
if(x < 0) {
x = 128;
y = random(32, 64);
gap = random(20, 40);
}
}
// check if the dot has collided with this pipe
bool hitTest(int birdX, int birdY) {
return (x == birdX) && ((birdY > y) || (birdY < y - gap));
}
};
void onJoystickChange() {
Serial.print("Joystick: ");
for(int i = 0; i < sizeof(joystick_pins); i++) {
joystick_buttons[i] = !digitalRead(joystick_pins[i]);
Serial.print(joystick_buttons[i]);
}
Serial.println();
}
// Create two pipes
Pipe *p1;
Pipe *p2;
void setup() {
p1 = new Pipe(64, 25, 30);
p2 = new Pipe(128, 64, 30);
// init serial port
Serial.begin(115200);
// set the builtin LED pin to work as an output
pinMode(LED_BUILTIN, OUTPUT);
for(int i = 0; i < sizeof(joystick_pins); i++) {
pinMode(joystick_pins[i], INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(joystick_pins[i]), onJoystickChange, CHANGE);
}
// init the display
display.init();
// set text x and y coordinate to start at 0
x = 0;
y = 0;
}
bool playing = true;
void loop() {
// clear the screen
display.clear();
// display score
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.setFont(ArialMT_Plain_10);
String str_score = "Score: ";
str_score += score;
display.drawString(0, 0, str_score);
display.setPixel(x, y);
// main game actions
if(playing) {
// push joystick to jump
if(joystick_buttons[JOY_PUSH]) velocity = 5;
// make dot fall
velocity -= gravity;
if(velocity < -10) velocity = -10;
fy -= (velocity / 10);
if(fy > 63) fy = 63;
if(fy < 0) fy = 0;
y = (int)fy;
// make sure x and y are valid numbers
if(x > 128) x = 128;
if(x < 0) x = 0;
// draw pipes
p1->draw();
if(p1->hitTest(x, y)) {
playing = false;
} else {
p1->move();
}
p2->draw();
if(p2->hitTest(x, y)) {
playing = false;
} else {
p2->move();
}
score++;
} else {
// game over
display.drawString(0, 20, "Game over");
}
// update the display
display.display();
// slow down loop
delay(10);
}
If this code is useful or you have any questions, please leave a comment below.
Enjoy!
thank you very much for your help 🙂 I couldnt make it work without that
Hiyah!
The directional buttons: FLATH, RSET, D5, D6, D7
What on earth is FLATH?
Also – won’t RSET reset the board when the “direction” is pressed on the little joystick?
Yes, because of the way the joystick is connected up, the board will reset when you press left. I don’t know what FLATH is: it’s on all the description pages when you try to buy it but the joystick is actually connected to D3,D5,D6,D7 (and RSET). Maybe there’s a way to disable the reset-not sure-sorry!
I’m pretty sure FLATH is nothing but a typo from the first and original description (that has been copied wrongly every time)
This is the FLASH button. In order to FLASH another binary (firmware) this button has to be pressed while turning power ON.