diff --git a/Ball.cpp b/Ball.cpp index 95b331d..7999d90 100644 --- a/Ball.cpp +++ b/Ball.cpp @@ -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; } diff --git a/Ball.h b/Ball.h index e4b9bd0..4d01ef0 100644 --- a/Ball.h +++ b/Ball.h @@ -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); diff --git a/Pong.cpp b/Pong.cpp index e59aa43..e3851f4 100644 --- a/Pong.cpp +++ b/Pong.cpp @@ -26,7 +26,7 @@ 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; @@ -34,6 +34,7 @@ Pong::Pong(uint8_t player_1_pin, uint8_t player_2_pin, uint8_t lifes, uint16_t b auto_serve_timeout = 2000; position_is_allowed = false; waiting_time = millis(); + isFirstRun = true; randomSeed(analogRead(random_seed_pin)); } @@ -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); } @@ -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; diff --git a/Pong.h b/Pong.h index bc5d308..982b708 100644 --- a/Pong.h +++ b/Pong.h @@ -54,6 +54,7 @@ class Pong { Player player_2; Screen screen; Ball ball; + bool isFirstRun; unsigned long autoserve_time; unsigned long autoserve_step_time; diff --git a/README.md b/README.md index bf38ecb..3a17117 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,19 @@ 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 @@ -12,6 +22,7 @@ Pong-like game run on an Arduino MCU and a LED light strip. Inspired by a game s 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 @@ -19,6 +30,30 @@ Hardware build instructons & wiring schemes will be published soon! - 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) diff --git a/Screen.cpp b/Screen.cpp index a061558..e27db6e 100644 --- a/Screen.cpp +++ b/Screen.cpp @@ -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; @@ -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; @@ -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; } } } diff --git a/Screen.h b/Screen.h index 4dd0483..5b2d7e3 100644 --- a/Screen.h +++ b/Screen.h @@ -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); diff --git a/schematic/schematic.png b/schematic/schematic.png new file mode 100644 index 0000000..ae55aed Binary files /dev/null and b/schematic/schematic.png differ