You have probably seen this style of game. The goal is to score as many baskets in the time allotted. In my game, I give the player 30 seconds. The display has four digits, the left two digits are the remaining time, while the right two digits are the player’s score. Here is what the finished project looks like.

Parts

Assembly

To determine when the player scores a basket, I mounted the IR LED and sensor on opposite sides of the inside portion of the embroidery hoop. To mount them, I drilled two holes in the hoop and super glued the parts to the plastic. In order to keep the LED from protruding into the inside of the hoop, I printed a small spacer for the LED.

3d Printed Parts

To mount the display to the backboard, I printed a frame for the display. This frame fits in the hole I cut into the backboard. Next, I printed a second frame to hold the first frame in place. I used super glue to attach frame #2 to the frame #1 and the backboard. Unfortunately, I don’t have images of what these frame look like before I glued everything together.

After mounting the display into the backboard, I lost the ability to hang the goal on my door. To solve that problem I printed four 25mm cubes to use as spacers. I printed them with a hole through the middle in order to use screws and mount the goal more securely to a wall. On one spacer, I attached an Arduino Micro holder. I used super glue to attach the spacers to the backboard.

Code

The code for this project is very simple. After the first basket is made the game starts. When time runs out, I print the final score, wait 5 seconds, then start over at 30 seconds and wait for a basket to start the next game.

if (isBallInHoop()) {
  start_game = true;
}
if (start_game) {
  // time = 1000 * 30s
  for(uint16_t time = 30000; time > 0; time -= 10) {
    ...
    ...
    delay(10);
  }
  printMatrix(0, baskets);
  delay(5000);
}

If the time is an even second, I update the display with the time and score. I also save this time for later use.

if (time % 1000 == 0) {
  print_time = time / 1000;
  printMatrix(print_time, baskets);
}

I keep track of when the ball is in the hoop, and when it leaves. This allows the ball the take a long time to get through the net, while only adding one point.

if (in_hoop) {
  if (!isBallInHoop()) {
    in_hoop = false;
  }
}

When a basket is scored, I update the basket total, set in_hoop to true, and update the display. This is where I use the saved time from earlier.

if (!in_hoop && isBallInHoop()) {
  in_hoop = true;
  baskets++;
  printMatrix(print_time, baskets);
  Serial.println("basketball is in the way!");
  Serial.println(baskets);
}

The full code can be seen below, or downloaded from github with the necessary libraries included.

#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"

Adafruit_7segment matrix = Adafruit_7segment();

#define PIN 1
#define     IR_LED                 13
#define     IR_SENSOR              4

void setup() {
#ifndef __AVR_ATtiny85__
  Serial.begin(9600);
  Serial.println("Basketball Scoreboard!");
#endif

  matrix.begin(0x70);

  pinMode(IR_LED, OUTPUT);
  pinMode(IR_SENSOR, INPUT);
}

void loop() {
  uint16_t baskets = 0;
  uint16_t print_time = 0;
  boolean in_hoop = false;
  boolean start_game = false;
  printMatrix(30, baskets);

  // start game when basket is scored
  if (isBallInHoop()) {
    start_game = true;
  }

  if (start_game) {
    // time = 1000 * 30s
    for(uint16_t time = 30000; time > 0; time -= 10) {
      // if time == an even second update matrix
      if (time % 1000 == 0) {
        print_time = time / 1000;
        printMatrix(print_time, baskets);
      }

      if (in_hoop) {
        if (!isBallInHoop()) {
          in_hoop = false;
        }
      }

      if (!in_hoop && isBallInHoop()) {
        in_hoop = true;
        baskets++;
        printMatrix(print_time, baskets);
        Serial.println("basketball is in the way!");
        Serial.println(baskets);
      }

      delay(10);
    }
    printMatrix(0, baskets);
    delay(5000);
  }
  delay(100);
}

void printMatrix(uint16_t time, uint16_t count) {
  matrix.writeDigitNum(0, time / 10);
  matrix.writeDigitNum(1, time % 10);
  matrix.writeDigitNum(3, (count / 10) % 10);
  matrix.writeDigitNum(4, count % 10);
  matrix.writeDisplay();
}

///////////////////////////////////////////////////////
// isBallInHoop function
//
// Returns true if a ball is blocking the sensor.
///////////////////////////////////////////////////////
boolean isBallInHoop() {
  // Pulse the IR LED at 38khz for 1 millisecond
  pulseIR(1000);

  // Check if the IR sensor picked up the pulse (i.e. output wire went to ground).
  if (digitalRead(IR_SENSOR) == LOW) {
    return false; // Sensor can see LED, return false.
  }

  return true; // Sensor can't see LED, return true.
}

///////////////////////////////////////////////////////
// pulseIR function
//
// Pulses the IR LED at 38khz for the specified number
// of microseconds.
///////////////////////////////////////////////////////
void pulseIR(long microsecs) {
  // 38khz IR pulse function from Adafruit tutorial: http://learn.adafruit.com/ir-sensor/overview
  // we'll count down from the number of microseconds we are told to wait
  cli();  // this turns off any background interrupts

  while (microsecs > 0) {
    // 38 kHz is about 13 microseconds high and 13 microseconds low
    digitalWrite(IR_LED, HIGH);  // this takes about 3 microseconds to happen
    delayMicroseconds(9);        // hang out for 10 microseconds, you can also change this to 9 if its not working
    digitalWrite(IR_LED, LOW);   // this also takes about 3 microseconds
    delayMicroseconds(9);        // hang out for 10 microseconds, you can also change this to 9 if its not working

    // so 26 microseconds altogether
    microsecs -= 26;
  }

  sei();  // this turns them back on
}

Demo

What’s Next?

There are numerous ways to make this project better. Here are some of the way I can think to improve the game.

  • Add a power supply (currently I am using a usb cable, but that comes unplugged easily)
  • Add sounds (buzzer when time runs out)
  • Remember the high score
  • Add initials for high score
  • Make a full size arcade game