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-16
- Revision:
- 17:194789db2215
- Parent:
- 16:d0b142ba4362
- Child:
- 18:70190f956a24
File content as of revision 17:194789db2215:
/* * 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 4 // 3 rows for characters, 1 row for special functions #define GRIDCOLUMNSPACING 2 #define GRIDROWSPACING 2 // Some text. const char HighScoreEntry::textDelete[] = "DELETE"; const char HighScoreEntry::textEnter[] = "ENTER"; /***************/ /* 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 ) { // First initialise rows used for characters. 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++; } // Add another row for special functions. columnNumber = 0; x = GRIDX; y += GRIDROWSPACING; row = grid.GetRow( rowNumber++ ); if( row != (FieldRow*)NULL ) { AddTextCell( x, y, row, textDelete ); AddTextCell( x, y, row, textEnter ); } } /***************************************/ /* ADD A CELL CONTAINING TEXT TO A ROW */ /***************************************/ // Pass character coordinates in x and y. These will be updated. // Pass row to which cells should be added in row. // Pass text which is to be contained in cell in text. void HighScoreEntry::AddTextCell( UInt8 &x, UInt8 &y, FieldRow *row, const char *text ) { int len = strlen( text ); FieldCell *cell = new FieldCell(); cell->Rect.X1 = x - 1; cell->Rect.Y1 = y - 1; cell->Rect.X2 = x + len; cell->Rect.Y2 = y + 1; row->AddCell( cell ); x += ( len + 1 ); } /*********************/ /* 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() - 1 ) { char newChar = (char)( PlayerName::MinChar + cursorRow * GRIDCOLUMNS + cursorColumn ); name->Name[ charIndex ] = newChar; if( charIndex < PlayerName::Length - 1 ) { charIndex++; } } else { // Last row contains special functions. SpecialFunction( gd, cursorColumn, name, done ); } // 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 ); } /************************************************************************/ /* PERFORM A SPECIAL FUNCTION TRIGGERED FROM A CELL ON LAST ROW OF GRID */ /************************************************************************/ // Pass pointer to Gameduino to draw on in gd. // Pass function number in funcNum (this is the cursor column number). // Pass player name in name. // Pass reference to done flag in done. void HighScoreEntry::SpecialFunction( Gameduino *gd, UInt8 funcNum, PlayerName *name, bool &done ) { switch( funcNum ) { case 0 : // DELETE function if( charIndex > 0 ) { name->Name[ charIndex-- ] = ' '; } break; case 1 : // ENTER function done = true; break; } } /*********************/ /* 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 \"ENTER\"" ); gd->putstr( 2, 10, " 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 ) { // Draw rows containing characters. 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 row containing special functions. x = GRIDX; y += GRIDROWSPACING; gd->putstr( x, y, textDelete ); x += ( strlen( textDelete ) + 1 ); gd->putstr( x, y, textEnter ); } /********************************/ /* 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; } } }