Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Ball.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ void Ball::hit() {
increase_speed();
}

void Ball::increase_initial_speed() {
this->initial_speed = 0.6;
}

void Ball::calc_speedup(Player &player) {
speedup = distance_to_field_boundary(player)/10.0;
}
Expand Down
1 change: 1 addition & 0 deletions Ball.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class Ball {
void hit();
void advance();

void increase_initial_speed();
void calc_speedup(Player &player);
void reset_speedup();
void serve(Player player);
Expand Down
26 changes: 22 additions & 4 deletions Pong.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ Pong::Pong(uint8_t player_1_pin, uint8_t player_2_pin, uint8_t lifes, uint16_t b
player_2(lifes, num_leds-lifes, num_leds-1, player_2_pin, button_lock_time, CRGB::Blue, CRGB::Red),
screen(num_leds, brightness),
restart(restart_pin, restart_lock_time),
ball(0, 0, num_leds-1, 0.2, 1)
ball(0, 0, num_leds-1, 0.2, 1) // 0.2 is the inital speed. An option has been added in Ball.cpp to start with higher speed.
{
players[0] = &player_1;
players[1] = &player_2;
state = WAITING;
auto_serve_timeout = 2000;
position_is_allowed = false;
waiting_time = millis();
isFirstRun = true;
randomSeed(analogRead(random_seed_pin));
}

Expand All @@ -48,7 +49,7 @@ void Pong::prepare_next_serve() {
void Pong::choose_random_player() {
// randomly select active player to serve the first ball
active_player = random(0,2);
ball.set_position((active_player) ? -1 : 60);
ball.set_position((active_player) ? players[0]->hitbox_min -1 : players[1]->hitbox_max +1);
ball.set_direction((active_player) ? 1 : -1);
}

Expand All @@ -73,14 +74,31 @@ void Pong::game_logic() {
switch(state) {
case WAITING:
screen.show_score(player_1, player_2);
if (restart.is_pressed()) {
/* the game shall start after a few seconds after bootup of the Arduino.
* This makes using the reset pin optional,
* thus enables the game to be played without a separate reset button.
* Drawback: A restart of the game requires a reboot of the Arduino (takes only a few seconds).
*/
if (restart.is_pressed() || (isFirstRun && (millis() - waiting_time >= 5000))) {
choose_random_player();

player_1.reset_lifes();
player_2.reset_lifes();
screen.reset(player_1, player_2);

state = SERVE;
if (isFirstRun) {
isFirstRun = false;
// During first run one can lower the brightness to play in dark environments.
if (players[0]->button.is_pressed()) {
screen.lower_brightness();
}
// During first run one can setup a high speed mode with increased initial_speed.
if (players[1]->button.is_pressed()) {
ball.increase_initial_speed();
}
}

state = SERVE;
}
if (millis() - waiting_time >= 30000) {
state = IDLE;
Expand Down
1 change: 1 addition & 0 deletions Pong.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class Pong {
Player player_2;
Screen screen;
Ball ball;
bool isFirstRun;

unsigned long autoserve_time;
unsigned long autoserve_step_time;
Expand Down
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,58 @@

Pong-like game run on an Arduino MCU and a LED light strip. Inspired by a game seen on 34C3.

## Gameplay
Two players at each end of the strip send the ball back and forth by pressing their player button. Each player has an area of several LED's at each end of the strip. The ball is represented by a single white LED and can only be sent to the opposing player, when it hit within ones own area.
The base speed of the ball accelerates whenever the ball is hit by a player.
A goal is attributed once the ball is behind a player's area, which means behind the end of the LED strip.
The game is over once a player scores 8 goals.
Player 1 is represented by 8 green LED's, nearest to the LED connector socket. Player 2 is represented by 8 blue LED's, farther from LED connector socket.
Pro Tip for venturesome players: Hit the ball closer to your own goal to send it back to your opponent with much higher speed.

After 30 seconds without activity the LED strip shows some colorful animations until the next game is being started.

## Required Arduino Libraries

* FastLED (v3.1.6): http://fastled.io/
* FastLED (tested with v3.1.6 and 3.4.0): http://fastled.io/
- In Arduino IDE: Sketch > Include Library > Manage Libraries

## Used Hardware

Hardware build instructons & wiring schemes will be published soon!

* 1x Arduino Pro Mini
- Adafruit Pro Trinket 5V 16 MHz works, too, including USB support! Neither a separate power supply nor a Serial-to-USB-Adapter (FTDI programmer) are needed. The LED strip can be bus powered straight from the 'bus' pin, which supports 700 mA. This is enough to drive 60 LED's at 80% brightness. Beware, pin 7 is not available on this board, but Pins 3-6, Pin 8 and Pins A0-A5 are.
* 1x APA102-C LED light strip (1m) with 60 LEDs/m
* 1x 5v power supply (max. 2A)
* BOXEXPERT ABS casings
- 2x 52x50x35mm IP 65 https://www.boxexpert.de/epages/79711065.sf/de_DE/?ObjectPath=/Shops/79711065/Products/BXPBABS525035-E01
- 1x 65x50x35mm IP 65 https://www.boxexpert.de/epages/79711065.sf/de_DE/?ObjectPath=/Shops/79711065/Products/BXPBABS655035-E01
* 3x Sanwa OBSN-30 pushbutton

## Schematic

![Schematic](/schematic/schematic.png?raw=true "Schematic")

The wiring is pretty simple.

All electronics are powered via the same 5V power supply.
Make sure to use a supply that can deliver 2A.

There are three push buttons that pull the pin to high when beeing pressed.
Each button is connected to ground via a pull down resistor.
Without the resistor each pin would be touch sensitive. Then the pin registers as being pressed, when any cable is attached to it or any finger or metal object touches it. For testing the pins in general, this is a quite useful behaviour.

The input pins of the LED strip are connected to the SPI interface of the arduino.
CI (clock in) is connected to SCK and DI (data in) is connected to MOSI.
The power lines are directly connected to the power source.

## Features
* Game starts immediately after a few seconds
- You might not need a reset button, if you're willing to switch power off and on.
* During first run:
- Press Player 1 button to enter low brightness mode for darker environments (late at night, living room, bar/club)
- Press Player 2 button to enable high speed mode. Every game starts with increased initial speed.

## Feature Requests / Ideas from "Lange nacht der Computerspiele / HTWK Leipzig"

* Allow hits one off (+-1 outside of hit box)
Expand Down
13 changes: 9 additions & 4 deletions Screen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ void Screen::draw_player_score(Player p){
}
}

void Screen::lower_brightness() {
FastLED.setBrightness( 5 );
FastLED.show();
}

Screen::Screen(uint8_t num_leds, uint8_t brightness) : leds(new CRGB[num_leds]) {
//led_type = type;
//led_color_order = order;
Expand Down Expand Up @@ -137,8 +142,8 @@ void Screen::FillLEDsFromPaletteColors( uint8_t colorIndex)

void Screen::ChangePalettePeriodically()
{
uint8_t secondHand = (millis() / 1000) % 60;
static uint8_t lastSecond = 99;
uint8_t secondHand = (millis() / 1000) % 240;
static uint8_t lastSecond = 239;

if( lastSecond != secondHand) {
lastSecond = secondHand;
Expand All @@ -151,8 +156,8 @@ void Screen::ChangePalettePeriodically()
if( secondHand == 35) { SetupBlackAndWhiteStripedPalette(); currentBlending = LINEARBLEND; }
if( secondHand == 40) { currentPalette = CloudColors_p; currentBlending = LINEARBLEND; }
if( secondHand == 45) { currentPalette = PartyColors_p; currentBlending = LINEARBLEND; }
if( secondHand == 50) { currentPalette = myRedWhiteBluePalette_p; currentBlending = NOBLEND; }
if( secondHand == 55) { currentPalette = myRedWhiteBluePalette_p; currentBlending = LINEARBLEND; }
if( secondHand == 230) { currentPalette = myRedWhiteBluePalette_p; currentBlending = NOBLEND; }
if( secondHand == 235) { currentPalette = myRedWhiteBluePalette_p; currentBlending = LINEARBLEND; }
}
}

Expand Down
1 change: 1 addition & 0 deletions Screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class Screen {
public:
Screen(uint8_t num_leds, uint8_t brightness);

void lower_brightness();
void show_score(Player &p1, Player &p2);
void advance_ball(Ball &b, Player &p1, Player &p2);
void draw(Player &player_1, Player &player_2, Ball &ball);
Expand Down
Binary file added schematic/schematic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.