Rev 278 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
#include "defines.h"#include "CONTROLLERS.h"#include "SNAKE.h"#include "TIMER4.h"static SNAKE_DATA *snake_data_p;static uint32_t rand_value __attribute__((persistent));void Snake_Init(SNAKE_DATA *data) {snake_data_p = data;// Set starting pointsnake_data_p->body[0] = (SNAKE_POINT){0,0,7};snake_data_p->pos_head = 0;snake_data_p->pos_tail = 0;snake_data_p->length = 1;snake_data_p->level = 0;snake_data_p->delay = SNAKE_MAXIMUM_DELAY;// Initialize the starting directionsnake_data_p->direction = (SNAKE_POINT){1,0,7};snake_data_p->last_direction = 0x08;srand(rand_value);// Generate a starting location for the candysnake_data_p->candy_loc = Snake_Generate_Candy();// Draw the snake (head)Cube_Clear();uint32_t index = snake_data_p->pos_head;Cube_Set_Pixel(snake_data_p->body[index].z, snake_data_p->body[index].x, snake_data_p->body[index].y, SNAKE_HEAD_COLOR);while (index != snake_data_p->pos_tail) {if (snake_data_p->length > 1) {index = (index == 0) ? CUBE_PIXELS - 1 : index - 1;Cube_Set_Pixel(snake_data_p->body[index].z, snake_data_p->body[index].x, snake_data_p->body[index].y, SNAKE_BODY_COLOR);}}}void Snake_Main(void) {// Main function, loops and delays while updating the frame every x milliseconds// Ensure that a controller is connected before startingwhile(!Controller_Get_Connected()) {Delay_MS(100);Controller_Poll_Connected();}// Set the first controller as active and indicate it on its LEDsController_Set_Active(0);Delay_MS(20);Controller_Set_Left_Leds(0, 0x1);TIMER4_Start();Delay_MS(1000);while (1) {// Regenerate the seed upon each update so that the candy starts somewhere new every timerand_value = rand();Snake_Update_Frame();Delay_MS(snake_data_p->delay);}}void Snake_Update_Direction(uint8_t controller, CTRL_BTN_STATUS value) {// Determine the next direction for the snake based off the last button pressif (controller == 0) {snake_data_p->last_direction = value.w;SNAKE_POINT point = snake_data_p->body[snake_data_p->pos_head];if (value.BTN_L_N || value.BTN_L_E) { // Uppoint.z = (point.z == CUBE_LAYER_COUNT - 1) ? 0 : point.z + 1;} else if (value.BTN_L_W || value.BTN_L_S) { // Downpoint.z = (point.z == 0) ? CUBE_LAYER_COUNT - 1 : point.z - 1;} else if (value.BTN_R_N) { // Forwardpoint.x = (point.x == CUBE_ROW_COUNT - 1) ? 0 : point.x + 1;} else if (value.BTN_R_W) { // Rightpoint.y = (point.y == CUBE_COLUMN_COUNT - 1) ? 0 : point.y + 1;} else if (value.BTN_R_S) { // Backwardpoint.x = (point.x == 0) ? CUBE_ROW_COUNT - 1 : point.x - 1;} else if (value.BTN_R_E) { // Leftpoint.y = (point.y== 0) ? CUBE_COLUMN_COUNT - 1 : point.y - 1;}snake_data_p->direction = point;}// Update the overlay with the candy locationCube_Overlay_Clear();Cube_Overlay_Set_Pixel(snake_data_p->candy_loc.z, snake_data_p->candy_loc.x, snake_data_p->candy_loc.y, SNAKE_CANDY_COLOR);}void Snake_Update_Frame(void) {uint8_t om_nom_nom = 0;// Check if we are moving onto a candy, if so extend bodyif (snake_data_p->direction.x == snake_data_p->candy_loc.x &&snake_data_p->direction.y == snake_data_p->candy_loc.y &&snake_data_p->direction.z == snake_data_p->candy_loc.z) {snake_data_p->pos_head = (snake_data_p->pos_head == CUBE_PIXELS - 1) ? 0 : snake_data_p->pos_head + 1;snake_data_p->body[snake_data_p->pos_head] = snake_data_p->direction;snake_data_p->length++;snake_data_p->candy_loc = Snake_Generate_Candy();om_nom_nom = 1;}// Check if the location that we are moving to is overlapping the bodyuint32_t pos = snake_data_p->pos_tail;while (pos != snake_data_p->pos_head) {if (snake_data_p->direction.x == snake_data_p->body[pos].x &&snake_data_p->direction.y == snake_data_p->body[pos].y &&snake_data_p->direction.z == snake_data_p->body[pos].z) {// Indicate the overlapping pixel, delay, then return to idle stateCube_Set_Pixel(snake_data_p->direction.z, snake_data_p->direction.x, snake_data_p->direction.y, SNAKE_COLLISION_COLOR);Delay_MS(3000);Cube_Overlay_Clear();Animation_Cube_In_Out(200, ORANGE);Reset_Board(BOARD_MODE_IDLE);}pos = (pos == CUBE_PIXELS - 1) ? 0 : pos + 1;}// If we didnt eat a candy, increment the frame to move the body alongif (!om_nom_nom) {snake_data_p->pos_head = (snake_data_p->pos_head == CUBE_PIXELS - 1) ? 0 : snake_data_p->pos_head + 1;snake_data_p->pos_tail = (snake_data_p->pos_tail == CUBE_PIXELS - 1) ? 0 : snake_data_p->pos_tail + 1;snake_data_p->body[snake_data_p->pos_head] = snake_data_p->direction;}// Draw updated snake locationCube_Clear();uint32_t index = snake_data_p->pos_head;Cube_Set_Pixel(snake_data_p->body[index].z, snake_data_p->body[index].x, snake_data_p->body[index].y, SNAKE_HEAD_COLOR);while (index != snake_data_p->pos_tail) {if (snake_data_p->length > 1) {index = (index == 0) ? CUBE_PIXELS - 1 : index - 1;Cube_Set_Pixel(snake_data_p->body[index].z, snake_data_p->body[index].x, snake_data_p->body[index].y, SNAKE_BODY_COLOR);}}// Determine the next point to move toSnake_Update_Direction(0, (CTRL_BTN_STATUS)snake_data_p->last_direction);// If we ate a candy, delay for a bit to restif (om_nom_nom) {// Increase the level by onesnake_data_p->level += 1;TIMER4_Stop();Controller_Set_Middle_Leds(0, snake_data_p->level);if (snake_data_p->level >= 256)Controller_Set_Left_Leds(0, 0x9);TIMER4_Start();// Decrease the delay between frame updates by 5msif (snake_data_p->delay > SNAKE_MINIMUM_DELAY)snake_data_p->delay -= 5;// Clear the watchdog timer to prevent resets in a middle of a gameClearWDT();}}SNAKE_POINT Snake_Generate_Candy(void) {// Generates a random position within the cube that doesnt overlap anythingSNAKE_POINT ret;uint32_t x, y, z, brk = 0;while(1) {x = rand() % 8;y = rand() % 8;z = rand() % 8;if (snake_data_p->length != 1) {uint32_t pos = snake_data_p->pos_tail;uint32_t overlap = 0;// Iterate through the frame till we finish or find an overlapwhile (pos != snake_data_p->pos_head) {if (snake_data_p->body[pos].x == x &&snake_data_p->body[pos].y == y &&snake_data_p->body[pos].z == z) {overlap = 1;break;} else {pos = (pos == CUBE_PIXELS - 1) ? 0 : pos + 1;}}if (!overlap)brk = 1;} else {uint32_t pos = snake_data_p->pos_tail;if (snake_data_p->body[pos].x != x &&snake_data_p->body[pos].y != y &&snake_data_p->body[pos].z != z) {brk = 1;}}if (brk)break;}ret.x = x;ret.y = y;ret.z = z;return ret;}