Version of Robotron arcade game using LPC1768, a Gameduino shield, a serial EEPROM (for high scores), two microswitch joysticks and two buttons plus a box to put it in. 20 levels of mayhem.

Dependencies:   25LCxxx_SPI CommonTypes Gameduino mbed

HighScoreEntry.cpp

Committer:
RichardE
Date:
2013-06-15
Revision:
16:d0b142ba4362
Parent:
15:d8ea0c7b7e64
Child:
17:194789db2215

File content as of revision 16:d0b142ba4362:

/*
 * SOURCE FILE : HighScoreEntry.cpp
 *
 * Definition of class HighScoreEntry.
 * Routine to allow player to enter their name using joysticks.
 *
 */

#include "HighScoreEntry.h"
#include "Gameduino.h"       // Gameduino stuff
#include "GDExtra.h"         // more Gameduino stuff
#include "GDConst.h"         // Gameduino constants
#include "FrameCounter.h"    // counter updated every vertical flyback
#include "CharBlocks.h"      // blocks of characters in program memory
#include "CharFrame.h"       // for drawing frames made of characters
#include "CharCodes.h"       // character codes
#include "CharFrame.h"       // for drawing frames of characters

// Define this for debugging messages on serial port.
#undef CHATTY

#ifdef CHATTY
    extern Serial pc;
#endif

// Grid constants.
#define GRIDX 5
#define GRIDY 16
#define GRIDCOLUMNS 20
#define GRIDROWS 3
#define GRIDCOLUMNSPACING 2
#define GRIDROWSPACING 2

/***************/
/* CONSTRUCTOR */
/***************/
HighScoreEntry::HighScoreEntry() :
  charIndex( 0 ),
  cursorRow( 0 ),
  cursorColumn( 0 ),
  grid( GRIDROWS )
{
  // Initialise grid around which cursor moves.
  InitialiseGrid();
  #ifdef CHATTY
  for( UInt8 rowNum = 0; rowNum < grid.GetRowCount(); ++rowNum ) {
    FieldRow *row = grid.GetRow( rowNum );
    if( row != (FieldRow*)NULL ) {
        FieldCell *cell = row->GetFirstCell();
        UInt8 columnNum = 0;
        while( cell != (FieldCell*)NULL ) {
            pc.printf(
                "Row %d column %d -> %d,%d,%d,%d\r\n",
                (int)rowNum, (int)columnNum,
                (int)cell->Rect.X1, (int)cell->Rect.Y1, (int)cell->Rect.X2, (int)cell->Rect.Y2
            );
            cell = row->GetNextCell();
            columnNum++;
        }
    }
  }
  #endif
}

/**************/
/* DESTRUCTOR */
/**************/
HighScoreEntry::~HighScoreEntry() {
}

/*******************/
/* INITIALISE GRID */
/*******************/
void HighScoreEntry::InitialiseGrid( void ) {
    UInt8 code = PlayerName::MinChar;
    UInt8 x = GRIDX, y = GRIDY;
    UInt8 columnNumber = 0, rowNumber = 0;;
    FieldRow *row = grid.GetRow( rowNumber++ );
    while( code <= PlayerName::MaxChar ) {
        if( row != (FieldRow*)NULL ) {
            FieldCell *cell = new FieldCell();
            cell->Rect.X1 = x - 1;
            cell->Rect.Y1 = y - 1;
            cell->Rect.X2 = x + 1;
            cell->Rect.Y2 = y + 1;
            row->AddCell( cell );
        }
        columnNumber++;
        if( columnNumber >= GRIDCOLUMNS ) {
            columnNumber = 0;
            x = GRIDX;
            y += GRIDROWSPACING;
            row = grid.GetRow( rowNumber++ );
        }
        else {
            x += GRIDCOLUMNSPACING;
        }
        code++;
    }
}

