NXP Rapid IoT prototyping kit port of Silabs "hungry gecko" smake-like game. https://os.mbed.com/teams/SiliconLabs/code/Hungry_gecko/

Dependencies:   lib_sx9500 GraphicsDisplay ColorMemLCD Large_fonts

See a detailed description of this project on Hackster.io . https://www.hackster.io/marcomerli/riotwear-snake-ca6dfc

main.cpp

Committer:
batman52
Date:
2019-12-26
Revision:
80:77210aa1ad9c
Parent:
79:0431b9fd3dc0
Child:
81:737dff75e013

File content as of revision 80:77210aa1ad9c:

/***************************************************************************//**
 * @file main.cpp
 * @brief Demo program for game Hungry Gecko
 *******************************************************************************
 * @section License
 * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
 *******************************************************************************
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 *
 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
 * obligation to support this Software. Silicon Labs is providing the
 * Software "AS IS", with no express or implied warranties of any kind,
 * including, but not limited to, any implied warranties of merchantability
 * or fitness for any particular purpose or warranties against infringement
 * of any proprietary rights of a third party.
 *
 * Silicon Labs will not be liable for any consequential, incidental, or
 * special damages, or any other relief, or for any claim by any third party,
 * arising from your use of this Software.
 *
 ******************************************************************************/

// #include "LS013B7DH03.h"
#include "gecko.h"
#include "food.h"
#include "settings.h"

// Rapid IoT LCD stuff
#include "ColorMemLCD.h"
#include "string"
#include "Prototype24x27.h"
#include "Prototype_num21x25.h"
#include "meirio_num11x14.h"


/**************************** Define I/O **************************************/

/* LEDS */
DigitalOut led_blue(LED_BLUE, 1); // 1 = OFF
DigitalOut led_red(LED_RED, 1);

/* Rapid IoT Buttons */
// InterruptIn in(PTA4);
InterruptIn in(PTE28);
InterruptIn inB1(PTE9);
// InterruptIn SW1(PTE8);
// DigitalIn SW3(PTE10);
// DigitalIn SW4(PTE28);

DigitalOut     lcd_light(PTE12, 1); // 1 = ON, 0 = OFF
ColorMemLCD    display( PTB22, PTB23, PTB21, PTB20, PTD15,  PTD9, "TFT");

/**************************** Define Timers ***********************************/

// LowPowerTicker ticker;
Ticker ticker;

/**************************** Global variables ********************************/

/* Flag that is set to true when the display is refreshed */
volatile bool refreshed = false;

/* Flag that is set to true by the ticker. Makes the gecko move at regular time intervals */
volatile bool updateDisplay = true;

/* A flag that ensures the controller to only read one click per frame */
volatile bool PBenabled = true;

/* Direction in which the gecko moves */
Direction dir = UP;

uint8_t score = 0;

/**************************** Define callback handlers ************************/
void tickerCallback(void);

/* Push button handlers */
void in_handler_B0();
void in_handler_B1();

/* Define game modes */
typedef enum {
    PLAY, STOP
} Modes;

/* Set the game mode */
Modes mode = PLAY;

void in_handler_B0()
{
    /* Only change the direction if push button is enabled */
    if (PBenabled) {
        switch (dir) {
            case (UP):
                dir = LEFT;
                break;
            case (DOWN):
                dir = RIGHT;
                break;
            case (RIGHT):
                dir = UP;
                break;
            case (LEFT):
                dir = DOWN;
                break;
        }
        PBenabled = false;
    }
}

void in_handler_B1()
{
    /* Only change the direction if push button is enabled */
    if (PBenabled) {
        switch (dir) {
            case UP:
                dir = RIGHT;
                break;
            case DOWN:
                dir = LEFT;
                break;
            case RIGHT:
                dir = DOWN;
                break;
            case LEFT:
                dir = UP;
                break;
        }
        PBenabled = false;
    }
}


/* Callback functions */
#define POLLING_LOOP 3
void pollingUpdate(void)
{
    static uint8_t idx = POLLING_LOOP;
    idx--;
    if(idx==0) {
        display.polling();
        idx = POLLING_LOOP;
        led_blue = !led_blue;
    }

}

void tickerCallback(void)
{
    updateDisplay = true;

    /* Enable push buttons if the display is refreshed */
    PBenabled = refreshed;

    led_red = !led_red;
}

void refreshCallback(void)
{
    refreshed = true;
}

/**************************** Fill the boarder ********************************/

void fillEdge(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color)
{
    #if(MULTI_UPDATE)   
    display.window(x,y,w,h);
    #endif

    display.fill  (x,y,w,h, color);

    #if(MULTI_UPDATE)   
    display.update();
    #endif
}

