#include <Keypad.h>
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
/*
Working,
Newest changes for delay in sounds.
*/
//tones
#define NOTE_B0 31
#define NOTE_C1 33
#define NOTE_CS1 35
#define NOTE_D1 37
#define NOTE_DS1 39
#define NOTE_E1 41
#define NOTE_F1 44
#define NOTE_FS1 46
#define NOTE_G1 49
#define NOTE_GS1 52
#define NOTE_A1 55
#define NOTE_AS1 58
#define NOTE_B1 62
#define NOTE_C2 65
#define NOTE_CS2 69
#define NOTE_D2 73
#define NOTE_DS2 78
#define NOTE_E2 82
#define NOTE_F2 87
#define NOTE_FS2 93
#define NOTE_G2 98
#define NOTE_GS2 104
#define NOTE_A2 110
#define NOTE_AS2 117
#define NOTE_B2 123
#define NOTE_C3 131
#define NOTE_CS3 139
#define NOTE_D3 147
#define NOTE_DS3 156
#define NOTE_E3 165
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_CS5 554
#define NOTE_D5 587
#define NOTE_DS5 622
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_FS5 740
#define NOTE_G5 784
#define NOTE_GS5 831
#define NOTE_A5 880
#define NOTE_AS5 932
#define NOTE_B5 988
#define NOTE_C6 1047
#define NOTE_CS6 1109
#define NOTE_D6 1175
#define NOTE_DS6 1245
#define NOTE_E6 1319
#define NOTE_F6 1397
#define NOTE_FS6 1480
#define NOTE_G6 1568
#define NOTE_GS6 1661
#define NOTE_A6 1760
#define NOTE_AS6 1865
#define NOTE_B6 1976
#define NOTE_C7 2093
#define NOTE_CS7 2217
#define NOTE_D7 2349
#define NOTE_DS7 2489
#define NOTE_E7 2637
#define NOTE_F7 2794
#define NOTE_FS7 2960
#define NOTE_G7 3136
#define NOTE_GS7 3322
#define NOTE_A7 3520
#define NOTE_AS7 3729
#define NOTE_B7 3951
#define NOTE_C8 4186
#define NOTE_CS8 4435
#define NOTE_D8 4699
#define NOTE_DS8 4978
//create the screen variable from the library
TFT_eSPI tft = TFT_eSPI();
//Sprite
TFT_eSprite img = TFT_eSprite(&tft);
// Set up variables for the cursor and counter. Cursor starts in the middle of the screen.
//Screen size: (480 x 320)
//float cursorX = 240.0;
//float cursorY = 160.0;
//Sound pin.
int sound = 11;
int greenPin = 22;
int redPin = 23;
//If we rotate screen.
int screenSizeX = 320;
int screenSizeY = 480;
int resetCount = 0;
// Setting the joystick pins here so we can easily change them
#define JOYSTICK_X_PIN A14
#define JOYSTICK_Y_PIN A15
#define JOYSTICK_BUTTON_PIN 38
// Define colours in 4-digit hex
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
const int ROWS_NUM = 4; //Keypad rows.
const int COLUMNS_NUM = 4; //Keypad columns.
//symbols on keypad.
char keys[ROWS_NUM][COLUMNS_NUM] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
//Pin Connections.
byte pin_rows[ROWS_NUM] = {9,8,7,6}; //connect to row pinouts.
byte pin_column[COLUMNS_NUM] = {5,4,3,2}; //connect to column pinouts.
//Inititalizing instance of keypad.
Keypad ourKeypad = Keypad(makeKeymap(keys), pin_rows, pin_column, ROWS_NUM, COLUMNS_NUM);
//level 0 before game start.
int levelCount = 0;
//Just for start up screen.
bool gameStarted = false;
int delayTime = 150;
void setup() {
Serial.begin(9600);
// Initalize the screen and set the orientation correctly, then make sure it's clear.
tft.begin();
tft.setRotation(2); //can be 0,1,2,3.
tft.fillScreen(BLACK);
//Starting screen.
tft.setTextColor(RED);
tft.setTextSize(3);
pinMode(11, OUTPUT);//Setting pinMode for sounds.
pinMode(21, OUTPUT);
//create sprite
img.createSprite(240,135);
}
void loop() {
//TESTING
//img.fillCircle(0,36,30,BLACK);
//tft.drawString(23, 20, 74, 7);
//delay(10000);
Serial.println("Loop started.");
//New level start.
if (gameStarted == false) {
gameBeginScreen();
}
long correctSeq[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //Correct sequence list of ten numbers.
//logic.
for (int i = 0; i <= levelCount; ++i) { //for loop for each level.
Serial.println("For loop entered.");
//neccessary for the beginning of every level.
levelCount++; //will start level 1 at 1.
Serial.print("Level "); Serial.print(levelCount); Serial.println(" has started.");
long userSeq[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //User Choice.
//Displaying shapes. (After this for is completely, correctSeq[] should be fully populated)
for (int x = 0; x < (i+1); x++) { //for loop depending on level.
//base grid
tft.drawRoundRect(10, 90, 300, 300, 5, RED);
if (x == i){ //if last square.
long position = random(1,9); //Decide random positon.
correctSeq[x] = position;//Populating correctSeq array for level (i).
Serial.print("Position "); Serial.print(position); Serial.print(" stored in index value "); Serial.println(x);
}
printShape(correctSeq[x]); //Print shape.
Serial.print("Shape "); Serial.print(x+1); Serial.print(" printed for level "); Serial.println(levelCount);
}
tft.fillScreen(BLACK);
tft.drawCentreString("Your Turn!", screenSizeX/2, screenSizeY/2,2);
//Letting user emulate.
Serial.println("User's turn.");
int userChoices = 0; //Player has not yet inputted on keys (will add upon input from player).
while (userChoices <= i) { //While player has not fully populated userSeq[] array.
//Key listeners.
char customKey = ourKeypad.getKey();
String keyConv = String(customKey);
int numKey = keyConv.toInt();
//Serial.println("User loop listener running.");
if (customKey) { //if a key is pressed.
Serial.print("Key pressed is "); Serial.println(customKey);
//update userSeq.
userSeq[userChoices] = numKey;
++userChoices; //Take into account user has populated an index in userSeq[] array.
playSound(numKey);
}
} //Once player has fully populated userSeq[] array, leave loop and move on.
//After both the sequence and the user arrays have been populated, compare them.
if (seqCompare(userSeq, correctSeq)) { //Calls function which compares arrays.
tft.fillScreen(BLACK);
Serial.println("Correct Sequence.");
String levelDisp = "Level " + String(i+1);
tft.drawCentreString(levelDisp, screenSizeX/2, (screenSizeY/2) - 30, 2);
tft.drawCentreString("Complete", screenSizeX/2, (screenSizeY/2) + 10, 2);
playSound(99); //Level passed sound.
tft.fillScreen(BLACK);
} else { //call reboot sequence.
rebootSeq();
break;
//Manual game restart.
}
}
//Reset logic and await next level.
}
void printShape(long thisSpot) {
//This function displays the shape and logs spot (1-9)
/*
320 x 390
square height and width = 80
x and y space in between = 20
x margin = 20
y margin = 100
*/
int squareWH = 80;
int rad = 5;
int time = 150;
long spot = thisSpot;
if (spot == 1) {
tft.fillRoundRect(20, 100, squareWH, squareWH, rad, RED);
playSound(spot);
delay(time);
tft.fillRoundRect(120, 100, squareWH , squareWH, rad, BLACK);
//need to clear screen.
} else if (spot == 2) {
tft.fillRoundRect(120, 100, squareWH , squareWH, rad, RED);
playSound(spot);
delay(time);
tft.fillRoundRect(120, 100, squareWH , squareWH, rad, BLACK);
} else if (spot == 3) {
tft.fillRoundRect(220, 100, squareWH , squareWH, rad, RED);
playSound(spot);
delay(time);
tft.fillRoundRect(220, 100, squareWH , squareWH, rad, BLACK);
} else if (spot == 4) {
tft.fillRoundRect(20, 200, squareWH , squareWH, rad, RED);
playSound(spot);
delay(time);
tft.fillRoundRect(20, 200, squareWH , squareWH, rad, BLACK);
} else if (spot == 5) {
tft.fillRoundRect(120, 200, squareWH , squareWH, rad, RED);
playSound(spot);
delay(time);
tft.fillRoundRect(120, 200, squareWH , squareWH, rad, BLACK);
} else if (spot == 6) {
tft.fillRoundRect(220, 200, squareWH , squareWH, rad, RED);
playSound(spot);
delay(time);
tft.fillRoundRect(220, 200, squareWH , squareWH, rad, BLACK);
} else if (spot == 7) {
tft.fillRoundRect(20, 300, squareWH , squareWH, rad, RED);
playSound(spot);
delay(time);
tft.fillRoundRect(20, 300, squareWH , squareWH, rad, BLACK);
} else if (spot == 8) {
tft.fillRoundRect(120, 300, squareWH , squareWH, rad, RED);
playSound(spot);
delay(time);
tft.fillRoundRect(120, 300, squareWH , squareWH, rad, BLACK);
} else if (spot == 9) {
tft.fillRoundRect(220, 300, squareWH , squareWH, rad, RED);
playSound(spot);
delay(time);
tft.fillRoundRect(220, 300, squareWH , squareWH, rad, BLACK);
}
}
void gameBeginScreen() {
tft.fillScreen(BLACK);
tft.drawCentreString("Press any key", screenSizeX/2,(screenSizeY/2) - 20, 1);
tft.drawCentreString("to start!", screenSizeX/2,(screenSizeY/2) + 10, 1);
while (true) { //key listening.
char customKey = ourKeypad.getKey();
if (customKey) {
break;
}
Serial.print("Key not pressed.");
}
gameStarted = true;
tft.fillScreen(BLACK);
tft.drawCentreString("Game starting...", screenSizeX/2,screenSizeY/2, 1);
delay(1000);
tft.fillScreen(BLACK);
tft.setCursor(screenSizeX/2, screenSizeY/3);
for (int i = 3; i > 0; --i) { //displaying 1,2,3.
Serial.print("Game starting in "); Serial.println(i);
tft.setCursor(screenSizeX/2, screenSizeY/2);
tft.println(i);
delay(100); //wait 1 second.
tft.fillScreen(BLACK);
}
tft.fillScreen(BLACK);
}
bool seqCompare (long player[], long correct[]) { //checks if userSeq is equal to keySeq.
//Print arrays to serial.
Serial.print("Correct Seq:");
for (int i = 0; i < 10; i++) {
Serial.print(correct[i]);
}
for (int i = 0; i < 10; ++i) { //will check 10 indexes ranging from 0-9 in both arrays.
if (player[i] != correct[i]) { //if the values are not the same in each array.
return false; //user did not enter correct sequence.
}
}
return true; //if the conditional statement is never entered, it means the arrays are the same and returns true.
}
void rebootSeq() { //Call once game ends.
tft.fillScreen(BLACK);
playSound(0); //Game end sound.
tft.drawCentreString("Wrong Sequence!", screenSizeX/2, screenSizeY/2, 2);
int levelCount = 0;
gameStarted = false;
delay(2000);
tft.fillScreen(BLACK);
}
void playSound(long spot) {
if (spot == 1) {
tone(sound, NOTE_C4, 100);
noTone(sound);
} else if (spot == 2) {
tone(sound, NOTE_CS4, 100);
noTone(sound);
} else if (spot == 3) {
tone(sound, NOTE_D4, 100);
noTone(sound);
} else if (spot == 4) {
tone(sound, NOTE_DS4, 100);
noTone(sound);
} else if (spot == 5) {
tone(sound, NOTE_E4, 100);
noTone(sound);
} else if (spot == 6) {
tone(sound, NOTE_F4, 100);
noTone(sound);
} else if (spot == 7) {
tone(sound, NOTE_FS4, 100);
noTone(sound);
} else if (spot == 8) {
tone(sound, NOTE_G4, 100);
noTone(sound);
} else if (spot == 9) {
tone(sound, NOTE_GS4, 100);
noTone(sound);
} else if (spot == 0) { //game over sound.
int melody[] = {NOTE_C5, NOTE_G4, NOTE_E4, NOTE_A4, NOTE_B4, NOTE_A4, NOTE_GS4, NOTE_AS4, NOTE_GS4, NOTE_G4, NOTE_D4, NOTE_E4};
int durations[] = { 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 2};
int size = sizeof(durations) / sizeof(int);
for (int note = 0; note < size; note++) {
//to calculate the note duration, take one second divided by the note type.
//e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
int duration = 1000 / durations[note];
tone(sound, melody[note], duration);
//to distinguish the notes, set a minimum time between them.
//the note's duration + 30% seems to work well:
int pauseBetweenNotes = duration * 1.30;
delay(pauseBetweenNotes);
//stop the tone playing:
noTone(sound);
}
} else if (spot == 99) { //level passed sound.
delay(2000);
}
}
void endgameMenu (char choice) {
if (choice == "A") {
} else if (choice == "B") {
}
}
void intructionView() {
}