I simplified the library "ILI9225_TFT" provided by Arman Safikhani to better suit my needs in implementing a simple sliding puzzle game.

States.h

Committer:
blac3777
Date:
2018-04-27
Revision:
3:251e4d020501

File content as of revision 3:251e4d020501:

#include "Fonts.h"

//STATE 0
//GLCD Displays the start screen - encouraging the player to start the game
//by displaying the message "PRESS SELECT TO START".
//
//Player must press the SELECT button to trigger the next STATE.
void greetingScreen() {
    tft.clear();
    tft.setFont(Terminal12x16);
    tft.drawText(60, 40, "PRESS", COLOR_RED);
    tft.drawText(54, 65, "SELECT", COLOR_RED);
    tft.drawText(77, 90, "TO", COLOR_RED);
    tft.drawText(60, 115, "START", COLOR_RED);
    
    while(1) {
        if(getPlayerInput(wirelessInput_Freq) == 6) //SELECT -> 6
            return;
    }
}

//STATE 1
//GLCD encourages player to take a picture of something by displaying the
//message "SELECT TO TAKE PICTURE".
//
//Player must press the SELECT button to take a picture and trigger the next
//STATE.
void takePicture() {
    tft.clear();
    tft.setFont(Terminal12x16);
    tft.drawText(54, 40, "SELECT", COLOR_RED);
    tft.drawText(77, 65, "TO", COLOR_RED);
    tft.drawText(65, 90, "TAKE", COLOR_RED);
    tft.drawText(50, 115, "PICTURE", COLOR_RED);
    
    while(1) {
        if(getPlayerInput(wirelessInput_Freq) == 6) { //SELECT -> 6
            for(int index = 0; index < 19200; index++)
                handlePixel(index, getNextPixel());
            return;
        }
    }
}

//STATE 2
//GLCD will display the picture taken in STATE 1 @ the bottom of the screen.
//
//Player input is ignored during this STATE.
void previewPicture() {
    tft.clear();
    updatePuzzle();
}

//STATE 3
//GLCD will display the message "SELECT > ACCEPT" atop "OR" atop
//"CANCEL > RETAKE" at the top of the screen.
//
//Player may press SELECT to continue (STATE 4) w| picture or CANCEL to retake
//the picture (STATE 1).
bool confirmPicture() {
    tft.fillRectangle(0, 0, 175, 91, COLOR_BLACK);
    tft.setFont(Terminal12x16);
    tft.drawText(4, 8, "SELECT > ACCEPT", COLOR_RED);
    tft.drawText(77, 33, "OR", COLOR_RED);
    tft.drawText(4, 58, "CANCEL > RETAKE", COLOR_RED);
    //printElementsInPicture();
    
    while(1) {
        if(getPlayerInput(wirelessInput_Freq) == 6) //SELECT -> 6
            return true; //Confirm the picture by returning true
        else if(getPlayerInput(wirelessInput_Freq) == 7) //CANCEL -> 7
            return false; //Retake the picture by returning false
    }
}

//STATE 4
//GLCD will display the message "LOADING" and keeps it there until the
//LPC1769 has finished shuffling the pieces in the background. When it is done,
//it will black out the screen, populate the 4x4 grid with the puzzle pieces,
//and start the player off at index 0 of the puzzle grid.
//Remark: 2 out of 16 of the puzzle pieces will be missing. There were 3 reasons
//that led us to this design choice:
//1) We had to remove, at the very least, 1 puzzle piece to make a classic
//sliding puzzle game.
//2) We desired that the sizeof(picture) << 32kB but we still wanted a colored
//image (i.e., 16 bit aray element) so we needed to get rid of 2 pieces to reach
//our goal.
//3) If puzzle piece positions for a classic sliding puzzle game are generated
//completely randomly then they are only solvable 50% of the time based off
//whether there is an even amount of permutations. There are applicable methods
//for only generating solvable puzzles but another (and easier) solution is to
//just remove a second puzzle piece.
//
//The player's button presses are ignored during this time.
void shufflePuzzle() {
    tft.clear();
    tft.setFont(Terminal12x16);
    tft.drawText(47, 40, "LOADING", COLOR_RED);

    shuffleGridIndices();

    tft.clear();
    updatePuzzle();
    cursorIndex = 0;
    highlightGridIndex(cursorIndex, false);
}

