Tetris for the RA8875, derived from another users implementation.

Dependencies:   RA8875

Fork of Tetris by Sergejs Popovs

Tetris, adapted to the RA8875 graphics library and display.

As currently implemented, this version is defined for the 800x480 display. A number of macros can adapt it for other screen resolutions.

Further, while presently configured for landscape mode, it should be fairly easy to reconfigure it for portrait mode.

Tetris/playGround.cpp

Committer:
WiredHome
Date:
2017-03-18
Revision:
5:5ce8976cd303
Child:
6:d2aa47c92687

File content as of revision 5:5ce8976cd303:

#include "mbed.h"
#include "playGround.h"
#include "Piece.h"
#include "Block.h"
#include "Field.h"
#include "BPG_Arial20x20.h"
#include "BPG_Arial10x10.h"
#include "Define.h"
#include <ctime>

// Define this for 800x480 panel, undefine for 480x272
#define BIG_SCREEN

// Define this for Cap touch panel, undefine for resistive
#define CAP_TOUCH

#ifdef CAP_TOUCH
RA8875 TFT(p5,p6,p7,p12,NC, p9,p10,p13, "tft"); // SPI:{MOSI,MISO,SCK,/ChipSelect,/reset}, I2C:{SDA,SCL,/IRQ}, name
#else
RA8875 TFT(p5,p6,p7,p12,NC, "tft");             // SPI:{MOSI,MISO,SCK,/ChipSelect,/reset}, name
LocalFileSystem local("local");                     // access to calibration file for resistive touch.
#endif

#ifdef BIG_SCREEN
    #define LCD_W 800
    #define LCD_H 480
    #define LCD_C 8         // color - bits per pixel
    #define BL_NORM 25      // Backlight Normal setting (0 to 255)
#else
    #define LCD_W 480
    #define LCD_H 272
    #define LCD_C 8         // color - bits per pixel
    #define BL_NORM 25      // Backlight Normal setting (0 to 255)
#endif

#if 0
#define PIN_XP              p20
#define PIN_XM              p19
#define PIN_YP              p18
#define PIN_YM              p17
#define PIN_MOSI            p11
#define PIN_MISO            p12
#define PIN_SCLK            p13
#define PIN_CS_TFT          p14
#define PIN_DC_TFT          p21
#define PIN_BL_TFT          p15
#define PIN_CS_SD           p4
#endif 

// Hot-Spots
static const rect_t Drop   = { DROP };
static const rect_t rLeft  = { ROT_LEFT };
static const rect_t rRight = { ROT_RIGHT };
static const rect_t mLeft  = { MOV_LEFT };
static const rect_t mRight = { MOV_RIGHT };
static const rect_t Replay = { REPLAY };

//  Draws Field on the screen. Draw both black and colored blocks
//  It does delete everything on the PlayGround what shouldn't be there

void drawMap()
{
    int y , x;

    for ( y = 0 ; y < MAXY ; y++ ) {
        for ( x = 0 ; x < MAXX ; x++ ) {
            if ( Field[y][x] != 0 ) {
                TFT.fillrect(ORIGIN_X + BLOCK_SIZE * ( x + 1 ), ORIGIN_Y + BLOCK_SIZE * y,
                             ORIGIN_X + BLOCK_SIZE * ( x + 2 ), ORIGIN_Y + BLOCK_SIZE * ( y + 1 ),
                             Field[y][x]);
                TFT.rect(ORIGIN_X + BLOCK_SIZE * ( x + 1 ), ORIGIN_Y + BLOCK_SIZE * y,
                         ORIGIN_X + BLOCK_SIZE * ( x + 2 ), ORIGIN_Y + BLOCK_SIZE * ( y + 1 ),
                         White );
            }
        }
    }
}

//  Draws Field on the screen. Draw only colored blocks
//  It doesn't delete anything on the playground what shouldn't be there

void drawMapV2()
{
    int y , x;

    for ( y = 0 ; y < MAXY ; y++ ) {
        for ( x = 0 ; x < MAXX ; x++ ) {
            TFT.fillrect(ORIGIN_X + BLOCK_SIZE * ( x + 1 ), ORIGIN_Y + BLOCK_SIZE * y,
                         ORIGIN_X + BLOCK_SIZE * ( x + 2 ), ORIGIN_Y + BLOCK_SIZE * ( y + 1 ),
                         Field[y][x]);
            if ( Field[y][x] != 0 )
                TFT.rect(ORIGIN_X + BLOCK_SIZE * ( x + 1 ), ORIGIN_Y + BLOCK_SIZE * y,
                         ORIGIN_X + BLOCK_SIZE * ( x + 2 ), ORIGIN_Y + BLOCK_SIZE * ( y + 1 ),
                         White );
        }
    }
}

//  Draws NewBlock on the playground. 

