From b8d11050f858aca12f1d5db049a3402cda9ac94f Mon Sep 17 00:00:00 2001 From: IllusionMan1212 Date: Fri, 29 Dec 2023 23:09:30 +0200 Subject: [PATCH] animate tile spawning --- game.c | 166 ++++++++++++++++++++++++++++++++++++--------------------- game.h | 3 ++ ui.c | 1 + 3 files changed, 108 insertions(+), 62 deletions(-) diff --git a/game.c b/game.c index fc19f48..f9978c2 100644 --- a/game.c +++ b/game.c @@ -8,7 +8,8 @@ #include "zephr.h" #define TILE_ANIM_SPEED 2.5f -#define GAMEOVER_ANIM_SPEED 150.f +#define TILE_SPAWN_SPEED 8.0f +#define GAMEOVER_ANIM_SPEED 175.f Game game = {0}; @@ -60,8 +61,8 @@ void print_new_board() { } } -Color get_color_from_tile(Tile tile) { - switch (tile.value) { +Color get_tile_color(u16 value) { + switch (value) { case 2: return ColorRGBA(238, 228, 218, 255); case 4: @@ -89,8 +90,8 @@ Color get_color_from_tile(Tile tile) { } } -u8 get_tile_font_size(Tile tile) { - switch (tile.value) { +u8 get_tile_font_size(u16 value) { + switch (value) { case 2: case 4: case 8: @@ -111,6 +112,7 @@ u8 get_tile_font_size(Tile tile) { } } + /////////////////////////////////// // // @@ -119,6 +121,53 @@ u8 get_tile_font_size(Tile tile) { // /////////////////////////////////// +u16 get_spawned_tile_value(void) { + // 90% chance of spawning a 2, 10% chance of spawning a 4 + if (rand() % 10 < 9) { + return 2; + } else { + return 4; + } +} + +void spawn_new_tile_with_value(u8 x, u8 y, u16 value) { + game.board[x][y].value = value; + game.board[x][y].new_value = value; +} + +void spawn_new_tile(u8 x, u8 y) { + const u16 val = get_spawned_tile_value(); + + game.board[x][y].value = val; + game.board[x][y].new_value = val; +} + +Vec2 get_random_available_tile_coords(void) { + u8 available_tiles_count = 0; + u8 available_tiles[16]; + + for (int i = 0; i < 4; i++) { + for (int j = 0; j <= 3; j++) { + if (game.board[i][j].new_value == 0 && !game.board[i][j].merged) { + available_tiles[available_tiles_count] = i * 4 + j; + available_tiles_count++; + } + } + } + + u8 rand_idx = rand() % available_tiles_count; + + u8 x = available_tiles[rand_idx] / 4; + u8 y = available_tiles[rand_idx] % 4; + + return (Vec2){x, y}; +} + +void spawn_random_tile(void) { + Vec2 coords = get_random_available_tile_coords(); + spawn_new_tile(coords.x, coords.y); +} + void move_right(void) { game.last_move_dir = MOVE_DIR_RIGHT; @@ -164,6 +213,8 @@ void move_right(void) { } src->new_value = 0; game.animating = true; + game.spawning_tile_coords = get_random_available_tile_coords(); + game.spawning_tile_value = get_spawned_tile_value(); } } } @@ -214,10 +265,11 @@ void move_left(void) { } src->new_value = 0; game.animating = true; + game.spawning_tile_coords = get_random_available_tile_coords(); + game.spawning_tile_value = get_spawned_tile_value(); } } } - } void move_down(void) { @@ -262,6 +314,8 @@ void move_down(void) { } src->new_value = 0; game.animating = true; + game.spawning_tile_coords = get_random_available_tile_coords(); + game.spawning_tile_value = get_spawned_tile_value(); } } } @@ -309,43 +363,13 @@ void move_up(void) { } src->new_value = 0; game.animating = true; + game.spawning_tile_coords = get_random_available_tile_coords(); + game.spawning_tile_value = get_spawned_tile_value(); } } } } -void spawn_new_tile(u8 x, u8 y) { - // 90% chance of spawning a 2, 10% chance of spawning a 4 - if (rand() % 10 < 9) { - game.board[x][y].value = 2; - game.board[x][y].new_value = 2; - } else { - game.board[x][y].value = 4; - game.board[x][y].new_value = 4; - } -} - -void spawn_random_tile(void) { - u8 available_tiles_count = 0; - u8 available_tiles[16]; - - for (int i = 0; i < 4; i++) { - for (int j = 0; j <= 3; j++) { - if (game.board[i][j].new_value == 0 && !game.board[i][j].merged) { - available_tiles[available_tiles_count] = i * 4 + j; - available_tiles_count++; - } - } - } - - u8 rand_idx = rand() % available_tiles_count; - - u8 x = available_tiles[rand_idx] / 4; - u8 y = available_tiles[rand_idx] % 4; - - spawn_new_tile(x, y); -} - bool gameover(void) { if (game.has_lost) return false; @@ -369,7 +393,7 @@ bool gameover(void) { return true; } -void game_new(void) { +void reset_game(void) { game.score = 0; game.animating = false; game.spawning_new_tile = false; @@ -536,7 +560,7 @@ void draw_game_over(void) { UIConstraints content_card_con = {0}; set_parent_constraint(&content_card_con, &dialog_con); - set_width_constraint(&content_card_con, 0.4f, UI_CONSTRAINT_RELATIVE); + set_width_constraint(&content_card_con, 0.3f, UI_CONSTRAINT_RELATIVE); set_height_constraint(&content_card_con, 0.2f, UI_CONSTRAINT_RELATIVE); draw_quad(&content_card_con, ColorRGBA(135, 124, 124, (u8)game.game_over_opacity), 8, ALIGN_CENTER); @@ -554,13 +578,13 @@ void draw_game_over(void) { set_y_constraint(&btn_con, -24, UI_CONSTRAINT_RELATIVE_PIXELS); set_width_constraint(&btn_con, 0.10f, UI_CONSTRAINT_RELATIVE); set_height_constraint(&btn_con, 0.3f, UI_CONSTRAINT_ASPECT_RATIO); - if (draw_button(&btn_con, ColorRGBA(201, 146, 126, 255), "Try Again", 8.f, ALIGN_BOTTOM_CENTER, btn_state)) { - game_new(); + if (draw_button(&btn_con, ColorRGBA(201, 146, 126, (u8)game.game_over_opacity), "Try Again", 8.f, ALIGN_BOTTOM_CENTER, btn_state)) { + reset_game(); } } void draw_ui(void) { - ButtonState bg_btns_state = game.quit_dialog || game.help_dialog + ButtonState bg_btns_state = game.quit_dialog || game.help_dialog || game.has_lost ? BUTTON_STATE_INACTIVE : BUTTON_STATE_ACTIVE; const int icon_btn_width = 80; @@ -587,7 +611,7 @@ void draw_ui(void) { set_width_constraint(&btn_con, 200, UI_CONSTRAINT_RELATIVE_PIXELS); set_height_constraint(&btn_con, 65, UI_CONSTRAINT_RELATIVE_PIXELS); if (draw_button(&btn_con, ColorRGBA(201, 172, 126, 255), "New Game", btn_con.height * 0.25f, ALIGN_BOTTOM_CENTER, bg_btns_state)) { - game_new(); + reset_game(); } if (game.help_dialog) { @@ -641,12 +665,14 @@ void draw_board(void) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { Tile *tile = &game.board[i][j]; - Color tile_color = get_color_from_tile(*tile); + Color tile_color = get_tile_color(tile->value); char value[16]; sprintf(value, "%d", tile->value); + f32 tile_y_pos = (f32)((tile_height + tile_padding) * i + tile_padding + game.board[i][j].anim_y_offset_relative * board_con.height); + f32 tile_x_pos = (f32)((tile_height + tile_padding) * j + tile_padding + game.board[i][j].anim_x_offset_relative * board_con.height); - set_y_constraint(&tile_con, (f32)((tile_height + tile_padding) * i + tile_padding + game.board[i][j].anim_y_offset_relative * board_con.height), UI_CONSTRAINT_FIXED); - set_x_constraint(&tile_con, (f32)((tile_height + tile_padding) * j + tile_padding + game.board[i][j].anim_x_offset_relative * board_con.height), UI_CONSTRAINT_FIXED); + set_y_constraint(&tile_con, tile_y_pos, UI_CONSTRAINT_FIXED); + set_x_constraint(&tile_con, tile_x_pos, UI_CONSTRAINT_FIXED); if (tile->value > 0) { draw_quad(&tile_con, tile_color, tile_board_radius, ALIGN_TOP_LEFT); @@ -655,10 +681,30 @@ void draw_board(void) { set_x_constraint(&text_con, 0, UI_CONSTRAINT_FIXED); set_y_constraint(&text_con, 0, UI_CONSTRAINT_FIXED); - draw_text(value, get_tile_font_size(*tile), text_con, mult_color(tile_color, 0.5), ALIGN_CENTER); + draw_text(value, get_tile_font_size(tile->value), text_con, mult_color(tile_color, 0.5), ALIGN_CENTER); } } } + + if (game.spawning_new_tile) { + // spawning tile + Color tile_color = get_tile_color(game.spawning_tile_value); + f32 tile_x_pos = (f32)((tile_height + tile_padding) * game.spawning_tile_coords.y + tile_padding) + tile_height / 2 - game.spawning_tile_scale * tile_height / 2; + f32 tile_y_pos = (f32)((tile_height + tile_padding) * game.spawning_tile_coords.x + tile_padding) + tile_height / 2 - game.spawning_tile_scale * tile_height / 2; + set_x_constraint(&tile_con, tile_x_pos, UI_CONSTRAINT_FIXED); + set_y_constraint(&tile_con, tile_y_pos, UI_CONSTRAINT_FIXED); + set_height_constraint(&tile_con, tile_height * game.spawning_tile_scale, UI_CONSTRAINT_FIXED); + set_width_constraint(&tile_con, 1, UI_CONSTRAINT_ASPECT_RATIO); + draw_quad(&tile_con, tile_color, tile_board_radius, ALIGN_TOP_LEFT); + // value text + set_parent_constraint(&text_con, &tile_con); + set_x_constraint(&text_con, 0, UI_CONSTRAINT_FIXED); + set_y_constraint(&text_con, 0, UI_CONSTRAINT_FIXED); + + char value[16]; + sprintf(value, "%d", game.spawning_tile_value); + draw_text(value, (u8)(get_tile_font_size(game.spawning_tile_value) * game.spawning_tile_scale), text_con, mult_color(tile_color, 0.5), ALIGN_CENTER); + } } void update_positions(f64 delta_t) { @@ -676,8 +722,6 @@ void update_positions(f64 delta_t) { src->anim_x_offset_relative -= speed * delta_t; if (src->anim_x_offset_relative <= -0.240f * (tiles_to_move + (tiles_to_move * 0.02f))) { - src->anim_x_offset_relative = -0.240f * (tiles_to_move + (tiles_to_move * 0.02f)); - if (dest->new_value == src->value * 2) { dest->merged = false; } @@ -687,7 +731,6 @@ void update_positions(f64 delta_t) { src->tiles_to_move = 0; src->anim_x_offset_relative = 0; - game.animating = false; game.spawning_new_tile = true; } } @@ -706,8 +749,6 @@ void update_positions(f64 delta_t) { src->anim_x_offset_relative += speed * delta_t; if (src->anim_x_offset_relative >= 0.240f * (tiles_to_move + (tiles_to_move * 0.02f))) { - src->anim_x_offset_relative = 0.240f * (tiles_to_move + (tiles_to_move * 0.02f)); - if (dest->new_value == src->value * 2) { dest->merged = false; } @@ -717,7 +758,6 @@ void update_positions(f64 delta_t) { src->tiles_to_move = 0; src->anim_x_offset_relative = 0; - game.animating = false; game.spawning_new_tile = true; } } @@ -736,8 +776,6 @@ void update_positions(f64 delta_t) { src->anim_y_offset_relative -= speed * delta_t; if (src->anim_y_offset_relative <= -0.240f * (tiles_to_move + (tiles_to_move * 0.02f))) { - src->anim_y_offset_relative = -0.240f * (tiles_to_move + (tiles_to_move * 0.02f)); - if (dest->new_value == src->value * 2) { dest->merged = false; } @@ -747,7 +785,6 @@ void update_positions(f64 delta_t) { src->tiles_to_move = 0; src->anim_y_offset_relative = 0; - game.animating = false; game.spawning_new_tile = true; } } @@ -766,8 +803,6 @@ void update_positions(f64 delta_t) { src->anim_y_offset_relative += speed * delta_t; if (src->anim_y_offset_relative >= 0.240f * (tiles_to_move + (tiles_to_move * 0.02f))) { - src->anim_y_offset_relative = 0.240f * (tiles_to_move + (tiles_to_move * 0.02f)); - if (dest->new_value == src->value * 2) { dest->merged = false; } @@ -777,7 +812,6 @@ void update_positions(f64 delta_t) { src->tiles_to_move = 0; src->anim_y_offset_relative = 0; - game.animating = false; game.spawning_new_tile = true; } } @@ -793,8 +827,16 @@ void update_positions(f64 delta_t) { } if (game.spawning_new_tile) { - spawn_random_tile(); - game.spawning_new_tile = false; + game.spawning_tile_scale += (float)(TILE_SPAWN_SPEED * delta_t); + + if (game.spawning_tile_scale >= 1.0f) { + spawn_new_tile_with_value(game.spawning_tile_coords.x, game.spawning_tile_coords.y, game.spawning_tile_value); + game.spawning_tile_coords = (Vec2){0, 0}; + game.spawning_tile_value = 0; + game.spawning_new_tile = false; + game.animating = false; + game.spawning_tile_scale = 0.0f; + } } if (game.has_lost) { diff --git a/game.h b/game.h index 5a5d2d0..0a0fb3a 100644 --- a/game.h +++ b/game.h @@ -37,6 +37,9 @@ typedef struct Game { bool has_lost; float game_over_bg_opacity; float game_over_opacity; + float spawning_tile_scale; + Vec2 spawning_tile_coords; + u16 spawning_tile_value; TextureId icon_textures[ICON_TEXTURE_COUNT]; bool quit_dialog; diff --git a/ui.c b/ui.c index fa63945..2e4ca2e 100644 --- a/ui.c +++ b/ui.c @@ -347,6 +347,7 @@ void draw_texture(UIConstraints *constraints, const TextureId texture_id, const bool draw_button(UIConstraints *constraints, const Color color, const char *text, f32 radius, Alignment align, ButtonState state) { Color text_color = COLOR_BLACK; + text_color.a = color.a; Rect rect = {0}; apply_constraints(constraints, &rect.pos, &rect.size);