void fillBoarder(){
	
    // fill score header
    fillEdge(0, 0, DISPLAY_WIDTH, TOPEDGE*STEPSIZE, FOREGROUND_COLOR);

	// Fill right edge
    fillEdge(DISPLAY_WIDTH - (BOARDERWIDTH/2), TOPEDGE*STEPSIZE + BOARDERWIDTH/2, 1, BOARD_HEIGHT*STEPSIZE, FOREGROUND_COLOR);

	for (uint8_t i=0;i<=BOARD_HEIGHT;i++){
		for (uint8_t j=0;j<(DISPLAY_WIDTH-BOARD_WIDTH*STEPSIZE - BOARDERWIDTH/2);j++){
			 display.pixel(BOARD_WIDTH*STEPSIZE + BOARDERWIDTH/2 +j, (i+TOPEDGE)*STEPSIZE + BOARDERWIDTH/2+j, Black);
		}
	}

	// Fill bottom edge
    fillEdge(BOARDERWIDTH/2, (BOARD_HEIGHT+TOPEDGE)*STEPSIZE + BOARDERWIDTH/2, BOARD_WIDTH*STEPSIZE, 1, FOREGROUND_COLOR);
    
	for (uint8_t i=0;i<=BOARD_WIDTH;i++){
		for (uint8_t j=0;j<(DISPLAY_WIDTH-BOARD_WIDTH*STEPSIZE - BOARDERWIDTH/2);j++){
			display.pixel(i*STEPSIZE + BOARDERWIDTH/2 +j, (BOARD_HEIGHT+TOPEDGE)*STEPSIZE + BOARDERWIDTH/2+j, Black);
		}
	}

	// Fill left edge
  	fillEdge(BOARDERWIDTH/2, TOPEDGE*STEPSIZE + BOARDERWIDTH/2, 1, BOARD_HEIGHT*STEPSIZE, Black);
    
	for (uint8_t i=0;i<=BOARD_HEIGHT;i++){
		for (uint8_t j=0;j<(DISPLAY_WIDTH-BOARD_WIDTH*STEPSIZE - BOARDERWIDTH/2 - 1);j++){
			// display.pixel(j, (i+TOPEDGE)*STEPSIZE + BOARDERWIDTH/2+j, Black);
            display.pixel(j, (i+TOPEDGE)*STEPSIZE + j, Black);
		}
	}

	// Fill top edge
    fillEdge(BOARDERWIDTH/2, TOPEDGE*STEPSIZE + BOARDERWIDTH/2 - 1, BOARD_WIDTH*STEPSIZE, 1, Black);

	for (uint8_t i=0;i<=BOARD_WIDTH;i++){
		for (uint8_t j=0;j<(DISPLAY_WIDTH-BOARD_WIDTH*STEPSIZE - BOARDERWIDTH/2 - 1);j++){
			// display.pixel(i*STEPSIZE + BOARDERWIDTH/2 + j, TOPEDGE*STEPSIZE + j, Black);
            display.pixel(i*STEPSIZE + j, TOPEDGE*STEPSIZE + j, Black);
		}
	}

}


void display_clear_all(void)
{
    display.foreground(FOREGROUND_COLOR);
    display.background(BACKGROUND_COLOR);

#if(MULTI_UPDATE)
    int j;
    int Divide = 8;                // separate for 8 windows to save memory
    int Block = LCD_DISP_HEIGHT / Divide; 

    for(j = 0 ; j <Divide ; j++) {
            display.window(0, j*Block, LCD_DISP_WIDTH, Block);
            display.cls();
            display.update();
        }
#else
            display.window(0, 0, LCD_DISP_WIDTH, LCD_DISP_HEIGHT);
            display.cls();
            display.update();
#endif

}

void display_score(void)
{
    int j = 0;
    int Block = 27; // Text Font height; 

    display.foreground(White);
    display.background(Black);

#if(MULTI_UPDATE)   
    display.window(0, j*Block, LCD_DISP_WIDTH, Block);
#else
    display.window(0, 0, LCD_DISP_WIDTH, LCD_DISP_HEIGHT);
#endif

    display.fill(0,0,LCD_DISP_WIDTH, Block, Black);

    display.locate(4, j*Block);
    display.printf("Score: %02d", score);     
#if(MULTI_UPDATE)
    display.update();
#else
    // reduce buffer window size to game area for faster refresh rate
    display.window(BOARDERWIDTH/2, TOPEDGE*STEPSIZE + BOARDERWIDTH/2, BOARD_WIDTH * STEPSIZE, BOARD_HEIGHT * STEPSIZE);
#endif
    display.foreground(FOREGROUND_COLOR);
    display.background(BACKGROUND_COLOR);
}

#define GAME_OVER_X 40
void display_game_over(void)
{
    int j = 3;
    int Block = 27; // Text Font height: 6 lines of text
   
    display.window(0, j*Block, LCD_DISP_WIDTH, Block);
    display.locate(GAME_OVER_X, j*Block);
    display.printf("GAME");  
    display.update();
  
    j++;
    display.window(0, j*Block, LCD_DISP_WIDTH, Block);
    display.locate(GAME_OVER_X, j*Block);
    display.printf("OVER!");  
    display.update();        
}

/**************************** MAIN ********************************************/
int main()
{
    /* Initialize pushbutton handlers */
    in.fall(in_handler_B0);
    inB1.fall(in_handler_B1);

    /* Enable the LCD */
    display.command_AllClear();
    display.set_font( (unsigned char*)Prototype24x27 );

#if TICKER_EN
    /* Start generating the 3Hz call */
    ticker.attach(&tickerCallback, 0.3333f);
#endif

    /* Reset the LCD to a blank state. (All white) */
    display_clear_all();
    fillBoarder();
    display_score();

    Gecko gck;
    Food fd;
    gck.draw(display);
    fd.draw(display);

    /* Push update to the display */
    display.update();
    
    /* Main loop */
    while (1) {
        #if(TICKER_EN)
        sleep();
        #else
        wait(0.2);
        #endif

        // update button status              
        refreshCallback(); 
        #if(!TICKER_EN)
        tickerCallback();
        #endif

        if (updateDisplay && refreshed && (mode==PLAY)) {
            updateDisplay = false;
            refreshed = false;
            pollingUpdate();    

            gck.move(display, dir);

            if (fd.isEaten(gck)) {
                fd.reset(display, gck);
                gck.increaseLength(display, dir);

                /* Redraw gecko */
                gck.draw(display);

                /* Update the score */
                score++;
                display_score();
            }

            if (gck.selfCollision()) {
                mode = STOP;
                gck.move(display, dir);
                display_game_over();
            }

            /* Update display */
            refreshed = false;
            display.update();
        }
    }
}