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

GameRobotRic.cpp

Committer:
RichardE
Date:
2013-06-17
Revision:
18:70190f956a24
Parent:
17:194789db2215

File content as of revision 18:70190f956a24:

/*
 * SOURCE FILE : GameRobotRic.cpp
 *
 * The RobotRic game class.
 *
 */

#include "GameRobotRic.h"          // this module's prototypes
#include "Types.h"                 // various integer types etc.
#include "LevelCollection.h"       // all the levels
#include "sprite.h"                // sprite data
#include "RobotRicCharacterSet.h"  // character set used in this game
#include "HighScoreEntry.h"        // for getting player's name for high score table
#include "GDExtra.h"               // extra Gameduino functions
#include "GDConst.h"               // a few more Gameduino constants
#include "ArenaConst.h"            // gameplay arena constants

// Define following for debugging messages to serial port.
#undef CHATTY

// Define following to reset all high scores on power up.
#undef RESETHIGHSCORES

// Number of lives player starts with.
#define START_LIVES 5

// Serial link to PC over USB cable. Globally accessible.
Serial pc( USBTX, USBRX );

/**************************/
/* CHECK FOR A HIGH SCORE */
/**************************/
// Pass pointer to a Gameduino to display on in gd.
// Pass pointer to high score table in highScores.
// Pass score that was achieved in score.
void GameRobotRic::CheckForHighScore( Gameduino *gd, HighScoreTable *highScores, UInt32 score ) {
    UInt8 tablePos;
    // Enter name into high score table if score is high enough.
    if( ( tablePos = highScores->GetPositionInTable( score ) ) < highScores->GetCapacity() ) {
        // Player has made it onto the high score table.
        // Get player to input name.
        HighScoreEntry nameGetter;
        PlayerName name;
        nameGetter.GetName( &name, &controls, gd );
        // Add name and score to table.
        highScores->Add( tablePos, &name, score );
    }
}

/*****************/
/* PLAY THE GAME */
/*****************/
// This NEVER exits.
void GameRobotRic::Play( void ) {
    // Change baud rate on PC serial link.
    pc.baud( 115200 );
    #ifdef CHATTY
        pc.puts( "Program has restarted!\r\n" );
    #endif
    // Make a digital output for use as the Gameduino chip select pin. Deselect it.
    DigitalOut gameduinoCS( p8 );
    gameduinoCS = 1;
    // Initialise an SPI link for communications with Gameduino and the serial EEPROM.
    // This is different from how the Maple version of RobotRic did it. It used an
    // I2C EEPROM.
    // Use pin 5 for MOSI.
    // Use pin 6 for MISO.
    // Use pin 7 for SCK.
    SPI spi( p5, p6, p7 );
    // 8MHz clock should be OK.
    spi.frequency( 8000000 );
    // Set SPI format to use.
    // Use 8 bits per SPI frame.
    // Use SPI mode 0. Clock normally low. Data captured on rising edge.
    spi.format( 8, 0 );
    // Make a Gameduino and pass SPI link and digital output for chip select.
    Gameduino gd( &spi, &gameduinoCS );
    // Reset the Gameduino.
    gd.begin();
    gd.copy( Gameduino::RAM_SPRIMG, sprite_sprimg, sizeof( sprite_sprimg ) );
    // Copy sprite palette data into Gameduino memory.
    gd.copy( Gameduino::RAM_SPRPAL, sprite_sprpal, sizeof( sprite_sprpal ) );
    // Initialise character set pixel data RAM.
    gd.copy( Gameduino::RAM_CHR, RobotRicCharacterSet::PixelData, ( LAST_CHAR_IN_CHARACTER_SET + 1 ) << 4 );
    // Initialise character set pixel palette RAM.
    gd.copy( Gameduino::RAM_PAL, RobotRicCharacterSet::PaletteData, ( LAST_CHAR_IN_CHARACTER_SET + 1 ) << 3 );
    // Turn off JK collision detection. Every sprite collides with every other.
    // Did it this way because I could not resolve some problems with wandering humans.
    // Suppose JK collision detection were used. The player sprite is of type J and humans
    // are of type K so collisions between them will register allowing humans to be rescued.
    // However, I also need some enemies (Crushers for example) to be able to collide with
    // humans so they would need to be J type to collide with humans. But then player and
    // enemies are both J type and so collisions between players and enemies are not detected.
    gd.wr( Gameduino::JK_MODE, 0 );
    // Pass Gameduino to sound manager.
    SoundManager::Instance.SetGameduino( &gd );
    // Initialise serial EEPROM object which is on same SPI bus as the Gameduino.
    Ser25LCxxx eeprom( &spi, p14, 32768, 64 );
    // Create a high score table that uses the EEPROM.
    HighScoreTable highScores( &eeprom );
    // Start on the attract level.
    UInt8 levelNumber = LevelCollection::AttractLevel;
    player.Lives = START_LIVES;
    LevelCollection levels;
    Level *level;
    Level::LevelExitCode exitCode;
    // Initialise panel controls.
    controls.InitialisePins();
    // Specify controls player should use.
    player.SetControls( &controls );
    // Restrict players movement.
    player.MovementRestricted = true;
    player.Bounds = &ArenaRectangle;
    // If configured to do so reset high scores.
    #ifdef RESETHIGHSCORES
        highScores.WriteEEPROMDefaults();
    #endif    
    // Repeat forever.
    while( true ) {
        // Get level specified by level number.
        level = levels.GetLevel( levelNumber );
        // If failed to get level with that number go back to first normal level.
        // This will happen if player completes last level.
        if( level == NULL ) {
            levelNumber = LevelCollection::FirstNormalLevel;
            // Refetch level.
            level = levels.GetLevel( levelNumber );
        }
        // Pass reference to high score table.
        level->SetHighScores( &highScores );
        // Set player that is playing the level.
        level->SetPlayer( &player );
        // Set Gameduino to use.
        level->SetGameduino( &gd );
        // Play the level.
        exitCode = level->Play();
        // Free memory used by level.
        levels.FreeLevel( level );
        // If player was killed then decrement lives otherwise
        // advance to next level.
        switch( exitCode ) {
        case Level::GameOver :
            // TODO : Do some sort of game over fuss.
            CheckForHighScore( &gd, &highScores, player.Score );
            // Go back to attract level and reset player lives and score.
            levelNumber = LevelCollection::AttractLevel;
            player.Lives = START_LIVES;
            player.Score = 0;
            break;
        case Level::Completed :
            levelNumber++;
            break;
        }
    }
}