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:
2020-03-28
Revision:
10:a09d9bb9c5c8
Parent:
9:b97b336ab36a

File content as of revision 10:a09d9bb9c5c8:

#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>

#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
#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 };
static const point_t orig  = { ORIGIN_X,ORIGIN_Y };
static const point_t sb_orig = { SB_X, SB_Y };
// Convert cell coordinates to a rectangle location
//
rect_t CellPosToRect(int x, int y, point_t o = orig, int bs = BLOCK_SIZE) {
    rect_t r;
    
    r.p1.x = o.x + bs * (x + 1);
    r.p1.y = o.y + bs * (y + 0);
    r.p2.x = o.x + bs * (x + 2);
    r.p2.y = o.y + bs * (y + 1);
    return r;
}

//  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 ) {
                rect_t r = CellPosToRect(x,y);
                TFT.fillrect(r, Field[y][x]);
                TFT.rect(r, 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++ ) {
            rect_t r = CellPosToRect(x,y);
            TFT.fillrect(r, Field[y][x]);
            if ( Field[y][x] != 0 )
                TFT.rect(r, 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 ) {
                rect_t r = CellPosToRect(ix,iy);
                TFT.fillrect(r, Piece[NewBlock.form][NewBlock.angle][ix - x + 2][iy - y + 2]);
                TFT.rect(r, 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 ) {
                rect_t r = CellPosToRect(ix,iy);
                TFT.fillrect(r, Black );
            }
        }
    }
}


//  Draws Purple frame around playground
//
void drawFrame()
{
    int x, y;

    for ( y = 0 ; y < (MAXY) ; y++ ) {
        rect_t r = CellPosToRect(-1,y);

        TFT.fillrect(r, Purple );
        TFT.rect(r, DarkGray );
        r = CellPosToRect(MAXX,y);
        TFT.fillrect(r, Purple );
        TFT.rect(r, DarkGray );
    }
    for ( x = -1 ; x < (MAXX + 1) ; x++ ) {
        rect_t r = CellPosToRect(x,MAXY);

        TFT.fillrect(r, Purple );
        TFT.rect(r, 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.SetGraphicsOrientation();
}


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);
    for (int y=0; y<MAXY; y++) {
        for (int x=0; x<MAXX; x++) {
            Field[y][x] = 0;
        }
    }
    drawFrame();
    drawMap();
}


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


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

void drawPeriod(int period)
{
    TFT.SelectUserFont(BPG_Arial10x10);
    TFT.SetTextCursor(PACE_X, PACE_Y);
    TFT.foreground(Brown);
    TFT.printf("Pace : %i", period);    
}

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 objec clockwise
//                      4 for rotating object counter-clockwise
//                      13 for ignore
gesture_t getGesture(point_t p)
{
    gesture_t gesture = ignore;

    if (TFT.Intersect(Drop,p) ) {      // below the bottom to drop
        gesture = drop;
    } else if (TFT.Intersect(rLeft, p) ) {
        return spin_ccw;
    } else if (TFT.Intersect(rRight, p) ) {
        return spin_cw;
    } else if (TFT.Intersect(mLeft, p) ) {
        return move_left;
    } else if (TFT.Intersect(mRight, p) ) {
        return move_right;
    }
    return gesture;
}



//  Moves NewBlock acording the gesture was read by function getGesture.
//
Block doGest(Block NewBlock, point_t p)
{
    static bool lockout = false;
    gesture_t gest = getGesture(p);
    if ( gest != ignore ) {
        switch ( gest ) {
            case drop: {
                while ( !NewBlock.CheckBottom() ) {
                    NewBlock.y++;
                }
                saveToField(NewBlock);
                drawFrame();
                lockout = false;
                break;
            }
            case move_right: {
                NewBlock.moveRight();
                lockout = false;
                break;
            }
            case move_left: {
                NewBlock.moveLeft();
                lockout = false;
                break;
            }
            case spin_ccw: {
                if (!lockout) {
                    NewBlock.rotateLeft();
                }
                break;
            }
            case spin_cw: {
                if (!lockout) {
                    NewBlock.rotateRight();
                }
                break;
            }
        }
    } else {
        lockout = false;
    }
    return NewBlock;
}


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

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

    for ( ix = 0 ; ix < 4 ; ix++ ) {
        for ( iy = 0 ; iy < 4 ; iy++ ) {
            rect_t r = CellPosToRect(ix,iy, sb_orig, SB_SIZE);

            if ( Piece[NewBlock.nextForm][NewBlock.angle][ix][iy] != 0 ) {
                TFT.fillrect(r, Piece[NewBlock.nextForm][NewBlock.angle][ix][iy]);
                TFT.rect(r, White );
            }
        }
    }
}


//  Clear the Next Block indicator
//
void clrNextBlock(Block NewBlock)
{
    rect_t r0 = CellPosToRect(0,0, sb_orig, SB_SIZE);
    rect_t r1 = CellPosToRect(3,3, sb_orig, SB_SIZE);
    rect_t r;
    r.p1 = r0.p1;
    r.p2 = r1.p2;
    TFT.fillrect( r, Black );
}