Pong Game

Image of capacitative sensor
Project Date March 9th, 2023
Elements Circuitry, Arduino
Is it cool? Yes
Inspiration My Childhood

Materials

  • Arduino Uno
  • Breadboard
  • Wires
  • Arduino IDE Software
  • Poscilloscope

Introduction

I wanted to try my hand at using the OLED screen, provided that I think this would be nice to include in my final project in some way. I had the idea to create a game, which seemed to work out!

The Process

For this project, I started first by building the circuit, including wiring for the OLED screen and two controls, which would help operate the "up" and "down" mechanics within the Pong game. From here, I wanted to first figure out how to use the OLED screen, so I used the demo program. See below!

Sensor schematic

From here, I uploaded the following code to Arudino, which would be the Pong game!


                    /*
                    A simple Pong game:
                    */

                    #include 
                    #include 
                    #include 
                    #include 

                    #define UP_BUTTON 2
                    #define DOWN_BUTTON 3

                    const unsigned long PADDLE_RATE = 33;
                    const unsigned long BALL_RATE = 16;
                    const uint8_t PADDLE_HEIGHT = 24;

                    #define SCREEN_WIDTH 128 // OLED display width, in pixels
                    #define SCREEN_HEIGHT 64 // OLED display height, in pixels

                    // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
                    #define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
                    Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

                    void drawCourt();

                    uint8_t ball_x = 64, ball_y = 32;
                    uint8_t ball_dir_x = 1, ball_dir_y = 1;
                    unsigned long ball_update;

                    unsigned long paddle_update;
                    const uint8_t CPU_X = 12;
                    uint8_t cpu_y = 16;

                    const uint8_t PLAYER_X = 115;
                    uint8_t player_y = 16;

                    void setup() {
                    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

                    
                    display.display();
                    unsigned long start = millis();

                    pinMode(UP_BUTTON, INPUT);
                    pinMode(DOWN_BUTTON, INPUT);
                    digitalWrite(UP_BUTTON,1);
                    digitalWrite(DOWN_BUTTON,1);
                    display.clearDisplay();
                    drawCourt();

                    while(millis() - start < 2000);

                    display.display();

                    ball_update = millis();
                    paddle_update = ball_update;
                    }

                    void loop() {
                    bool update = false;
                    unsigned long time = millis();

                    static bool up_state = false;
                    static bool down_state = false;
                    
                    up_state |= (digitalRead(UP_BUTTON) == LOW);
                    down_state |= (digitalRead(DOWN_BUTTON) == LOW);

                    if(time > ball_update) {
                        uint8_t new_x = ball_x + ball_dir_x;
                        uint8_t new_y = ball_y + ball_dir_y;

                        // Check if we hit the vertical walls
                        if(new_x == 0 || new_x == 127) {
                            ball_dir_x = -ball_dir_x;
                            new_x += ball_dir_x + ball_dir_x;
                        }

                        // Check if we hit the horizontal walls.
                        if(new_y == 0 || new_y == 63) {
                            ball_dir_y = -ball_dir_y;
                            new_y += ball_dir_y + ball_dir_y;
                        }

                        // Check if we hit the CPU paddle
                        if(new_x == CPU_X && new_y >= cpu_y && new_y <= cpu_y + PADDLE_HEIGHT) {
                            ball_dir_x = -ball_dir_x;
                            new_x += ball_dir_x + ball_dir_x;
                        }

                        // Check if we hit the player paddle
                        if(new_x == PLAYER_X
                            && new_y >= player_y
                            && new_y <= player_y + PADDLE_HEIGHT)
                        {
                            ball_dir_x = -ball_dir_x;
                            new_x += ball_dir_x + ball_dir_x;
                        }

                        display.drawPixel(ball_x, ball_y, BLACK);
                        display.drawPixel(new_x, new_y, WHITE);
                        ball_x = new_x;
                        ball_y = new_y;

                        ball_update += BALL_RATE;

                        update = true;
                    }

                    if(time > paddle_update) {
                        paddle_update += PADDLE_RATE;

                        // CPU paddle
                        display.drawFastVLine(CPU_X, cpu_y, PADDLE_HEIGHT, BLACK);
                        const uint8_t half_paddle = PADDLE_HEIGHT >> 1;
                        if(cpu_y + half_paddle > ball_y) {
                            cpu_y -= 1;
                        }
                        if(cpu_y + half_paddle < ball_y) {
                            cpu_y += 1;
                        }
                        if(cpu_y < 1) cpu_y = 1;
                        if(cpu_y + PADDLE_HEIGHT > 63) cpu_y = 63 - PADDLE_HEIGHT;
                        display.drawFastVLine(CPU_X, cpu_y, PADDLE_HEIGHT, WHITE);

                        // Player paddle
                        display.drawFastVLine(PLAYER_X, player_y, PADDLE_HEIGHT, BLACK);
                        if(up_state) {
                            player_y -= 1;
                        }
                        if(down_state) {
                            player_y += 1;
                        }
                        up_state = down_state = false;
                        if(player_y < 1) player_y = 1;
                        if(player_y + PADDLE_HEIGHT > 63) player_y = 63 - PADDLE_HEIGHT;
                        display.drawFastVLine(PLAYER_X, player_y, PADDLE_HEIGHT, WHITE);

                        update = true;
                    }

                    if(update)
                        display.display();
                    }


                    void drawCourt() {
                    display.drawRect(0, 0, 128, 64, WHITE);
                    }
                  

I then turned to using the oscilloscope to discover the time domain at which your output device is operating. It seemed to be running on a fixed clock, with a speed of roughly 20 µs. Shoutout to Ibrahim for helping me visualize this! It seems to be quite fast, and I had to toy around a bit with the different controls.

plot