Note
Hello, welcome to the SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts Community on Facebook! Dive deeper into Raspberry Pi, Arduino, and ESP32 with fellow enthusiasts.
Why Join?
Expert Support: Solve post-sale issues and technical challenges with help from our community and team.
Learn & Share: Exchange tips and tutorials to enhance your skills.
Exclusive Previews: Get early access to new product announcements and sneak peeks.
Special Discounts: Enjoy exclusive discounts on our newest products.
Festive Promotions and Giveaways: Take part in giveaways and holiday promotions.
👉 Ready to explore and create with us? Click [here] and join today!
GAME - Pong
This is a simple Pong game designed using an OLED display and an Arduino board. In the Pong game, players compete against the computer, controlling a vertical paddle to bounce back a bouncing ball. The goal is to prevent the ball from passing your paddle’s edge, or else the opponent scores.
The game mechanics can be divided into the following parts:
Ball Movement - The ball moves along its current direction at a set speed. Whenever the ball collides with a paddle, its speed increases, making the game more challenging.
Paddle Movement - Used to block the ball’s movement, the paddle can move up or down. Players control their own paddle using buttons, while the computer’s paddle automatically follows the ball’s position.
Scoring - Whenever the ball goes beyond the left or right edge of the screen, the corresponding player or CPU scores.
Required Components
In this project, we need the following components.
It’s definitely convenient to buy a whole kit, here’s the link:
Name |
ITEMS IN THIS KIT |
LINK |
|---|---|---|
Elite Explorer Kit |
300+ |
You can also buy them separately from the links below.
COMPONENT INTRODUCTION |
PURCHASE LINK |
|---|---|
- |
|
- |
Wiring
Note
To protect the Power Supply Module’s battery, please fully charge it before using it for the first time.
Schematic
Code
Note
You can open the file
12_pong_oled.inounder the path ofelite-explorer-kit-main\fun_project\12_pong_oleddirectly.Or copy this code into Arduino IDE.
Note
To install the library, use the Arduino Library Manager and search for “Adafruit SSD1306” and “Adafruit GFX” and install them.
1/*
2 This code creates a basic Pong game using an Arduino Uno, an OLED display,
3 and buttons. Players use the buttons to control a vertical paddle and bounce
4 back a moving ball to prevent it from passing their paddle. Scoring happens
5 when the ball goes off the screen edges.
6
7 Board: Arduino Uno R4
8 Component: OLED Display Module and Button
9 Library: https://github.com/adafruit/Adafruit_SSD1306 (Adafruit SSD1306 by Adafruit)
10 https://github.com/adafruit/Adafruit-GFX-Library (Adafruit GFX Library by Adafruit)
11*/
12
13
14#include <SPI.h>
15#include <Wire.h>
16#include <Adafruit_GFX.h>
17#include <Adafruit_SSD1306.h>
18
19#define UP_BUTTON 3
20#define DOWN_BUTTON 2
21
22#define SCREEN_WIDTH 128 // OLED display width, in pixels
23#define SCREEN_HEIGHT 64 // OLED display height, in pixels
24
25// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
26#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
27Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
28
29// ball set
30const unsigned long BALL_RATE = 16;
31int ball_x = 64, ball_y = 32;
32int ball_speed = 1;
33int8_t ball_dir_x = 1, ball_dir_y = 1;
34
35//flash rate
36unsigned long ball_update;
37unsigned long paddle_update;
38
39// paddle set
40const unsigned long PADDLE_RATE = 33;
41const uint8_t PADDLE_HEIGHT = 16;
42const uint8_t CPU_X = 12;
43int8_t cpu_y = 16;
44const uint8_t PLAYER_X = 115;
45int8_t player_y = 16;
46int paddle_speed = 3;
47
48// score
49uint8_t player_score = 0;
50uint8_t cpu_score = 0;
51
52
53void setup() {
54 Serial.begin(115200);
55
56 randomSeed(analogRead(A0));
57 ball_dir_x = random(0, 2) * 2 - 1;
58 ball_dir_y = random(0, 2) * 2 - 1;
59
60 display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
61 display.display();
62
63 pinMode(UP_BUTTON, INPUT);
64 pinMode(DOWN_BUTTON, INPUT);
65
66 unsigned long start = millis();
67
68 display.clearDisplay();
69 drawCourt();
70
71 while (millis() - start < 2000)
72 ;
73
74 displayScore();
75 display.display();
76
77 ball_update = millis();
78 paddle_update = ball_update;
79}
80
81void loop() {
82 bool update = false;
83 unsigned long time = millis();
84
85 static bool up_state = false;
86 static bool down_state = false;
87
88 /* check if the button pressed */
89 up_state |= (digitalRead(UP_BUTTON) == LOW);
90 down_state |= (digitalRead(DOWN_BUTTON) == LOW);
91
92 /* refresh the ball */
93 if (time > ball_update) {
94 int new_x = ball_x + ball_dir_x * ball_speed;
95 int8_t new_y = ball_y + ball_dir_y * ball_speed;
96
97 // Check if it hits the horizontal walls.
98 if (new_y <= 0 || new_y >= SCREEN_HEIGHT - 1) {
99 ball_dir_y = -ball_dir_y;
100 new_y += ball_dir_y + ball_dir_y * ball_speed;
101 displayScore();
102 }
103
104 // Check if it hits the CPU paddle
105 if (crossesCpuPaddle(ball_x, new_x, ball_y)) {
106 ball_dir_x = -ball_dir_x;
107 new_x = CPU_X + 1;// move the ball's position to the left edge of the paddle
108 ball_speed++; // speeds up
109 }
110
111 // Check if it hits the player paddle
112 if (crossesPlayerPaddle(ball_x, new_x, ball_y)) {
113 ball_dir_x = -ball_dir_x;
114 new_x = PLAYER_X - 1; // move the ball's position to the right edge of the paddle
115 ball_speed++; // speeds up
116 }
117
118 // Check if it hits the vertical walls
119 if (new_x <= 0 || new_x >= SCREEN_WIDTH - 1) {
120 if (new_x <= 1) {
121 player_score++;
122 }
123 if (new_x >= 126) {
124 cpu_score++;
125 }
126 /* reset ball */
127 displayScore();
128 ball_speed = 1; // reset speed
129 new_x = 64; // reset position
130 // new_y = 32;
131 ball_dir_x = (ball_dir_x > 0) ? -1 : 1; // reset direction
132 ball_dir_y = (random(0, 2) == 0) ? 1 : -1; // reset direction
133 }
134
135 display.drawPixel(ball_x, ball_y, BLACK);
136 display.drawPixel(new_x, new_y, WHITE);
137 ball_x = new_x;
138 ball_y = new_y;
139
140 ball_update += BALL_RATE; // next refresh time
141 update = true;
142 }
143
144 /* refresh paddles */
145 if (time > paddle_update) {
146 paddle_update += PADDLE_RATE; // next refresh time
147
148 // CPU paddle
149 display.drawFastVLine(CPU_X, cpu_y, PADDLE_HEIGHT, BLACK); //clear paddle
150 const uint8_t half_paddle = PADDLE_HEIGHT >> 1;
151 if (cpu_y + half_paddle > ball_y) {
152 cpu_y -= paddle_speed;
153 }
154 if (cpu_y + half_paddle < ball_y) {
155 cpu_y += paddle_speed;
156 }
157 // constraint position
158 if (cpu_y < 1) cpu_y = 1;
159 if (cpu_y + PADDLE_HEIGHT > 63) cpu_y = 63 - PADDLE_HEIGHT;
160 display.drawFastVLine(CPU_X, cpu_y, PADDLE_HEIGHT, WHITE); //show paddle
161
162 // Player paddle
163 display.drawFastVLine(PLAYER_X, player_y, PADDLE_HEIGHT, BLACK); //clear paddle
164 if (up_state) {
165 player_y -= paddle_speed;
166 }
167 if (down_state) {
168 player_y += paddle_speed;
169 }
170 up_state = down_state = false;
171 // constraint position
172 if (player_y < 1) player_y = 1;
173 if (player_y + PADDLE_HEIGHT > 63) player_y = 63 - PADDLE_HEIGHT;
174 display.drawFastVLine(PLAYER_X, player_y, PADDLE_HEIGHT, WHITE); //show paddle
175 update = true;
176 }
177
178 if (update)
179 display.display();
180}
181
182bool crossesPlayerPaddle(uint8_t old_x, uint8_t new_x, uint8_t ball_y) {
183 return old_x < PLAYER_X && new_x >= PLAYER_X && ball_y >= player_y && ball_y <= player_y + PADDLE_HEIGHT;
184}
185
186bool crossesCpuPaddle(uint8_t old_x, uint8_t new_x, uint8_t ball_y) {
187 return old_x > CPU_X && new_x <= CPU_X && ball_y >= cpu_y && ball_y <= cpu_y + PADDLE_HEIGHT;
188}
189
190void drawCourt() {
191 display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, WHITE);
192}
193
194void displayScore() {
195 display.fillRect(SCREEN_WIDTH / 2 - 20, 10, 60, 10, BLACK);// clear
196
197 display.setCursor(SCREEN_WIDTH / 2 - 20, 10);
198 display.setTextSize(1);
199 display.setTextColor(WHITE);
200
201 display.print(cpu_score);
202 display.print(" - ");
203 display.print(player_score);
204}
How it works?
The program structure can be divided into the following five parts:
Import Necessary Libraries - Used to control the OLED screen and read button inputs.
Define Constants and Global Variables:
Definitions for OLED screen width and height. Definitions for buttons and OLED reset pins. Position, speed, size, and direction of the ball and paddles. Scores for player and CPU.
Initialization:
Initialize serial communication, the OLED screen, and display the initial interface. Set buttons as inputs and connect pull-up resistors. Draw the playing field.
Main Loop:
Read button states. Move the ball based on the set refresh rate. Detect collisions between the ball and paddles or walls, adjusting the ball’s direction and speed accordingly. Update the screen with scores based on scoring events. Refresh paddle positions.
Additional Functions:
crossesPlayerPaddleandcrossesCpuPaddle- Used to detect whether the ball collides with the player’s or CPU’s paddle.drawCourt- Draws the playing field on the OLED screen.displayScore- Displays the player’s and CPU’s scores on the screen.