Last active
August 29, 2015 14:15
-
-
Save cybrox/86e69f95b39e9afc6fdd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @file sketch.ino | |
* @author Sven Marc 'cybrox' Gehring | |
* @date 2015-02-20 | |
* @brief Pathetic guitar hero implementation for RKAG Matrix | |
*/ | |
#include "Matrix_RKAG.h" | |
#include "SPI.h" | |
#include "Wire.h" | |
#define ENEMIES 10 /* number of max enemies */ | |
#define INCREASE_SPEED false /* game speed will increase over time if set */ | |
matrix matrix; /* global instance of our matrix class */ | |
enum colNumber { /* enumerable with col type identifiers */ | |
LEFT, /* led cols 0 - 1 */ | |
MIDDLE, /* led cols 3 - 4 */ | |
RIGHT /* led cols 6 - 7 */ | |
}; | |
/** | |
* @brief Struct that holds all the input values | |
*/ | |
struct InputDataTag { | |
int poti; /* value of the on-board potentiometer */ | |
bool button1; /* value of the left button */ | |
bool button2; /* value of the middle button */ | |
bool button3; /* value of the right button */ | |
} inputData = { 0, false, false, false }; | |
/** | |
* @brief Struct that holds the current game data | |
*/ | |
struct currentGameTag { | |
bool started; /* indicator wether or not the game has started */ | |
int speed; /* speed value calculated from the potentiomenter */ | |
int multi; /* the multiplier for the players points */ | |
int cRound; /* current round identifier */ | |
double points; /* points scored in the current game */ | |
} currentGame = { false, 0, 0, 0, 0 }; | |
/** | |
* @brief Ene object data | |
* Each enemy object is represented by an EnemyObjectTag, its place | |
* in the enemy queue is freed when the player "hits" the target. | |
*/ | |
typedef struct EnemyObjectTag { | |
enum colNumber col; /* indicator for the current column of the enemy */ | |
int row; /* current row (from top) */ | |
bool alive; /* indicator if the enemy is alive */ | |
} EnemyObject_t; | |
static EnemyObject_t l_EnemyObject[ENEMIES]; /* static array of enemies present */ | |
bool firstStart = false; /* first start helper */ | |
int roundCount = 0; /* round count for delayed action */ | |
int scoreCount = 0; /* helper to dispay score */ | |
/* Forward declarations of functions */ | |
void inputDataUpdate(void); /* update all input data */ | |
void currentGameAddEnemy(void); /* add a new enemy */ | |
void currentGameMoveEnemy(void); /* move all enemies present on the game fild */ | |
void currentGameShootEnemy(void); /* check button press and enemy positions */ | |
void currentGameDisplayEnemy(void); /* display all enemies in the matrix */ | |
void currentGameResetEnemies(void); /* reset all enemies */ | |
/** | |
* @brief Setup method, initializing rkag matrix | |
*/ | |
void setup() { | |
matrix.init(); /* initialize our matrix object */ | |
} | |
/** | |
* @brief Main loop, arduino default | |
* For this application, the loop will run with a default cycle delay | |
* of roughly 1ms. | |
*/ | |
void loop() { | |
if(roundCount >= floor(currentGame.speed / 10)){ | |
if(currentGame.started){ /* if the game is started, run the game loop */ | |
if(random(0, 4) == 2) currentGameAddEnemy();/* random chance to add a new enemy to the game */ | |
currentGameMoveEnemy(); /* move all enemies present on the game fild */ | |
currentGameDisplayEnemy(); /* display all enemies on the matrix */ | |
} else { /* otherwise display the user's points */ | |
if(inputData.button1 || inputData.button2 || inputData.button3){ /* start on button press */ | |
currentGameResetEnemies(); /* reset all enemies */ | |
currentGame.started = true; | |
currentGame.points = 0; | |
firstStart = true; /* tell the programm that we startet at least one game */ | |
} | |
if(firstStart){ | |
if(scoreCount >= 0){ | |
int mp = pow(10, scoreCount); | |
int gp = currentGame.points; | |
int ft = 0x30 + floor((gp % (mp*10) - gp % mp) / mp); | |
if(scoreCount == 2) ft = ft - 1; /* Hacky workaround for round bug */ | |
if(ft < 48 || ft > 57) ft = 48; /* secure number area 0 - 9 */ | |
matrix.clear(); | |
delay(10); /* small pause to allow recognizing same numbers */ | |
matrix.font_write(ft); | |
scoreCount--; | |
} else { | |
matrix.font_write('-'); | |
scoreCount = 4; | |
} | |
} else { | |
matrix.write(0xFF, 0x7E, 0x3C, 0x18, 0x18, 0x3C, 0x7E, 0xFF); /* Initial game screen */ | |
} | |
} | |
roundCount = 0; /* reset round counter for delay */ | |
} else { | |
roundCount++; | |
} | |
inputDataUpdate(); /* update all our input information */ | |
delay(10); | |
} | |
/** | |
* @brief Read all input values from the connected input peripherials | |
* This will read all input peripherials and generate the game speed and | |
* score multipliers at the same time. | |
*/ | |
void inputDataUpdate(void){ | |
int keyTemp = matrix.key(); /* read keys from port expander */ | |
inputData.poti = analogRead(A0); | |
inputData.button1 = ((keyTemp & 0x01) == 1); | |
inputData.button2 = ((keyTemp & 0x02) == 2); | |
inputData.button3 = ((keyTemp & 0x04) == 4); | |
int speed = 1024 - inputData.poti; /* invert poti value for left - right speed */ | |
currentGame.speed = 1000 - (speed / 1.2); | |
#if (INCREASE_SPEED == true) | |
currentGame.speed -= (currentGame.cRound / 2); | |
#endif | |
currentGame.multi = ceil(speed / 200); /* calculate score multiplier */ | |
currentGameShootEnemy(); /* check if the button presses match enemy positions */ | |
} | |
/** | |
* @brief add a new enemy to the game with a random col number | |
* @note Little hacky, the initial row is set to -1 because it's incremented pre-display. | |
*/ | |
void currentGameAddEnemy(void){ | |
for(int i = 0; i < ENEMIES; i++){ | |
if(l_EnemyObject[i].alive == false){ /* search for a free (dead) enemy space */ | |
l_EnemyObject[i].alive = true; | |
l_EnemyObject[i].col = (colNumber)random(0,3); | |
l_EnemyObject[i].row = -1; | |
break; | |
} | |
} | |
} | |
/** | |
* @brief Move all currently active enemies | |
* This will move every enemy down one line and check if he reached the bottom. | |
* If he reached line 8, the game will be terminated since that is a failure. | |
*/ | |
void currentGameMoveEnemy(void){ | |
currentGame.cRound++; /* increment current round counter */ | |
for(int i = 0; i < ENEMIES; i++){ | |
if(l_EnemyObject[i].alive == true){ | |
l_EnemyObject[i].row++; /* move the enemy one line down */ | |
if(l_EnemyObject[i].row >= 8){ /* if the enemy has reached the bottom */ | |
delay(1000); /* delay to notify user */ | |
l_EnemyObject[i].alive = false; /* kill enemy */ | |
currentGame.started = false; /* end the current game */ | |
currentGame.cRound = 0; /* reset the delay modifier */ | |
} | |
} | |
} | |
} | |
/** | |
* @brief Check button presses and enemy position | |
* Kill enemies where button is pressed | |
*/ | |
void currentGameShootEnemy(void){ | |
for(int i = 0; i < ENEMIES; i++){ | |
if(l_EnemyObject[i].alive && l_EnemyObject[i].row >= 5 ){ | |
if( | |
l_EnemyObject[i].col == LEFT && inputData.button1 || | |
l_EnemyObject[i].col == MIDDLE && inputData.button2 || | |
l_EnemyObject[i].col == RIGHT && inputData.button3 | |
){ | |
currentGame.points += currentGame.multi; | |
l_EnemyObject[i].alive = false; | |
} | |
} | |
} | |
} | |
/** | |
* @brief Empty the enemies array | |
*/ | |
void currentGameResetEnemies(void){ | |
for(int i = 0; i < ENEMIES; i++) l_EnemyObject[i].alive = false; | |
} | |
/** | |
* @brief Place and display enemies in matrix | |
* @note The matrix array is char-casted here, a method overload would | |
* be more convenient to write the data to the matrix field. | |
*/ | |
void currentGameDisplayEnemy(void){ | |
int matrixData[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
int matrixMask[] = { 0xC0, 0x18, 0x03 }; | |
for(int i = 0; i < ENEMIES; i++){ | |
if(l_EnemyObject[i].alive == true){ | |
matrixData[l_EnemyObject[i].row] |= matrixMask[l_EnemyObject[i].col]; | |
} | |
} | |
matrix.write((char)matrixData[0], (char)matrixData[1], (char)matrixData[2], | |
(char)matrixData[3], (char)matrixData[4], (char)matrixData[5], | |
(char)matrixData[6], (char)matrixData[7]); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment