Subversion Repositories Code-Repo

Rev

Rev 278 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
240 Kevin 1
#include "defines.h"
2
#include "CONTROLLERS.h"
3
#include "SNAKE.h"
276 Kevin 4
#include "TIMER4.h"
240 Kevin 5
 
278 Kevin 6
static SNAKE_DATA *snake_data_p;
242 Kevin 7
static uint32_t rand_value __attribute__((persistent));
240 Kevin 8
 
9
void Snake_Init(SNAKE_DATA *data) {
278 Kevin 10
    snake_data_p = data;
240 Kevin 11
 
12
    // Set starting point
278 Kevin 13
    snake_data_p->body[0] = (SNAKE_POINT){0,0,7};
240 Kevin 14
 
278 Kevin 15
    snake_data_p->pos_head = 0;
16
    snake_data_p->pos_tail = 0;
17
    snake_data_p->length = 1;
18
    snake_data_p->level = 0;
19
    snake_data_p->delay = SNAKE_MAXIMUM_DELAY;
240 Kevin 20
 
278 Kevin 21
    // Initialize the starting direction
22
    snake_data_p->direction = (SNAKE_POINT){1,0,7};
23
    snake_data_p->last_direction = 0x08;
24
 
242 Kevin 25
    srand(rand_value);
26
 
240 Kevin 27
    // Generate a starting location for the candy
278 Kevin 28
    snake_data_p->candy_loc = Snake_Generate_Candy();
240 Kevin 29
 
30
    // Draw the snake (head)
31
    Cube_Clear();
278 Kevin 32
    uint32_t index = snake_data_p->pos_head;
33
    Cube_Set_Pixel(snake_data_p->body[index].z, snake_data_p->body[index].x, snake_data_p->body[index].y, SNAKE_HEAD_COLOR);
34
    while (index != snake_data_p->pos_tail) {
35
        if (snake_data_p->length > 1) {
240 Kevin 36
            index = (index == 0) ? CUBE_PIXELS - 1 : index - 1;
278 Kevin 37
            Cube_Set_Pixel(snake_data_p->body[index].z, snake_data_p->body[index].x, snake_data_p->body[index].y, SNAKE_BODY_COLOR);
240 Kevin 38
        }
39
    }
40
}
41
 
42
void Snake_Main(void) {
241 Kevin 43
    // Main function, loops and delays while updating the frame every x milliseconds
276 Kevin 44
 
278 Kevin 45
    // Ensure that a controller is connected before starting
276 Kevin 46
    while(!Controller_Get_Connected()) {
47
        Delay_MS(100);
48
        Controller_Poll_Connected();
49
    }
50
 
278 Kevin 51
    // Set the first controller as active and indicate it on its LEDs
276 Kevin 52
    Controller_Set_Active(0);
53
    Delay_MS(20);
54
    Controller_Set_Left_Leds(0, 0x1);
55
    TIMER4_Start();
56
    Delay_MS(1000);
240 Kevin 57
    while (1) {
242 Kevin 58
        // Regenerate the seed upon each update so that the candy starts somewhere new every time
59
        rand_value = rand();
276 Kevin 60
 
240 Kevin 61
        Snake_Update_Frame();
278 Kevin 62
        Delay_MS(snake_data_p->delay);
240 Kevin 63
    }
64
}
65
 
276 Kevin 66
void Snake_Update_Direction(uint8_t controller, CTRL_BTN_STATUS value) {
240 Kevin 67
    // Determine the next direction for the snake based off the last button press
276 Kevin 68
    if (controller == 0) {
278 Kevin 69
        snake_data_p->last_direction = value.w;
70
        SNAKE_POINT point = snake_data_p->body[snake_data_p->pos_head];
240 Kevin 71
 
276 Kevin 72
        if (value.BTN_L_N || value.BTN_L_E) {    // Up
73
            point.z = (point.z == CUBE_LAYER_COUNT - 1) ? 0 : point.z + 1;
74
        } else if (value.BTN_L_W || value.BTN_L_S) { // Down
75
            point.z = (point.z == 0) ? CUBE_LAYER_COUNT - 1 : point.z - 1;
76
        } else if (value.BTN_R_N) { // Forward
77
            point.x = (point.x == CUBE_ROW_COUNT - 1) ? 0 : point.x + 1;
78
        } else if (value.BTN_R_W) { // Right
79
            point.y = (point.y == CUBE_COLUMN_COUNT - 1) ? 0 : point.y + 1;
80
        } else if (value.BTN_R_S) { // Backward
81
            point.x = (point.x == 0) ? CUBE_ROW_COUNT - 1 : point.x - 1;
82
        } else if (value.BTN_R_E) { // Left
83
            point.y = (point.y== 0) ? CUBE_COLUMN_COUNT - 1 : point.y - 1;
84
        }
85
 
278 Kevin 86
        snake_data_p->direction = point;
240 Kevin 87
    }
88
 
89
    // Update the overlay with the candy location
90
    Cube_Overlay_Clear();
278 Kevin 91
    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);
240 Kevin 92
}
93
 