/*********************/
/* GET A PLAYER NAME */
/*********************/
// Pass pointer to place to store name in name.
// Pass pointer to controls to read in controls.
// Pass pointer to Gameduino to display on in gd.
void HighScoreEntry::GetName( PlayerName *name, PanelControls *controls, Gameduino *gd ) {
  UInt16 inputs;
  UInt8 countdown = 0;
  // Initialise name to all 'A' characters.
  for( UInt8 i = 0; i < PlayerName::Length; ++i ) {
    name->Name[ i ] = 'A';
  }
  // Draw screen.
  DrawScreen( gd, name );
  // Wait until player releases all controls.
  WaitControls( gd, controls, false );
  // Loop until player activates done cell.
  bool done = false;
  while( ! done ) {
    // Read panel controls.
    controls->Read();
    inputs = controls->GetInputs();
    // Only react to controls every so often to slow things down.
    if( countdown == 0 ) {
      countdown = 10;
      bool cursorMoved = false;
      // Point to current cell before changing.
      FieldCell *lastCell = grid.GetCellAt( cursorRow, cursorColumn );      
      if( inputs & PanelControls::Up1 ) {
        // Joystick up moves cursor up.
        if( cursorRow > 0 ) {
          cursorRow--;
          ValidateCursorColumn();
          cursorMoved = true;
        }
      }
      else if( inputs & PanelControls::Down1 ) {
        // Joystick down moves cursor down.
        if( cursorRow < grid.GetRowCount() - 1 ) {
          cursorRow++;
          ValidateCursorColumn();
          cursorMoved = true;
        }
      }
      if( inputs & PanelControls::Left1 ) {
        // Joystick left moves cursor left.
        if( cursorColumn > 0 ) {
          cursorColumn--;
          cursorMoved = true;
        }
      }
      else if( inputs & PanelControls::Right1 ) {
        // Joystick right moves cursor right.
        FieldRow *row = grid.GetRow( cursorRow );
        if( ( row != (FieldRow*)NULL ) && ( cursorColumn < row->GetColumnCount() - 1 ) ) {
            cursorColumn++;
            cursorMoved = true;
        }
      }
      if( inputs & PanelControls::Button1 ) {
          // Button 1 adds a character or possibly does something special.
          if( cursorRow < grid.GetRowCount() ) {
              char newChar = (char)( PlayerName::MinChar + cursorRow * GRIDCOLUMNS + cursorColumn );
              name->Name[ charIndex ] = newChar;
              if( charIndex < PlayerName::Length - 1 ) {
                  charIndex++;
              }
          }
          else {
              // TODO. Special functions.
          }
          // Draw modified name.
          gd->waitvblank();
          DrawName( gd, name );
          // Wait until player releases all controls.
          WaitControls( gd, controls, false );
      }
      // If necessary redraw the cursor.
      if( cursorMoved ) {
          WipeCursor( gd, lastCell );
          DrawCursor( gd, grid.GetCellAt( cursorRow, cursorColumn ) );
      }
    }
    else {
      countdown--;
    }
    // Wait for vertical flyback. Then do animation.
    gd->waitvblank();
    FrameCounter++;
    Animate( gd );
  }
  // Wait until player releases all controls before returning.
  WaitControls( gd, controls, false );
}

/*********************/
/* WAIT FOR CONTROLS */
/*********************/
// Pass pointer to Gameduino to display on in gd.
// Pass pointer to controls to read in controls.
// Pass true in waitActivate to wait for a control to be used.
// Pass false to wait for release.
void HighScoreEntry::WaitControls( Gameduino *gd, PanelControls *controls, bool waitActivate ) {
  bool released = false;
  UInt16 inputs;
  while( ! released ) {
    controls->Read();
    inputs = controls->GetInputs();
    released = ( waitActivate ? ( inputs != 0 ) : ( inputs == 0 ) );
    if( ! released ) {
      gd->waitvblank();
      FrameCounter++;
      Animate( gd );
    }
  }
}

