From 8f877d46772aae1c0ec9cf971d9436b7683ee2c7 Mon Sep 17 00:00:00 2001 From: hkz Date: Tue, 22 Jul 2025 11:53:14 +0200 Subject: [PATCH] Add border animation when moving --- graphics/arrow_left.aseprite | Bin 0 -> 348 bytes graphics/arrow_left.png | Bin 0 -> 165 bytes graphics/arrow_up.aseprite | Bin 0 -> 344 bytes graphics/arrow_up.png | Bin 0 -> 168 bytes graphics/conversion.txt | 34 +++++++++++++++++++++++++++ src/game_graphics.c | 43 ++++++++++++++++++++++++----------- src/game_graphics.h | 11 +++++++++ src/main.c | 17 ++++++++++---- src/utility.c | 9 ++++++++ src/utility.h | 1 + 10 files changed, 98 insertions(+), 17 deletions(-) create mode 100644 graphics/arrow_left.aseprite create mode 100644 graphics/arrow_left.png create mode 100644 graphics/arrow_up.aseprite create mode 100644 graphics/arrow_up.png create mode 100644 graphics/conversion.txt diff --git a/graphics/arrow_left.aseprite b/graphics/arrow_left.aseprite new file mode 100644 index 0000000000000000000000000000000000000000..a039b866bef38102e86c5ca60cfad7ffddbaf667 GIT binary patch literal 348 zcma!HWMFu(l#xLO2o)HB9EKDiMgV38Mvx$b01(mw+yNT;>mv);Ru&*z42ankz*Ztz zrvqe5DlkJun2=4l=A60^Zi@_-|IXk^5zceo;11QI;08#KCZWt&8 zD(1YsV$H>%z{7HJ@BgJ!MVdUk=C;mgT^aw-{Zc^qu87d?Pv0h9%hs39yepMCS8Z#& i&96T)-!FgsC-dJsP3T@;&^;s1^QmRACX7w4C6@q}%{iO^ literal 0 HcmV?d00001 diff --git a/graphics/arrow_left.png b/graphics/arrow_left.png new file mode 100644 index 0000000000000000000000000000000000000000..183d94dbee4c5d691ef666a4c56ddd7fb58e7c6d GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^G9b*s1SJ3FdmIK*jKx9jP7LeL$-D$|;yqm)Lp(a) zPBG+TP~c!*`~SZ&A0OM{CGCkHmv);Ru&*z42ankz*Ztz zrvqe5DlkJun2=4l=A60^Zi@_-|IXk^5zceoe{kh=Tuc!$2WW zG3V`NLoNmb4(0=Y{$GB3>!{PJWqh0|!u;%vIy~AZoSV(^u=x=F-^OaN|j9n zlD~HZ85Y!ri1@E-j_X{P9mtU8baP+k(m7Waym02y-EzU{zgzIXIxn?J&(*cm52n`u PZDa6s^>bP0l+XkKhYLCb literal 0 HcmV?d00001 diff --git a/graphics/conversion.txt b/graphics/conversion.txt new file mode 100644 index 0000000..89ebbf2 --- /dev/null +++ b/graphics/conversion.txt @@ -0,0 +1,34 @@ +void convert_pic(uint16_t w, uint16_t h, const uint8_t *data, uint8_t *dest) { + uint8_t remainder = 0; + uint8_t remainder_size = 0; + uint8_t pic_width_bytes = w / 8 + ((w % 8) ? 1 : 0); + uint16_t spurious_bits = (pic_width_bytes * 8) - w; + uint16_t counter = 0; + + + for(uint16_t row = 0; row < h; row++) { + remainder = 0; + remainder_size = 0; + + // MSB is the color indicator + for(uint8_t column = 0; column < pic_width_bytes; column++) { + uint8_t pix_data = data[(pic_width_bytes * row) + column]; + uint8_t conv_data = (pix_data << remainder_size) | remainder; + remainder_size++; + remainder = (pix_data >> (8 - remainder_size)) & 0x7F; + dest[counter++] = conv_data & 0x7F; + + if(remainder_size == 7) { + dest[counter++] = remainder & 0x7F; + remainder = 0; + remainder_size = 0; + } + } + + if(remainder_size > spurious_bits) { + uint8_t mask = ~((1 << remainder_size) - 1); + dest[counter] = (dest[counter] & mask) | (remainder & 0x7F); + counter++; + } + } +} \ No newline at end of file diff --git a/src/game_graphics.c b/src/game_graphics.c index 13f028b..9e3b832 100644 --- a/src/game_graphics.c +++ b/src/game_graphics.c @@ -23,24 +23,20 @@ static uint8_t *back_buf = (uint8_t*)DISPLAY_PAGE_2; // It is offset on the left side by 7 pixels and on the top by 14 // Every square is 35x35 pixels +void draw_field_borders_on_buffer(uint8_t brd, uint8_t* buf); void swap_display_buffers(void); +void ddraw_field_borders_on_buffer(uint8_t brd) { + draw_field_borders_on_buffer(brd, front_buf); +} + void draw_game_background(void) { // Draw the background on display page 1 uint8_t* buf = (uint8_t*)DISPLAY_PAGE_1; - - // Horizontal borders - for(uint8_t col = 0; col < (GRID_SIDE * (GRID_CELL_SIDE/7)) + 1; col++) { - buf[line_offset_map[TOP_OFFSET - 1] + col + LEFT_OFFSET_B] = 0x7F; - buf[line_offset_map[TOP_OFFSET + (GRID_CELL_SIDE * GRID_SIDE) + 7] + col + LEFT_OFFSET_B] = 0x7F; - } - // Vertical borders - for(uint8_t row = 0; row < (GRID_CELL_SIDE * GRID_SIDE) + 7; row++) { - buf[line_offset_map[row + TOP_OFFSET] + LEFT_OFFSET_B - 1] = 0x40; - buf[line_offset_map[row + TOP_OFFSET] + LEFT_OFFSET_B + (GRID_SIDE * (GRID_CELL_SIDE/7)) + 1] = 0x01; - } - + // Draw the borders + draw_field_borders_on_buffer(0x0F, buf); + // Copy the data from display page 1 to 2 memcpy((void*)DISPLAY_PAGE_2, (void*)DISPLAY_PAGE_1, DISPLAY_PAGE_SIZE); @@ -69,7 +65,7 @@ void draw_tiles(void) { uint8_t* grid = get_front_grid(); // Clear the grid so we'll be able to draw the boxes on - clear_box(GRID_SIDE * (GRID_CELL_SIDE/7) + 1, (GRID_SIDE * GRID_CELL_SIDE) + 6, LEFT_OFFSET_B, TOP_OFFSET + 1, back_buf); + clear_box(GRID_SIDE * (GRID_CELL_SIDE/7) + 1, (GRID_SIDE * GRID_CELL_SIDE) + 4, LEFT_OFFSET_B, TOP_OFFSET + 1, back_buf); for (uint8_t tile = 0; tile < GRID_SIDE * GRID_SIDE; tile++) { if(grid[tile]) { @@ -84,6 +80,10 @@ void draw_tiles(void) { } } + // Re-draw the borders, to restore the correct width + draw_field_borders_on_buffer(0x0F, back_buf); + + // And finally swap the buffer to show the update swap_display_buffers(); } @@ -95,3 +95,20 @@ void swap_display_buffers(void) { // Show the current buffer PEEK(((uint16_t)front_buf == DISPLAY_PAGE_1) ? IO_DISPLAY_PAGE1 : IO_DISPLAY_PAGE2); } + +void draw_field_borders_on_buffer(uint8_t brd, uint8_t* buf) { + // Horizontal borders + for(uint8_t col = 0; col < (GRID_SIDE * (GRID_CELL_SIDE/7)) + 1; col++) { + buf[line_offset_map[TOP_OFFSET - 1] + col + LEFT_OFFSET_B] = BRD_SKIP_UP(brd) ? 0x00: 0x7F; + buf[line_offset_map[TOP_OFFSET - 0] + col + LEFT_OFFSET_B] = BRD_DOUBLING_UP(brd) && !BRD_SKIP_UP(brd) ? 0x7F : 0x00; + + buf[line_offset_map[TOP_OFFSET + (GRID_CELL_SIDE * GRID_SIDE) + 7] + col + LEFT_OFFSET_B] = BRD_SKIP_DOWN(brd) ? 0x00: 0x7F; + buf[line_offset_map[TOP_OFFSET + (GRID_CELL_SIDE * GRID_SIDE) + 6] + col + LEFT_OFFSET_B] = BRD_DOUBLING_DOWN(brd) && !BRD_SKIP_DOWN(brd) ? 0x7F : 0x00; + } + + // Vertical borders + for(uint8_t row = 0; row < (GRID_CELL_SIDE * GRID_SIDE) + 7; row++) { + buf[line_offset_map[row + TOP_OFFSET] + LEFT_OFFSET_B - 1] = BRD_SKIP_LEFT(brd) ? 0x00 : (BRD_DOUBLING_LEFT(brd) ? 0x60 : 0x40); + buf[line_offset_map[row + TOP_OFFSET] + LEFT_OFFSET_B + (GRID_SIDE * (GRID_CELL_SIDE/7)) + 1] = BRD_SKIP_RIGHT(brd) ? 0x00 : (BRD_DOUBLING_RIGHT(brd) ? 0x03 : 0x01); + } +} diff --git a/src/game_graphics.h b/src/game_graphics.h index fbcafed..99d2dd5 100644 --- a/src/game_graphics.h +++ b/src/game_graphics.h @@ -3,6 +3,17 @@ #include +#define BRD_DOUBLING_UP(a) (a & 0x01) +#define BRD_DOUBLING_DOWN(a) (a & 0x02) +#define BRD_DOUBLING_LEFT(a) (a & 0x04) +#define BRD_DOUBLING_RIGHT(a) (a & 0x08) + +#define BRD_SKIP_UP(a) (a & 0x10) +#define BRD_SKIP_DOWN(a) (a & 0x20) +#define BRD_SKIP_LEFT(a) (a & 0x40) +#define BRD_SKIP_RIGHT(a) (a & 0x80) + +void ddraw_field_borders_on_buffer(uint8_t brd); void draw_game_background(void); void draw_tiles(void); void ddraw_single_tile(uint8_t offset); diff --git a/src/main.c b/src/main.c index bcaecab..031617e 100644 --- a/src/main.c +++ b/src/main.c @@ -27,6 +27,8 @@ void init(void) { } __task int main(void) { + uint16_t moves_count = 0; + init(); game_state state; @@ -43,35 +45,42 @@ __task int main(void) { switch(read_kb()) { case K_UP: BELL1(); + ddraw_field_borders_on_buffer(0x1F); state = step_game(UP); break; case K_DOWN: BELL1(); + ddraw_field_borders_on_buffer(0x2F); state = step_game(DOWN); break; case K_LEFT: BELL1(); + ddraw_field_borders_on_buffer(0x4F); state = step_game(LEFT); break; case K_RIGHT: BELL1(); + ddraw_field_borders_on_buffer(0x8F); state = step_game(RIGHT); break; default: continue; // Do nothing, loop again } + + // Increase the count of moves we made + moves_count++; - // If we have finished, break out of this loop + // If we have won, break out of this loop if(state.done) break; - // Draw the moved sprites + // Draw the moved tiles draw_tiles(); - // Unable to add a tile. We lost!!! + // Unable to add a tile: we ran out of space and lost!!! uint8_t random_tile_off = add_random_tile(); if(!random_tile_off) break; - // Draw the new tile directly on the front buffer + // Draw the new tile directly on the front buffer, this way we make it appear with an "animation" ddraw_single_tile(random_tile_off - 1); } diff --git a/src/utility.c b/src/utility.c index 11d2308..3f1afee 100644 --- a/src/utility.c +++ b/src/utility.c @@ -4,6 +4,15 @@ #include "monitor_subroutines.h" #include "line_data.h" +// https://stackoverflow.com/questions/2602823/in-c-c-whats-the-simplest-way-to-reverse-the-order-of-bits-in-a-byte +uint8_t bit_reverse(uint8_t b) { + b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; + b = (b & 0xAA) >> 1 | (b & 0x55) << 1; + + return b; +} + // https://stackoverflow.com/questions/14009765/fastest-way-to-count-bits uint8_t bit_count(uint8_t b) { b = (b & 0x55) + (b >> 1 & 0x55); diff --git a/src/utility.h b/src/utility.h index 5b97469..74d2d77 100644 --- a/src/utility.h +++ b/src/utility.h @@ -18,6 +18,7 @@ #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) +uint8_t bit_reverse(uint8_t b); uint8_t bit_count(uint8_t b); uint16_t lfsr_update(void); void clear_box(uint8_t w, uint8_t h, uint8_t off_x, uint8_t off_y, uint8_t *disp_buf);