void drawBlock(Block NewBlock)
{
    int ix , iy , x , y;
    x = NewBlock.x;
    y = NewBlock.y;
    for ( ix = x - 2 ; ix < x + 2 ; ix++ ) {
        for ( iy = y - 2 ; iy < y + 2 ; iy++ ) {
            if ( Piece[NewBlock.form][NewBlock.angle][ix - x + 2][iy - y + 2] != 0 ) {
                TFT.fillrect(ORIGIN_X + BLOCK_SIZE * ( ix + 1 ), ORIGIN_Y + BLOCK_SIZE * iy,
                             ORIGIN_X + BLOCK_SIZE * ( ix + 2 ), ORIGIN_Y + BLOCK_SIZE * ( iy + 1 ),
                             Piece[NewBlock.form][NewBlock.angle][ix - x + 2][iy - y + 2]);
                TFT.rect(ORIGIN_X + BLOCK_SIZE * ( ix + 1 ), ORIGIN_Y + BLOCK_SIZE * iy,
                         ORIGIN_X + BLOCK_SIZE * ( ix + 2 ), ORIGIN_Y + BLOCK_SIZE * ( iy + 1 ),
                         White );
            }
        }
    }
}

//  Removes NewBlock from the playground. 

void clrBlock(Block NewBlock)
{
    int ix , iy , x , y;
    x = NewBlock.x;
    y = NewBlock.y;
    for ( ix = x - 2 ; ix < x + 2 ; ix++ ) {
        for ( iy = y - 2 ; iy < y + 2 ; iy++ ) {
            if ( Piece[NewBlock.form][NewBlock.angle][ix - x + 2][iy - y + 2] != 0 ) {
                TFT.fillrect(ORIGIN_X + BLOCK_SIZE * ( ix + 1 ), ORIGIN_Y + BLOCK_SIZE * iy,
                             ORIGIN_X + BLOCK_SIZE * ( ix + 2 ), ORIGIN_Y + BLOCK_SIZE * ( iy + 1 ),
                             Black );
            }
        }
    }
}

//  Draws Purple frame around playground

void drawFrame()
{
    int x, y;
    for ( y = 0 ; y < (MAXY + 1) * BLOCK_SIZE ; y += BLOCK_SIZE ) {
        TFT.fillrect(ORIGIN_X + 0, ORIGIN_Y + y, ORIGIN_X + BLOCK_SIZE, ORIGIN_Y + y + BLOCK_SIZE, Purple );
        TFT.rect(ORIGIN_X + 0, ORIGIN_Y + y, ORIGIN_X + BLOCK_SIZE, ORIGIN_Y + y + BLOCK_SIZE, DarkGray );
        TFT.fillrect(ORIGIN_X + (MAXX + 1) * BLOCK_SIZE, ORIGIN_Y + y, ORIGIN_X + (MAXX + 2) * BLOCK_SIZE, ORIGIN_Y + y + BLOCK_SIZE, Purple );
        TFT.rect(ORIGIN_X + (MAXX + 1) * BLOCK_SIZE, ORIGIN_Y + y, ORIGIN_X + (MAXX + 2) * BLOCK_SIZE, ORIGIN_Y + y + BLOCK_SIZE, DarkGray );
    }
    for ( x = 0 ; x < (MAXX + 2) * BLOCK_SIZE ; x += BLOCK_SIZE ) {
        TFT.fillrect(ORIGIN_X + x, ORIGIN_Y + MAXY * BLOCK_SIZE, ORIGIN_X + x + BLOCK_SIZE, ORIGIN_Y + (MAXY + 1) * BLOCK_SIZE, Purple );
        TFT.rect(ORIGIN_X + x, ORIGIN_Y + MAXY * BLOCK_SIZE, ORIGIN_X + x + BLOCK_SIZE, ORIGIN_Y + (MAXY + 1) * BLOCK_SIZE, DarkGray );
    }
}

//  Initializes screen parameters, sets orentation, background,
//  fonts and cleans screen.

void TFTInit()
{
    TFT.init(LCD_W,LCD_H,LCD_C);
    TFT.TouchPanelInit();
    TFT.Backlight_u8(BL_NORM);
    TFT.SetOrientation();
}

void ReInitGame() {
    TFT.foreground(White);
    TFT.background(Black);
    TFT.cls();
    TFT.SetLayerMode(RA8875::BooleanOR);
    TFT.SelectUserFont(BPG_Arial20x20);
    TFT.SelectDrawingLayer(1);
    TFT.SetGraphicsCursor(TITLE_X,TITLE_Y);
    TFT.printf("Tetris for the RA8875\r\n");
    TFT.SelectUserFont(BPG_Arial10x10);
    TFT.printf("   adapted by Smartware Computing");
    TFT.rect(Drop, Charcoal);
    TFT.rect(rLeft, Charcoal);
    TFT.rect(rRight, Charcoal);
    TFT.rect(mLeft, Charcoal);
    TFT.rect(mRight, Charcoal);
    TFT.SelectDrawingLayer(0);
}