94
void Snake_Update_Frame(void) {
95
    uint8_t om_nom_nom = 0;
96
 
97
    // Check if we are moving onto a candy, if so extend body
278 Kevin 98
    if (snake_data_p->direction.x == snake_data_p->candy_loc.x &&
99
            snake_data_p->direction.y == snake_data_p->candy_loc.y &&
100
            snake_data_p->direction.z == snake_data_p->candy_loc.z) {
101
        snake_data_p->pos_head = (snake_data_p->pos_head == CUBE_PIXELS - 1) ? 0 : snake_data_p->pos_head + 1;
102
        snake_data_p->body[snake_data_p->pos_head] = snake_data_p->direction;
103
        snake_data_p->length++;
104
        snake_data_p->candy_loc = Snake_Generate_Candy();
240 Kevin 105
        om_nom_nom = 1;
106
    }
107
 
108
    // Check if the location that we are moving to is overlapping the body
278 Kevin 109
    uint32_t pos = snake_data_p->pos_tail;
110
    while (pos != snake_data_p->pos_head) {
111
        if (snake_data_p->direction.x == snake_data_p->body[pos].x &&
112
                snake_data_p->direction.y == snake_data_p->body[pos].y &&
113
                snake_data_p->direction.z == snake_data_p->body[pos].z) {
241 Kevin 114
            // Indicate the overlapping pixel, delay, then return to idle state
278 Kevin 115
            Cube_Set_Pixel(snake_data_p->direction.z, snake_data_p->direction.x, snake_data_p->direction.y, SNAKE_COLLISION_COLOR);
240 Kevin 116
            Delay_MS(3000);
242 Kevin 117
            Cube_Overlay_Clear();
118
            Animation_Cube_In_Out(200, ORANGE);
240 Kevin 119
            Reset_Board(BOARD_MODE_IDLE);
120
        }
121
        pos = (pos == CUBE_PIXELS - 1) ? 0 : pos + 1;
122
    }
123
 
124
    // If we didnt eat a candy, increment the frame to move the body along
125
    if (!om_nom_nom) {
278 Kevin 126
        snake_data_p->pos_head = (snake_data_p->pos_head == CUBE_PIXELS - 1) ? 0 : snake_data_p->pos_head + 1;
127
        snake_data_p->pos_tail = (snake_data_p->pos_tail == CUBE_PIXELS - 1) ? 0 : snake_data_p->pos_tail + 1;
128
        snake_data_p->body[snake_data_p->pos_head] = snake_data_p->direction;
240 Kevin 129
    }
130
 
131
    // Draw updated snake location
132
    Cube_Clear();
278 Kevin 133
    uint32_t index = snake_data_p->pos_head;
134
    Cube_Set_Pixel(snake_data_p->body[index].z, snake_data_p->body[index].x, snake_data_p->body[index].y, SNAKE_HEAD_COLOR);
135
    while (index != snake_data_p->pos_tail) {
136
        if (snake_data_p->length > 1) {
240 Kevin 137
            index = (index == 0) ? CUBE_PIXELS - 1 : index - 1;
278 Kevin 138
            Cube_Set_Pixel(snake_data_p->body[index].z, snake_data_p->body[index].x, snake_data_p->body[index].y, SNAKE_BODY_COLOR);
240 Kevin 139
        }
140
    }
141
 
278 Kevin 142
    // Determine the next point to move to
143
    Snake_Update_Direction(0, (CTRL_BTN_STATUS)snake_data_p->last_direction);
240 Kevin 144
 
145
    // If we ate a candy, delay for a bit to rest
146
    if (om_nom_nom) {
276 Kevin 147
        // Increase the level by one
278 Kevin 148
        snake_data_p->level += 1;
276 Kevin 149
 
150
        TIMER4_Stop();
278 Kevin 151
        Controller_Set_Middle_Leds(0, snake_data_p->level);
152
        if (snake_data_p->level >= 256)
276 Kevin 153
            Controller_Set_Left_Leds(0, 0x9);
154
        TIMER4_Start();
155
 
241 Kevin 156
        // Decrease the delay between frame updates by 5ms
278 Kevin 157
        if (snake_data_p->delay > SNAKE_MINIMUM_DELAY)
158
            snake_data_p->delay -= 5;
241 Kevin 159
        // Clear the watchdog timer to prevent resets in a middle of a game
160
        ClearWDT();
240 Kevin 161
    }
162
}
163
 
164
SNAKE_POINT Snake_Generate_Candy(void) {
165
    // Generates a random position within the cube that doesnt overlap anything
166
    SNAKE_POINT ret;
167
    uint32_t x, y, z, brk = 0;
168
    while(1) {
169
        x = rand() % 8;
170
        y = rand() % 8;
171
        z = rand() % 8;
172
 
278 Kevin 173
        if (snake_data_p->length != 1) {
174
            uint32_t pos = snake_data_p->pos_tail;
240 Kevin 175
            uint32_t overlap = 0;
176
            // Iterate through the frame till we finish or find an overlap
278 Kevin 177
            while (pos != snake_data_p->pos_head) {
178
                if (snake_data_p->body[pos].x == x &&
179
                        snake_data_p->body[pos].y == y &&
180
                        snake_data_p->body[pos].z == z) {
240 Kevin 181
                    overlap = 1;
182
                    break;
183
                } else {
184
                    pos = (pos == CUBE_PIXELS - 1) ? 0 : pos + 1;
185
                }
186
            }
187
            if (!overlap)
188
                brk = 1;
189
        } else {
278 Kevin 190
            uint32_t pos = snake_data_p->pos_tail;
191
            if (snake_data_p->body[pos].x != x &&
192
                    snake_data_p->body[pos].y != y &&
193
                    snake_data_p->body[pos].z != z) {
240 Kevin 194
                brk = 1;
195
            }
196
        }
197
 
198
        if (brk)
199
            break;
200
    }
201
 
202
    ret.x = x;
203
    ret.y = y;
204
    ret.z = z;
205
    return ret;
206
}