/*******************/
/* DRAW THE SCREEN */
/*******************/
// Pass pointer to Gameduino to draw on in gd.
// Pass player name in name.
void HighScoreEntry::DrawScreen( Gameduino *gd, PlayerName *name ) {
  gd->waitvblank();
  // Clear the screen to zero characters.
  gd->fill( Gameduino::RAM_PIC, 0, RAM_PIC_SIZE );
  // Turn off all the sprites.
  for( UInt16 s = 0; s < SPRITE_COUNT; ++s ) {
    gd->sprite( s, 0, 400, 0, 0 );
  }
  // Draw border around screen.
  CharFrame::Draw( gd, 0, 0, VISIBLE_CHAR_WIDTH, VISIBLE_CHAR_HEIGHT );
  // Draw instructions.
  gd->putstr( 2, 2,  "   CONGRATULATIONS : YOU HAVE A HIGH SCORE!" );
  gd->putstr( 2, 4,  "PLEASE ENTER YOUR NAME USING THE LEFT JOYSTICK" );
  gd->putstr( 2, 6,  " TO MOVE THE CURSOR. PRESS THE LEFT BUTTON TO" );
  gd->putstr( 2, 8,  "  ENTER EACH LETTER. MOVE CURSOR TO FOOT OF" );
  gd->putstr( 2, 10, " SCREEN AND PRESS LEFT BUTTON WHEN FINISHED." );
  // Draw player's name.
  DrawName( gd, name );
  // Draw character grid.
  DrawGrid( gd );
  // Draw cursor.
  DrawCursor( gd, grid.GetCellAt( cursorRow, cursorColumn ) );
}

/***************************/
/* DRAW THE CHARACTER GRID */
/***************************/
// Pass pointer to Gameduino to draw on in gd.
void HighScoreEntry::DrawGrid( Gameduino *gd ) {
    UInt8 code = PlayerName::MinChar;
    UInt8 x = GRIDX, y = GRIDY;
    UInt8 columnNumber = 0;
    char str [] = "X";
    while( code <= PlayerName::MaxChar ) {
        str[ 0 ] = (char)code++;
        gd->putstr( x, y, str );
        columnNumber++;
        if( columnNumber >= GRIDCOLUMNS ) {
            columnNumber = 0;
            x = GRIDX;
            y += GRIDROWSPACING;
        }
        else {
            x += GRIDCOLUMNSPACING;
        }
    }
}

/********************************/
/* DRAW THE NAME AND THE CURSOR */
/********************************/
// Pass pointer to Gameduino to draw on in gd.
// Pass player name in name.
void HighScoreEntry::DrawName( Gameduino *gd, PlayerName *name ) {
  gd->putstr( 23, 13, name->Name );
  UInt16 address = Gameduino::RAM_PIC + 14 * SCREEN_CHAR_WIDTH + 23;
  for( UInt8 i = 0; i < PlayerName::Length; ++i ) {
    gd->wr( address, ( i == charIndex ) ? ArrowUp : ' ' );
    address++;
  }
}

/********************/
/* UPDATE ANIMATION */
/********************/
// Pass pointer to Gameduino to display on in gd.
void HighScoreEntry::Animate( Gameduino *gd ) {
}

/*******************/
/* WIPE THE CURSOR */
/*******************/
// Pass pointer to Gameduino to display on in gd.
// Pass cell to draw in cell.
void HighScoreEntry::WipeCursor( Gameduino *gd, FieldCell *cell ) {
    if( cell != (FieldCell*)NULL ) {
        CharFrame::Wipe( gd, cell->Rect.X1, cell->Rect.Y1, cell->Rect.GetWidth(), cell->Rect.GetHeight() );
    }
}

/*******************/
/* DRAW THE CURSOR */
/*******************/
// Pass pointer to Gameduino to display on in gd.
// Pass cell to draw in cell.
void HighScoreEntry::DrawCursor( Gameduino *gd, FieldCell *cell ) {
    if( cell != (FieldCell*)NULL ) {
        CharFrame::Draw( gd, cell->Rect.X1, cell->Rect.Y1, cell->Rect.GetWidth(), cell->Rect.GetHeight() );
    }
}

/**************************/
/* VALIDATE CURSOR COLUMN */
/**************************/
// If cursor column is beyond end of row then forces it back.
void HighScoreEntry::ValidateCursorColumn( void ) {
    FieldRow *row = grid.GetRow( cursorRow );
    if( row != (FieldRow*)NULL ) {
        UInt8 columnCount = row->GetColumnCount();
        if( cursorColumn >= columnCount ) {
            cursorColumn = columnCount - 1;
        }
    }
}