diff --git a/include/dangerzone/render/anim.h b/include/dangerzone/render/anim.h index 4b5919a..ba544dd 100644 --- a/include/dangerzone/render/anim.h +++ b/include/dangerzone/render/anim.h @@ -1,13 +1,17 @@ #pragma once +#include #include /** * animate a rectangle's position changing over time * => x0 -> x1, y0 -> y1, all else stays the same + * + * ONLY DOES ONE FRAME OF THE ANIMATION */ void anim_rect_pos( + framebuffer_e framebuffer, uint32_t x0, uint32_t y0, uint32_t x1, diff --git a/src/engine/engine_init.c b/src/engine/engine_init.c index ab9dba6..adbb477 100644 --- a/src/engine/engine_init.c +++ b/src/engine/engine_init.c @@ -3,6 +3,8 @@ #include "internal/engine_internal.h" #include "internal/util/error.h" +#include + bool engine_sdl_init_state( engine_sdl_state_t **state, diff --git a/src/engine/render/anim.c b/src/engine/render/anim.c index 7a8409d..d554945 100644 --- a/src/engine/render/anim.c +++ b/src/engine/render/anim.c @@ -2,6 +2,7 @@ void anim_rect_pos( + framebuffer_e framebuffer, uint32_t x0, uint32_t y0, uint32_t x1, @@ -10,13 +11,28 @@ anim_rect_pos( uint32_t h, uint32_t color ) { - // TODO: I THINK I NEED LAYERED BUFFERS + // there's nowhere to move + if (x0 == x1 && y0 == y1) { + return; + } - // one step is one pixel - uint32_t stepsx = x1 - x0; - uint32_t stepsy = y1 - y0; + uint32_t dirx = (x1 - x0 > 0) ? 1 : -1; + uint32_t diry = (y1 - y0 > 0) ? 1 : -1; + + if (x0 == x1) { + dirx = 0; + } + + if (y0 == y1) { + diry = 0; + } /** - * 1. get the row / column in the direction of the movement + * 1. shift the rectangle by one pixel in the direction of movement + * 2. remove the trailing row / column left */ + + if (true) { + + } } diff --git a/src/examples/2048.c b/src/examples/2048.c index f864200..cd37b04 100644 --- a/src/examples/2048.c +++ b/src/examples/2048.c @@ -1,11 +1,12 @@ -#include "dangerzone/render/rect.h" #include #include +#include #include #include #include #include +#include #include #define SIZE 4 @@ -23,13 +24,33 @@ typedef struct { } v2_t; typedef struct { - uint32_t area[SIZE][SIZE]; + uint32_t value; + v2_t pos; +} tile_t; + +typedef struct { + tile_t area[SIZE][SIZE]; dir_e direction; uint32_t score; } game_t; static game_t game; +#define MOVE_DURATION 0.12f + +typedef struct { + uint32_t value; + int from_row, from_col; + int to_row, to_col; + bool merge_target; +} tile_anim_t; + +static tile_anim_t anims[SIZE * SIZE]; +static size_t anim_count; +static float anim_elapsed; +static bool anim_active; +uint32_t before[SIZE][SIZE]; + void print_area() { @@ -37,9 +58,9 @@ print_area() for (int i = 0; i < SIZE; i++) { printf("["); for (int j = 0; j < SIZE - 1; j++) { - printf("%d, ", game.area[i][j]); + printf("%d, ", game.area[i][j].value); } - printf("%d]\n", game.area[i][SIZE - 1]); + printf("%d]\n", game.area[i][SIZE - 1].value); } printf("\n"); } @@ -48,182 +69,149 @@ bool move() { bool retval = false; + tile_t *current, *next; + int k_start, k_end, k_step; switch (game.direction) { case LEFT: - for (int i = 0; i < SIZE; i++) { - for (int j = 0; j < SIZE; j++) { - for (int k = 0; k < SIZE - 1; k++) { - if (game.area[i][k] == 0 && game.area[i][k + 1] != 0) { - game.area[i][k] = game.area[i][k + 1]; - game.area[i][k + 1] = 0; - retval = true; - } - } - } - } + case UP: + k_start = 0; + k_end = SIZE - 1; + k_step = 1; break; case RIGHT: - for (int i = 0; i < SIZE; i++) { - uint32_t *row = game.area[i]; - for (int j = 0; j < SIZE; j++) { - for (int k = SIZE - 1; k > 0; k--) { - if (game.area[i][k] == 0 && game.area[i][k - 1] != 0) { - game.area[i][k] = game.area[i][k - 1]; - game.area[i][k - 1] = 0; - retval = true; - } - } - } - } - break; - case UP: - for (int i = 0; i < SIZE; i++) { - for (int j = 0; j < SIZE; j++) { - for (int k = 0; k < SIZE - 1; k++) { - if (game.area[k][i] == 0 && game.area[k + 1][i] != 0) { - game.area[k][i] = game.area[k + 1][i]; - game.area[k + 1][i] = 0; - retval = true; - } - } - } - } - break; case DOWN: - for (int i = 0; i < SIZE; i++) { - for (int j = 0; j < SIZE; j++) { - for (int k = SIZE - 1; k > 0; k--) { - if (game.area[k][i] == 0 && game.area[k - 1][i] != 0) { - game.area[k][i] = game.area[k - 1][i]; - game.area[k - 1][i] = 0; - retval = true; - } - } - } - } + k_start = SIZE - 1; + k_end = 0; + k_step = -1; break; default: break; } + for (int i = 0; i < SIZE; i++) { + for (int j = 0; j < SIZE; j++) { + for (int k = k_start; (k_start <= k_end) ? k < k_end : k > k_end; k += k_step) { + switch (game.direction) { + case LEFT: + case RIGHT: + current = &game.area[i][k]; + next = &game.area[i][k + k_step]; + break; + case UP: + case DOWN: + current = &game.area[k][i]; + next = &game.area[k + k_step][i]; + break; + } + + if (current->value == 0 && next->value != 0) { + current->pos = (v2_t) { + .x = next->pos.x, + .y = next->pos.y + }; + current->value = next->value; + next->value = 0; + retval = true; + } + } + } + } + return retval; } -bool -combine_horizontal( - bool has_moved + +static bool +merge_line( + uint32_t line[SIZE] ) { - bool retval = has_moved; - int8_t direction; - uint32_t start, end; - switch (game.direction) { - case LEFT: - // combine left - direction = -1; - start = 0; - end = SIZE - 1; - break; - case RIGHT: - // combine right - direction = 1; - start = SIZE - 1; - end = 0; - break; - default: - break; - } + uint32_t out[SIZE] = {0}; + int write = 0; + bool previous_was_merged = false; - for (int row_index = 0; row_index < SIZE; row_index++) { - uint32_t *row = game.area[row_index]; + for (int read = 0; read < SIZE; ++read) { + uint32_t value = line[read]; - for (int i = start; (game.direction == LEFT) ? i < end : i > end; i -= direction) { - if (row[i] == 0) { - continue; - } - if (row[i] == row[i - direction]) { - retval = true; - row[i] *= 2; - game.score += row[i]; - row[i - direction] = 0; - for (int j = i - direction; (game.direction == LEFT) ? j < end : j > end; j -= direction) { - row[j] = row[j - direction]; - } - row[end] = 0; - } + if (value == 0) + continue; + + if (write > 0 && + out[write - 1] == value && + !previous_was_merged) { + out[write - 1] *= 2; + game.score += out[write - 1]; + previous_was_merged = true; + } else { + out[write++] = value; + previous_was_merged = false; } } - return retval; -} - -bool -combine_vertical( - bool has_moved -) { - bool retval = has_moved; - int8_t direction; - uint32_t start, end; - switch (game.direction) { - case UP: - // combine up - direction = -1; - start = 0; - end = SIZE - 1; - break; - case DOWN: - // combine down - direction = 1; - start = SIZE - 1; - end = 0; - break; - default: - break; - } - - for (int col_index = 0; col_index < SIZE; col_index++) { - for (int i = start; (game.direction == UP) ? i < end : i > end; i -= direction) { - if (game.area[i][col_index] == 0) { - continue; - } - if (game.area[i][col_index] == game.area[i - direction][col_index]) { - retval = true; - game.area[i][col_index] *= 2; - game.score += game.area[i][col_index]; - game.area[i - direction][col_index] = 0; - for (int j = i - direction; (game.direction == UP) ? j < end : j > end; j -= direction) { - game.area[j][col_index] = game.area[j - direction][col_index]; - } - game.area[end][col_index] = 0; - } - } - } - - return retval; + bool changed = memcmp(line, out, sizeof out) != 0; + memcpy(line, out, sizeof out); + return changed; } bool combine( bool has_moved ) { - if (game.direction == LEFT || game.direction == RIGHT) { - return combine_horizontal(has_moved); - } else { - return combine_vertical(has_moved); + bool changed = false; + uint32_t line[SIZE]; + + for (int n = 0; n < SIZE; ++n) { + for (int p = 0; p < SIZE; ++p) { + int r, c; + + switch (game.direction) { + case LEFT: r = n; c = p; break; + case RIGHT: r = n; c = SIZE - 1 - p; break; + case UP: r = p; c = n; break; + case DOWN: r = SIZE - 1 - p; c = n; break; + default: return has_moved; + } + + line[p] = game.area[r][c].value; + } + + changed |= merge_line(line); + + for (int p = 0; p < SIZE; ++p) { + int r, c; + + switch (game.direction) { + case LEFT: r = n; c = p; break; + case RIGHT: r = n; c = SIZE - 1 - p; break; + case UP: r = p; c = n; break; + case DOWN: r = SIZE - 1 - p; c = n; break; + default: return has_moved; + } + + game.area[r][c].value = line[p]; + } } + + return has_moved || changed; } // finds a random empty position and puts a two there void new_2() { - uint32_t row = rand() % SIZE; - uint32_t col = rand() % SIZE; - while (game.area[row][col] != 0) { - row = rand() % SIZE; - col = rand() % SIZE; + // collect all zeroes + v2_t zeroes[SIZE * SIZE] = {0}; + uint32_t zero_count = 0; + for (int i = 0; i < SIZE; i++) { + for (int j = 0; j < SIZE; j++) { + if (game.area[i][j].value == 0) { + zeroes[zero_count++] = (v2_t){.x=j,.y=i}; + } + } } - game.area[row][col] = 2; + // choose among them + uint32_t rand_index = rand() % zero_count; + game.area[zeroes[rand_index].y][zeroes[rand_index].x].value = 2; } void @@ -235,16 +223,10 @@ slide() // 2. then combine them and shift the potential rest by one in the given direction bool has_combined = combine(has_moved); - // printf("moved? %s, combined? %s\n", (has_moved) ? "true" : "false", (has_combined) ? "true" : "false"); - // 3. generate a new 2 if (has_moved || has_combined) { new_2(); } - - // printf("score: %d\n", game.score); - - // print_area(); } // polling events every frame @@ -264,18 +246,30 @@ client_poll_event() break; case SDLK_W: game.direction = UP; + for (int r = 0; r < SIZE; ++r) + for (int c = 0; c < SIZE; ++c) + before[r][c] = game.area[r][c].value; slide(); break; case SDLK_S: game.direction = DOWN; + for (int r = 0; r < SIZE; ++r) + for (int c = 0; c < SIZE; ++c) + before[r][c] = game.area[r][c].value; slide(); break; case SDLK_A: game.direction = LEFT; + for (int r = 0; r < SIZE; ++r) + for (int c = 0; c < SIZE; ++c) + before[r][c] = game.area[r][c].value; slide(); break; case SDLK_D: game.direction = RIGHT; + for (int r = 0; r < SIZE; ++r) + for (int c = 0; c < SIZE; ++c) + before[r][c] = game.area[r][c].value; slide(); break; default: @@ -349,6 +343,8 @@ numrev( return new; } +v2_t last_area_positions[SIZE][SIZE] = {0}; + // performed every frame void client_update_framebuffer() @@ -373,7 +369,8 @@ client_update_framebuffer() uint32_t y = (border_width / 2) + j * tile_size; uint32_t w = tile_size - border_width; uint32_t h = tile_size - border_width; - uint32_t background_color = colors(game.area[j][i]); + uint32_t background_color = colors(game.area[j][i].value); + put_rect(BASE, x, y, w, h, 0xFFFFFF); put_rect(OVERDRAW, x, y, w, h, background_color); @@ -381,9 +378,9 @@ client_update_framebuffer() uint32_t foreground_color = 0x000000; uint8_t font_size = 3; - uint32_t n = game.area[j][i]; + uint32_t n = game.area[j][i].value; uint32_t n_len = numlen(n); - n_str = calloc(n_len, sizeof(char)); + n_str = calloc(n_len + 1, sizeof(char)); if (n_str == NULL) { game_state->is_running = false; } @@ -397,7 +394,7 @@ client_update_framebuffer() } // score display line (single line) - char *score_text = calloc(numlen(game.score), sizeof(char)); + char *score_text = calloc(7 + 6 + 1, sizeof(char)); if (score_text == NULL) { game_state->is_running = false; } @@ -431,8 +428,9 @@ v2_contains(v2_t v[], size_t size, v2_t elem) } void -game_init() -{ +game_init( + uint32_t window_width +) { srand(time(NULL)); // generate MAX_NUMBER_OF_4 + MAX_NUMBER_OF_2 random indices in range 0..15 (row in 0..3, col in 0..3) @@ -465,12 +463,22 @@ game_init() } } + for (int row = 0; row < SIZE; row++) { + for (int col = 0; col < SIZE; col++) { + game.area[row][col].pos = (v2_t){ + .x = col * (window_width / SIZE), + .y = row * (window_width / SIZE) + }; + game.area[row][col].value = 0; + } + } + for (i = 0; i < MAX_NUMBER_OF_4; i++) { - game.area[fours[i].y][fours[i].x] = 4; + game.area[fours[i].y][fours[i].x].value = 4; } for (i = 0; i < MAX_NUMBER_OF_2; i++) { - game.area[twos[i].y][twos[i].x] = 2; + game.area[twos[i].y][twos[i].x].value = 2; } game.direction = RIGHT; @@ -483,7 +491,7 @@ main() uint32_t window_width = 500; uint32_t window_height = window_width * 1.12f; - game_init(); + game_init(window_width); // initialize the engine if (engine_init(