A Bluetooth Low Energy multiplayer Pong game designed for custom Arduino controllers.
| Version | Description | Link |
|---|---|---|
| CC25 | Creation & Computation 2025 | Play |
| PhysComp26-501 | Physical Computing 2026 - Section 501 | Play |
| PhysComp26-502 | Physical Computing 2026 - Section 502 | Play |
DF Pong is a browser-based Pong game that allows players to create and connect custom Bluetooth Low Energy (BLE) controllers using Arduino Nano 33 IoT boards. The game supports 0, 1, or 2 BLE controllers, with keyboard fallback for any unconnected players. Designed for classroom environments with up to 25 active devices, it uses a unique UUID-based filtering system to ensure reliable connections even in crowded Bluetooth environments.
Key Features:
- Connect custom Arduino BLE controllers to play Pong in the browser
- Supports 0-2 controllers (keyboard controls available for unconnected players)
- Unique device identification system for classroom use (1-25 players)
- Configurable player names and device assignments
- Mobile and desktop support
- Real-time debug controls for game tuning
With 0 Controllers (Keyboard Only):
- Player 1:
A(up) /Z(down) or use on-screen arrow buttons - Player 2:
P(up) /L(down) or use on-screen arrow buttons - Click START button to begin
- Click PAUSE during game, then RESUME or RESET
With 1 Controller:
- One player uses their custom BLE controller
- Other player uses keyboard or on-screen arrow buttons
- On-screen controls automatically hide for connected players
With 2 Controllers:
- Both players use custom BLE controllers
- All on-screen paddle controls automatically hide
| Action | Desktop | Mobile |
|---|---|---|
| Start/Pause/Resume Game | Click START/PAUSE/RESUME button | Tap START/PAUSE/RESUME button |
| Reset Game | ENTER or RESET button (when paused) |
RESET button (when paused) |
| Control Paddles | Arrow buttons (left/right side of screen) | Arrow buttons (edges of screen) |
| Toggle BLE Debug | d key |
(Not available on mobile) |
| Toggle Game Settings | c key or Settings button |
Settings button |
BLE Debug (d key):
- Shows connection status
- Displays real-time data from controllers
- Useful for troubleshooting connectivity
Game Settings (c key):
- Player 1/2 Move Speed: Adjust paddle responsiveness (1-100)
- Puck Speed: Set base speed of the ball (1-20)
- Winning Score: Set points needed to win (default: 10)
All settings persist in browser's local storage.
The easiest way to create a controller is using the DFPongController Arduino Library.
Install the Library:
- Open Arduino IDE
- Go to Sketch > Include Library > Manage Libraries...
- Search for "DFPongController"
- Click Install
Supported Boards:
- Arduino UNO R4 WiFi
- Arduino Nano 33 IoT
- Arduino Nano 33 BLE / BLE Sense
- ESP32 / ESP32-S3 / ESP32-C3 (requires NimBLE-Arduino library)
Quick Start:
#include <DFPongController.h>
DFPongController controller;
void setup() {
pinMode(2, INPUT_PULLUP); // UP button
pinMode(3, INPUT_PULLUP); // DOWN button
controller.setControllerNumber(1); // ← CHANGE THIS (1-242)
controller.setStatusLED(LED_BUILTIN);
controller.begin();
}
void loop() {
controller.update(); // Required every loop!
if (!digitalRead(2)) {
controller.sendControl(UP);
} else if (!digitalRead(3)) {
controller.sendControl(DOWN);
} else {
controller.sendControl(NEUTRAL);
}
}See library examples in controller/examples/BLE/DFpong_Library_TwoButton/ and controller/examples/BLE/DFpong_Library_StartTemplate/.
For more control or learning purposes, you can use the raw BLE examples:
- Open
controller/examples/BLE/DFpong_controller_2button/DFpong_controller_2button.ino - Find this line at the top:
const int DEVICE_NUMBER = 1; // ← CHANGE THIS!
- Change the number to your assigned device (1-242)
- Upload the sketch to your Arduino
Important: Remember your controller number - you'll use it to connect!
Before playing a game, test your controller is working:
- Go to the Controller Test Page
- Select your controller number from the dropdown
- Click "Connect"
- Verify your controller inputs move the paddle
- Go to your class's game URL (see Game Versions above)
- Select your controller number from the dropdown (e.g., "1: Your Name")
- Click "Connect"
- Select your Arduino from the browser's Bluetooth picker
- The button will turn green and say "Disconnect" when connected
Each game version has its own players-config.json file. Edit the one in your version's folder (e.g., game/cc25/players-config.json):
{
"players": [
{ "deviceNumber": 1, "name": "Alice Smith" },
{ "deviceNumber": 2, "name": "Bob Jones" },
{ "deviceNumber": 3, "name": "Carol White" }
]
}Configuration Options:
- Dropdown display: Shows
"1: Alice Smith","2: Bob Jones", etc. - In-game display: Shows only the name:
"Alice Smith"vs"Bob Jones" - Number of players: Determined by array length (add/remove entries as needed)
- Changes take effect on page refresh
In a classroom with 25 Arduino devices broadcasting Bluetooth simultaneously, traditional device name filtering fails:
- Browser Caching: Web browsers cache paired device names
- Generic Names: Previously paired devices may show as "Arduino-Paired" instead of their custom names
- Name Collisions: Multiple devices can appear identical in the connection dialog
- Trial and Error: Players can't reliably identify which physical device is theirs
Instead of relying on device names, each Arduino generates a unique Bluetooth Service UUID based on its device number:
Base UUID: 19b10010-e8f2-537e-4f6c-d104768a12
Suffix Calculation: hex(13 + deviceNumber)
Device 1: 19b10010-e8f2-537e-4f6c-d104768a120e (13 + 1 = 14 = 0x0E)
Device 2: 19b10010-e8f2-537e-4f6c-d104768a120f (13 + 2 = 15 = 0x0F)
Device 25: 19b10010-e8f2-537e-4f6c-d104768a1227 (13 + 25 = 38 = 0x27)
Why add 13? The base UUID ends in 12 (hex), so adding 13 ensures device UUIDs start at 0E (14 in decimal). This creates a contiguous range (0E through 27) that's visually distinct from the base and avoids potential conflicts with reserved or commonly-used UUID suffixes in the 0x00-0x0D range.
When a person selects their device number from the dropdown:
-
JavaScript generates the matching UUID:
const deviceNumber = 1; const suffix = (13 + deviceNumber).toString(16); // "0e" const uuid = "19b10010-e8f2-537e-4f6c-d104768a12" + suffix;
-
Web Bluetooth API requests only that specific UUID:
navigator.bluetooth.requestDevice({ filters: [{ services: [uuid] }] })
-
Browser shows only matching devices: Typically just one
- Unique Hardware Identifier: Each device broadcasts a different UUID at the hardware level
- Browser-Agnostic: Works regardless of name caching or pairing history
- No Ambiguity: Only one device will match the requested UUID
- Reliable: Players always connect to their assigned device, first time, every time
Arduino Side (ble_functions.h):
void generateUUIDs(int deviceNumber) {
int suffix = 13 + deviceNumber;
String hexSuffix = String(suffix, HEX);
serviceUuidStr = "19b10010-e8f2-537e-4f6c-d104768a12" + hexSuffix;
// Advertise this unique service UUID
}JavaScript Side (bleController.js):
generateServiceUUID(deviceNumber) {
const suffix = (13 + deviceNumber).toString(16).padStart(2, '0');
return "19b10010-e8f2-537e-4f6c-d104768a12" + suffix;
}- Puck: Ball that bounces off paddles and edges, speeds up with each hit
- Paddles: Player-controlled vertical bars, scale responsively to canvas size
- GameController: Manages game states (waiting, playing, paused, won)
- BLEController: Handles UUID generation, device filtering, and connection management
game/
├── index.html # Main entry point
├── sketch.js # p5.js game loop and canvas management
├── gameController.js # Game state and scoring logic
├── bleController.js # BLE connection and UUID filtering
├── paddle.js # Paddle physics and rendering
├── puck.js # Ball physics and collision detection
├── players-config.json # Device-to-name mapping
└── style.css # Responsive layout (desktop/mobile)
controller/examples/BLE/
├── DFpong_controller_2button/ # Complete 2-button example
│ ├── DFpong_controller_2button.ino
│ ├── ble_functions.h # UUID generation and BLE setup
│ └── buzzer_functions.h # Audio feedback
└── DFpong_controller_startTemplate/ # Starter template for custom controllers
├── DFpong_controller_startTemplate.ino
├── ble_functions.h
└── buzzer_functions.h
- p5.js
- p5.sound.js: Audio support
- p5.ble.js (v0.0.7): Web Bluetooth API wrapper
- p5-phone (v1.5.0): Mobile debugging with on-screen console
- ArduinoBLE (Arduino): Bluetooth Low Energy library for Arduino Nano 33 IoT
Use the template in controller/examples/BLE/DFpong_controller_startTemplate/ to build your own controller:
- Set your
DEVICE_NUMBER - Implement
handleInput()to read your sensors - Set
currentMovementto:0= Stop/neutral1= Move paddle UP2= Move paddle DOWN
- Upload and connect!
Example sensors:
- Buttons, joysticks, accelerometers
- Light sensors, distance sensors, potentiometers
- Capacitive touch, flex sensors, pressure sensors
- Anything that can produce distinct UP/DOWN/NEUTRAL states!
Controller won't connect:
- Verify
DEVICE_NUMBERis set (1-25) - Check Arduino is powered and LED is blinking
- Try refreshing the browser page
- Check browser console for errors (press
dfor debug info)
Wrong controller connects:
- Verify you selected the correct device number from dropdown
- Each controller must have a unique
DEVICE_NUMBER - Check Serial Monitor to confirm UUID is correct
Game is too fast/slow:
- Press
cto open game settings - Adjust paddle speed and puck speed to your preference
- Settings are saved automatically
For detailed controller setup and examples:
https://github.com/DigitalFuturesOCADU/Pong-Controller
MIT License - See LICENSE file for details
