The Brick Bakery: The FollowMe Game.

This is a really simply game you can build using Lego Mindstorms. There are a number of games on the market where the computer makes some sound or flashes a light or something and you have to respond with some related action. Classic examples are "Simon" and "Bop-It" - but there are many others.

FollowMe uses the outputs of the Lego RCX computer to drive a spinning wheel and a light - and also uses the various sounds that the RCX can make. These are the things that the player has to imitate - using (appropriately) a second wheel attached to a rotation sensor, a light sensor and a touch sensor.

The whole machine.
(Notice the cabling)
The light sensor.
The motion sensor & motor
The light and The touch sensor

When FollowMe spins the wheel, you have to spin the other wheel in the same direction. When FollowMe flashes the light, you have to block the light sensor with your hand. When FollowMe makes a sound, you have to press the touch sensor (which makes a similar sound). You must only do the thing it tells you to do - and you must do it quickly!

Every time you get it right, FollowMe picks another thing for you to do. If you get it wrong, the game is over and the score is displayed on the RCX's LCD panel. Each time you get it right, you have less time to get the next thing right - so the game goes faster and faster until you can no longer keep up.

When you eventually lose, you'll hear a low beeping sound with your final score shown on the LCD. You have to stop the RCX and press RUN to play another game.

Precise details of what each command is and how you have to respond is easy to change - if for example you don't have a rotation sensor or you'd like some more complicated mechanics.

Here is a listing of the NQC program that plays the game. You need at least revision 2.0 of the Lego RCX firmware (although you can have an older RCX) and a reasonably recent version of NQC that knows how to drive the rev 2 firmware:


/*
  Attach a motor to OUT_A and a Lego lamp to each of
  OUT_B and OUT_C.

  Attach a rotation sensor with a 40t gear wheel
  and an axle to SENSOR 1, a light sensor to
  SENSOR 2 and a bump sensor to SENSOR 3.

  The light from OUT_C should shine directly into
  the light sensor with just enough room between
  for you to put your finger.  Place a black 
  1x2 one-hole beam in front of the light sensor to
  block it's own light from interfering.
  The OUT_B light must not be close to the light sensor.

  You may find that you have to flip the motor polarity
  in order for it to rotate in the same direction that
  the rotation sensor is measuring.

  The RCX then tells you what to do - and you have
  to follow it's commands:

  When the OUT_B lamp lights, you have to block the
    light sensor sufficiently to reduce the light
    coming from the OUT_C lamp by 20%.

  When the motor turns, you have to spin the rotation
    sensor by at least a quarter turn in the same
    direction.

  When the musical tone sounds, you have to press the
    touch sensor to make it play the opposite tone.

  The game gets gradually faster and faster and you have
  less and less time to respond.

  When you finally mess up, the RCX will display your
  score and you'll have to press RUN to play again.
*/

int score ;   /* Has to be global to be displayed on LCD */

task main ()
{
  int pick ;
  int action ;
  int speed ;
  int rot ;
  int lig ;
  int snd ;
  int i ;
  int light_on ;

  /* Zero the score and set the initial speed to something easy to beat */

  score = 0 ;
  speed = 300 ;

  /* Set up the sensors and outputs appropriately */

  SetSensorType(SENSOR_1, SENSOR_TYPE_ROTATION ) ;
  SetSensorMode(SENSOR_1, SENSOR_MODE_ROTATION ) ;

  SetSensorType(SENSOR_2, SENSOR_TYPE_LIGHT    ) ;
  SetSensorMode(SENSOR_2, SENSOR_MODE_PERCENT  ) ;

  SetSensorType(SENSOR_3, SENSOR_TYPE_TOUCH    ) ;
  SetSensorMode(SENSOR_3, SENSOR_MODE_BOOL     ) ;

  SetPower ( OUT_A, 7 ) ; Off ( OUT_A ) ;  /* Motor to tell you what to do */
  SetPower ( OUT_B, 7 ) ; Off ( OUT_B ) ;  /* Lamp to tell you what to do */
  SetPower ( OUT_C, 7 ) ; On  ( OUT_C ) ;  /* Lamp to light the light sensor */

  /* Tell the LCD to display the score */

  SelectDisplay ( DISPLAY_USER ) ;
  SetUserDisplay ( score, 0 ) ;

  /* Calibrate the light sensor so we can tell when it's blocked */

  Wait ( 20 ) ;
  light_on  = (SENSOR_2 * 8) / 10 ;  /* Trigger on 80% as much light */

  /* Initialise the random seed so we don't get the same game every time */

  SetRandomSeed ( light_on ) ;  /* There must be a better way! */

  while ( true )
  {
    action = Random ( 3 ) + 1 ;
    pick = 0 ;

    ClearSensor ( SENSOR_1 ) ;  /* Zero the rotation sensor */

    /* Pick an action for the RCX to perform... */

    switch ( action )
    {
      case 1 : /* Motor clockwise */
        OnFwd ( OUT_A ) ;
        break ;
      case 2 : /* Motor anticlockwise */
        OnRev ( OUT_A ) ;
        break ;
      case 3 : /* Light */
        OnFwd ( OUT_B ) ;
        break ;
      case 4 : /* Sound */
        PlaySound ( SOUND_UP ) ;
        break ;
    }

    /* Wait for the user to either perform an action - or run out of time */

    for ( i = 0 ; i < speed ; i++ )
    {
      rot = SENSOR_1 ;
      lig = SENSOR_2 ;
      snd = SENSOR_3 ;

      if ( rot >  4 ) { pick = 1 ; break ; }
      if ( rot < -4 ) { pick = 2 ; break ; }
      if ( lig < light_on ) { pick = 3 ; break ; }
      if ( snd == 1 ) { pick = 4 ; Off ( OUT_A ) ; Off ( OUT_B ) ;
                                   PlaySound ( SOUND_DOWN ) ;
                                   Wait ( 100 ) ; break ; }
      Wait ( 1 ) ;
    }

    Off ( OUT_A ) ;
    Off ( OUT_B ) ;

    /* So, did he do it right? */

    if ( pick == action )
    {
      /* Well Done! Play happy sound! */

      score++ ;
      PlaySound ( SOUND_DOUBLE_BEEP ) ;

      if ( speed > 30 )
        Wait ( speed ) ;
      else
        Wait ( 30 ) ;
    }
    else
    {
      /* You lose! Play sad sound and wait to be stopped manually */

      while ( true )
      {
        Wait ( 100 ) ;
        PlaySound ( SOUND_LOW_BEEP ) ;
      }
    }

    /*
      Make the speed increase quite fast to start with - then
      slow down a bit to make the game last longer - eventually,
      it's impossible to go any faster and still have the motor
      react fast enough - so stop speeding up and just hope he
      makes a mistake *eventually*
    */

    if ( speed > 50 )
      speed -= 10 ;
    else
    if ( speed > 10 )
      speed-- ;
  }
}



RETURN TO TOP
Steve Baker <steve@sjbaker.org>