//STATE 5
//We wait for the player to press SELECT. If the player presses SELECT we must
//verify 2 characteristics about the target piece before we may trigger STATE 6:
//1) Target puzzle piece is NOT one of the 2 missing puzzle pieces.
//2) Target puzzle piece is NOT locked on all 4 sides.
//
//At this point, the player is able to use the UP, DOWN, LEFT, and RIGHT buttons
//to move around their cursor until they find a piece that they want to swap
//for another piece. While their cursor is hovering over the target piece, they
//would press SELECT to "grab it". The cursor is green in this state.
uint8_t selectionMode() {
    highlightGridIndex(cursorIndex, false);
    //printElementsInPicture();
    while(1) {
        if(getPlayerInput(wirelessInput_Freq) == 6) { //SELECT -> 6
            if(selectionMode_indexVerified(cursorIndex)) //& index verified
                return cursorIndex;
        }
        else if(getPlayerInput(wirelessInput_Freq) == 2 //UP -> 2
            && cursorIndex - 4 > -1)
            highlightGridIndex(cursorIndex - 4, false);
        else if(getPlayerInput(wirelessInput_Freq) == 3 //DOWN -> 3
            && cursorIndex + 4 < 16)
            highlightGridIndex(cursorIndex + 4, false);
        else if(getPlayerInput(wirelessInput_Freq) == 4 //LEFT -> 4
            && ((cursorIndex%4) - 1) > -1)
            highlightGridIndex(cursorIndex - 1, false);
        else if(getPlayerInput(wirelessInput_Freq) == 5 //RIGHT -> 5
            && ((cursorIndex%4) + 1) < 4)
            highlightGridIndex(cursorIndex + 1, false);
    }
}

//STATE 6
//If player presses UP, DOWN, LEFT, or RIGHT, we verify that target index is an
//empty space before making the move and triggering STATE 5. A piece may only be
//moved 1 index position and it may only be moved to 1 of the 2 missing puzzle
//piece indices.
//
//Only UP, DOWN, LEFT, RIGHT, and CANCEL are monitored during this state.
//Pressing CANCEL, at any time, would restore us back to STATE 5 and no swapping
//would occur. The cursor is red in this state.
void selectedMode(uint8_t selectedIndex) {
    highlightGridIndex(selectedIndex, true);

    while(1) {
        if(getPlayerInput(wirelessInput_Freq) == 7) //CANCEL -> 7
            return;
        if(getPlayerInput(wirelessInput_Freq) == 2 //UP -> 2
            && selectedIndex - 4 > -1) {
            if(puzzState[selectedIndex - 4] > 13) { //Empty space above?
                swap(&puzzState[selectedIndex], &puzzState[selectedIndex - 4]);
                updatePuzzle();
                cursorIndex = selectedIndex - 4;
                return;
            }
        }
        if(getPlayerInput(wirelessInput_Freq) == 3 //DOWN -> 3
            && selectedIndex + 4 < 16) {
            if(puzzState[selectedIndex + 4] > 13) { //Empty space below?
                swap(&puzzState[selectedIndex], &puzzState[selectedIndex + 4]);
                updatePuzzle();
                cursorIndex = selectedIndex + 4;
                return;
            }
        }
        if(getPlayerInput(wirelessInput_Freq) == 4 //LEFT -> 4
            && ((selectedIndex%4) - 1) > -1) {
            if(puzzState[selectedIndex - 1] > 13) { //Empty space to the left?
                swap(&puzzState[selectedIndex], &puzzState[selectedIndex - 1]);
                updatePuzzle();
                cursorIndex = selectedIndex - 1;
                return;
            }
        }
        if(getPlayerInput(wirelessInput_Freq) == 5 //RIGHT -> 5
            && ((selectedIndex%4) + 1) < 4) {
            if(puzzState[selectedIndex + 1] > 13) { //Empty space to the right?
                swap(&puzzState[selectedIndex], &puzzState[selectedIndex + 1]);
                updatePuzzle();
                cursorIndex = selectedIndex + 1;
                return;
            }
        }
    }
}