0,0 → 1,177 |
#include "defines.h" |
#include "CONTROLLERS.h" |
#include "SNAKE.h" |
|
static SNAKE_DATA *data_p; |
|
void Snake_Init(SNAKE_DATA *data) { |
data_p = data; |
|
// Disable watchdog timer |
WDTCON = 0x00000000; |
|
// Set starting point |
data_p->body[0].x = 0; |
data_p->body[0].y = 0; |
data_p->body[0].z = 0; |
|
data_p->pos_head = 0; |
data_p->pos_tail = 0; |
data_p->length = 1; |
data_p->level = 1; |
data_p->delay = 800; |
|
// Generate a starting location for the candy |
data_p->candy_loc = Snake_Generate_Candy(); |
|
// Draw the snake (head) |
Cube_Clear(); |
uint32_t index = data_p->pos_head; |
Cube_Set_Pixel(data_p->body[index].z, data_p->body[index].x, data_p->body[index].y, SNAKE_HEAD_COLOR); |
while (index != data_p->pos_tail) { |
if (data_p->length > 1) { |
index = (index == 0) ? CUBE_PIXELS - 1 : index - 1; |
Cube_Set_Pixel(data_p->body[index].z, data_p->body[index].x, data_p->body[index].y, SNAKE_BODY_COLOR); |
} |
} |
} |
|
void Snake_Main(void) { |
Delay_MS(2000); |
while (1) { |
Snake_Update_Frame(); |
Delay_MS(data_p->delay); |
} |
} |
|
void Snake_Update_Direction(uint8_t p1, uint8_t p2) { |
// Determine the next direction for the snake based off the last button press |
SNAKE_DIRECTION dir; |
dir.value = p1 | p2; |
data_p->last_direction = dir.value; |
|
SNAKE_POINT point = data_p->body[data_p->pos_head]; |
|
if (dir.up) { |
point.z = (point.z == CUBE_LAYER_COUNT - 1) ? 0 : point.z + 1; |
} else if (dir.down) { |
point.z = (point.z == 0) ? CUBE_LAYER_COUNT - 1 : point.z - 1; |
} else if (dir.forward) { |
point.x = (point.x == CUBE_ROW_COUNT - 1) ? 0 : point.x + 1; |
} else if (dir.right) { |
point.y = (point.y == CUBE_COLUMN_COUNT - 1) ? 0 : point.y + 1; |
} else if (dir.backward) { |
point.x = (point.x == 0) ? CUBE_ROW_COUNT - 1 : point.x - 1; |
} else if (dir.left) { |
point.y = (point.y== 0) ? CUBE_COLUMN_COUNT - 1 : point.y - 1; |
} |
|
data_p->direction = point; |
|
// Update the overlay with the candy location |
Cube_Overlay_Clear(); |
Cube_Overlay_Set_Pixel(data_p->candy_loc.z, data_p->candy_loc.x, 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 body |
if (data_p->direction.x == data_p->candy_loc.x && |
data_p->direction.y == data_p->candy_loc.y && |
data_p->direction.z == data_p->candy_loc.z) { |
data_p->pos_head = (data_p->pos_head == CUBE_PIXELS - 1) ? 0 : data_p->pos_head + 1; |
data_p->body[data_p->pos_head] = data_p->direction; |
data_p->length++; |
data_p->candy_loc = Snake_Generate_Candy(); |
om_nom_nom = 1; |
} |
|
// Check if the location that we are moving to is overlapping the body |
uint32_t pos = data_p->pos_tail; |
while (pos != data_p->pos_head) { |
if (data_p->direction.x == data_p->body[pos].x && |
data_p->direction.y == data_p->body[pos].y && |
data_p->direction.z == data_p->body[pos].z) { |
Cube_Overlay_Set_Pixel(data_p->direction.z, data_p->direction.x, data_p->direction.y, SNAKE_HEAD_COLOR); |
Delay_MS(3000); |
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 along |
if (!om_nom_nom) { |
data_p->pos_head = (data_p->pos_head == CUBE_PIXELS - 1) ? 0 : data_p->pos_head + 1; |
data_p->pos_tail = (data_p->pos_tail == CUBE_PIXELS - 1) ? 0 : data_p->pos_tail + 1; |
data_p->body[data_p->pos_head] = data_p->direction; |
} |
|
// Draw updated snake location |
Cube_Clear(); |
uint32_t index = data_p->pos_head; |
Cube_Set_Pixel(data_p->body[index].z, data_p->body[index].x, data_p->body[index].y, SNAKE_HEAD_COLOR); |
while (index != data_p->pos_tail) { |
if (data_p->length > 1) { |
index = (index == 0) ? CUBE_PIXELS - 1 : index - 1; |
Cube_Set_Pixel(data_p->body[index].z, data_p->body[index].x, data_p->body[index].y, SNAKE_BODY_COLOR); |
} |
} |
|
// Determine the next direction to take |
Snake_Update_Direction(data_p->last_direction, 0x0); |
|
// If we ate a candy, delay for a bit to rest |
if (om_nom_nom) { |
data_p->level += 1; // Increase the level by one |
if (data_p->level % SNAKE_LEVEL_STEP == 0) { |
uint8_t tier = data_p->level / SNAKE_LEVEL_STEP; |
Controller_Set_Leds(tier, tier); |
} |
data_p->delay -= 5; // Decrease the delay between frame updates by 5ms |
} |
} |
|
SNAKE_POINT Snake_Generate_Candy(void) { |
// Generates a random position within the cube that doesnt overlap anything |
SNAKE_POINT ret; |
uint32_t x, y, z, brk = 0; |
while(1) { |
x = rand() % 8; |
y = rand() % 8; |
z = rand() % 8; |
|
if (data_p->length != 1) { |
uint32_t pos = data_p->pos_tail; |
uint32_t overlap = 0; |
// Iterate through the frame till we finish or find an overlap |
while (pos != data_p->pos_head) { |
if (data_p->body[pos].x == x && |
data_p->body[pos].y == y && |
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 = data_p->pos_tail; |
if (data_p->body[pos].x != x && |
data_p->body[pos].y != y && |
data_p->body[pos].z != z) { |
brk = 1; |
} |
} |
|
if (brk) |
break; |
} |
|
ret.x = x; |
ret.y = y; |
ret.z = z; |
return ret; |
} |