void gameOver(int score)
{
    drawScore(score);
    TFT.fillrect(Replay, Blue);
    TFT.rect(Replay, White);
    TFT.SetTextCursor(Replay.p1.x+15,(Replay.p1.y+Replay.p2.y)/2-TFT.fontheight()/2);
    TFT.foreground(White);
    TFT.background(Blue);
    TFT.puts("Replay");
}

bool ReplayTouched() {
    point_t p;
    
    if (TFT.TouchPanelReadable(&p))
        return true;
    else
        return false;
}

void drawScore(int score)
{
    TFT.SelectUserFont(BPG_Arial20x20);
    TFT.SetTextCursor(SCORE_X, SCORE_Y);
    TFT.foreground(BrightRed);
    TFT.printf("Score : %i", score);
}


//  Reads gestures from the screen. 
//  Returns         :   0 for dropping object down
//                      1 for moving object to the right
//                      2 for moving object to the left
//                      3 for rotating object counter-clockwise
//                      4 for rotating objec clockwise
int getGesture()
{
    point_t p;
    clock_t start_s = clock();
    int flag = 0;
    while( !flag ) {
        p.x=0;
        p.y=0;
        TouchCode_t t = TFT.TouchCode();
        if ( t == touch || t == held ) {
            p = TFT.TouchCoordinates();            // read analog pos.
            flag = 1;
        } else if ( start_s > 10 )
            return 13;
    }
    if ( TFT.Intersect(Drop,p) ) {      // below the bottom to drop
        return 0 ;
    } else if ( TFT.Intersect(rLeft, p) ) {
        return 3;
    } else if ( TFT.Intersect(rRight, p) ) {
        return 4;
    } else if ( TFT.Intersect(mLeft, p) ) {
        return 2;
    } else if ( TFT.Intersect(mRight, p) ) {
        return 1;
    }
    return 13;         //13 = IGNORE
}

//  Returns status of screen. If it was touched returns true, else false

bool TouchStatus()
{
    if ( TFT.TouchPanelReadable() )
        return true;
    return false;
}

//  Moves NewBlock acording the gesture was read by function getGesture.

Block doGest(Block NewBlock)
{
    static bool lockout = false;
    int gest = getGesture();
    if ( gest != 13 ) {
        switch ( gest ) {
            case 0: {
                while ( !NewBlock.CheckBottom() ) {
                    NewBlock.y++;
                }
                saveToField(NewBlock);
                drawFrame();
                lockout = false;
                break;
            }
            case 1: {
                NewBlock.moveRight();
                lockout = false;
                break;
            }
            case 2: {
                NewBlock.moveLeft();
                lockout = false;
                break;
            }
            case 3: {
                if (!lockout) {
                    lockout = true;
                    NewBlock.rotateLeft();
                }
                break;
            }
            case 4: {
                if (!lockout) {
                    lockout = true;
                    NewBlock.rotateRight();
                }
                break;
            }
        }
    } else {
        lockout = false;
    }
    return NewBlock;
}


//  Draws the next block on the bottom of the screen. 
//  Block is sized of SMALL_BLOCK_SIZED

void drawNextBlock(Block NewBlock)
{
    int ix, iy;

    for ( ix = - 2 ; ix < 2 ; ix++ ) {
        for ( iy = - 2 ; iy < 2 ; iy++ ) {
            rect_t r;

            r.p1.x = SB_X - 2 * SMALL_BLOCK_SIZE + SMALL_BLOCK_SIZE * ( ix + 1 );
            r.p1.y = SB_Y - 2 * SMALL_BLOCK_SIZE + SMALL_BLOCK_SIZE * iy;
            r.p2.x = SB_X - 2 * SMALL_BLOCK_SIZE + SMALL_BLOCK_SIZE * ( ix + 2 );
            r.p2.y = SB_Y - 2 * SMALL_BLOCK_SIZE + SMALL_BLOCK_SIZE * ( iy + 1 );
            if ( Piece[NewBlock.nextForm][NewBlock.angle][ix + 2][iy + 2] != 0 ) {
                TFT.fillrect(r, Piece[NewBlock.nextForm][NewBlock.angle][ix + 2][iy + 2]);
                TFT.rect(r, White );
            }
        }
    }
}

void clrNextBlock(Block NewBlock)
{
    rect_t r;
    
    r.p1.x = SB_X - 2 * SMALL_BLOCK_SIZE + SMALL_BLOCK_SIZE * ( -2 + 1 );
    r.p1.y = SB_Y - 2 * SMALL_BLOCK_SIZE + SMALL_BLOCK_SIZE * -2;
    r.p2.x = SB_X - 2 * SMALL_BLOCK_SIZE + SMALL_BLOCK_SIZE * ( 1 + 2 );
    r.p2.y = SB_Y - 2 * SMALL_BLOCK_SIZE + SMALL_BLOCK_SIZE * ( 1 + 1 );
    TFT.fillrect( r, Black );
}