diff options
author | turnipgod | 2025-03-04 14:34:34 -0500 |
---|---|---|
committer | turnipgod | 2025-03-04 14:34:34 -0500 |
commit | fd7f9092da2cb1bc85161263b985c3f0f45e7302 (patch) | |
tree | b2b0649597c645cfdc8b8cb442d25f495e235bf6 | |
parent | df24be9450f1221eea839b3c64982a0624627970 (diff) |
major refactor using a state machine to prepare for animations later
-rw-r--r-- | build.ninja | 1 | ||||
-rw-r--r-- | src/main.c | 423 |
2 files changed, 226 insertions, 198 deletions
diff --git a/build.ninja b/build.ninja index a173608..7166436 100644 --- a/build.ninja +++ b/build.ninja @@ -14,4 +14,3 @@ build out/tg_tetris: ld obj/main.o ldflags = -lraylib -lm build obj/main.o: cc src/main.c - diff --git a/src/main.c b/src/main.c index 9ef03f0..fc42c4f 100644 --- a/src/main.c +++ b/src/main.c @@ -11,8 +11,8 @@ #define BLOCK_SIZE 25 -#define FALL_TICK 0.2 -#define SOFT_DROP_MULT 4 +#define FALL_TICK 0.3 +#define SOFT_DROP_MULT 4.0 #define LOCK_TICK 0.5 enum Phases { @@ -20,13 +20,19 @@ enum Phases { FALL, LOCK, PATTERN, - MARK, - ITERATE, - ANIMATE, - ELIMINATE, - COMPLETE + //MARK, + //ITERATE, + //ANIMATE, + //ELIMINATE, + //COMPLETE } game_phase; +enum InputResult { + NONE = 0, + MOVED, + HARD_DROPPED +}; + #include "tetromino.h" struct { @@ -42,8 +48,8 @@ int current_bag = 0; int current_piece_index = 0; int hold = 7; int held = 0; -int hard_drop = 0; -double phase_time = 0.0; +double phase_time; +double fall_tick; void draw_block(int x, int y, int width, int height, struct Color color) { @@ -95,48 +101,50 @@ void render_matrix(void) } } - /* draw ghost piece */ int ghost_y = 0; - while(!is_overlap(0, ghost_y)) { - ghost_y--; - } + if (game_phase == FALL || game_phase == LOCK) { + /* draw ghost piece */ + while(!is_overlap(0, ghost_y)) { + ghost_y--; + } - for (int i = 0; i < tetrominos[current_piece.type].size; i++) { - for (int j = 0; j < tetrominos[current_piece.type].size; j++) { - if (tetrominos[current_piece.type].directions[current_piece.rotation][j][i] == 1) { - draw_block( - (matrix_origin_x + ((current_piece.pos_x + i - 1) * BLOCK_SIZE)) + 3 - ,(matrix_origin_y + ((current_piece.pos_y + j + ghost_y) * BLOCK_SIZE)) + 3 - ,BLOCK_SIZE - 6 - ,BLOCK_SIZE - 6 - ,tetrominos[current_piece.type].color - ); - draw_block( - (matrix_origin_x + ((current_piece.pos_x + i - 1) * BLOCK_SIZE)) + 4 - ,(matrix_origin_y + ((current_piece.pos_y + j + ghost_y) * BLOCK_SIZE)) + 4 - ,BLOCK_SIZE - 8 - ,BLOCK_SIZE - 8 - ,BLACK - ); + for (int i = 0; i < tetrominos[current_piece.type].size; i++) { + for (int j = 0; j < tetrominos[current_piece.type].size; j++) { + if (tetrominos[current_piece.type].directions[current_piece.rotation][j][i] == 1) { + draw_block( + (matrix_origin_x + ((current_piece.pos_x + i - 1) * BLOCK_SIZE)) + 3 + ,(matrix_origin_y + ((current_piece.pos_y + j + ghost_y) * BLOCK_SIZE)) + 3 + ,BLOCK_SIZE - 6 + ,BLOCK_SIZE - 6 + ,tetrominos[current_piece.type].color + ); + draw_block( + (matrix_origin_x + ((current_piece.pos_x + i - 1) * BLOCK_SIZE)) + 4 + ,(matrix_origin_y + ((current_piece.pos_y + j + ghost_y) * BLOCK_SIZE)) + 4 + ,BLOCK_SIZE - 8 + ,BLOCK_SIZE - 8 + ,BLACK + ); + } } } - } - - /* draw current piece */ - for (int i = 0; i < tetrominos[current_piece.type].size; i++) { - for (int j = 0; j < tetrominos[current_piece.type].size; j++) { - if (tetrominos[current_piece.type].directions[current_piece.rotation][j][i] == 1) { - draw_block( - (matrix_origin_x + ((current_piece.pos_x + i - 1) * BLOCK_SIZE)) + 1 - ,(matrix_origin_y + ((current_piece.pos_y + j - 1) * BLOCK_SIZE)) + 1 - ,BLOCK_SIZE - 2 - ,BLOCK_SIZE - 2 - ,tetrominos[current_piece.type].color - ); + /* draw current piece */ + for (int i = 0; i < tetrominos[current_piece.type].size; i++) { + for (int j = 0; j < tetrominos[current_piece.type].size; j++) { + if (tetrominos[current_piece.type].directions[current_piece.rotation][j][i] == 1) { + draw_block( + (matrix_origin_x + ((current_piece.pos_x + i - 1) * BLOCK_SIZE)) + 1 + ,(matrix_origin_y + ((current_piece.pos_y + j - 1) * BLOCK_SIZE)) + 1 + ,BLOCK_SIZE - 2 + ,BLOCK_SIZE - 2 + ,tetrominos[current_piece.type].color + ); + } } } } + /* draw piece hold */ draw_block( SCREEN_WIDTH/2 + 1 - (BLOCK_SIZE), @@ -203,6 +211,9 @@ void shuffle_bag(int *bag) void generation_phase(void) { + if (phase_time < 0.2) { + return; + } // bag generation if (current_piece_index == 14) { shuffle_bag(&(piece_queue[7])); @@ -217,14 +228,73 @@ void generation_phase(void) current_piece.rotation = NORTH; current_piece.pos_x = 4; current_piece.pos_y = 20; - if (is_overlap(0,0)) { - CloseWindow(); + held = 0; + phase_time = 0.0; + game_phase = FALL; +} + +int rotate_piece(int dir) +{ + int *kick_table; + int i; + int can_rotate = 0; + + if (dir == 1) { + kick_table = tetrominos[current_piece.type].cw_kick_table[current_piece.rotation]; + } else if (dir == -1) { + kick_table = tetrominos[current_piece.type].ccw_kick_table[current_piece.rotation]; + } + + current_piece.rotation += dir; + if (current_piece.rotation < 0) { + current_piece.rotation = 3; + } else { + current_piece.rotation = current_piece.rotation % 4; + } + + for (i = 0; i < 10 && !can_rotate; i += 2) { + if (!is_overlap(kick_table[i], kick_table[i+1])) { + current_piece.pos_x += kick_table[i]; + current_piece.pos_y += kick_table[i+1]; + can_rotate = 1; + } } + + if (!can_rotate) { + current_piece.rotation -= dir; + if (current_piece.rotation < 0) { + current_piece.rotation = 3; + } else { + current_piece.rotation = current_piece.rotation % 4; + } + } + + return can_rotate; +} + +int move_piece(int dir) +{ + if (is_overlap(dir, 0)) { + return 0; + } + current_piece.pos_x += dir; + return 1; } -void handle_hold(void) +void move_piece_to_matrix(void) { - if (IsKeyDown(KEY_SPACE) && !held) { + for (int i = 0; i < tetrominos[current_piece.type].size; i++) { + for (int j = 0; j < tetrominos[current_piece.type].size; j++) { + if (tetrominos[current_piece.type].directions[current_piece.rotation][j][i] == 1) { + matrix[current_piece.pos_x + i - 1][current_piece.pos_y + j - 1] = tetrominos[current_piece.type].color; + } + } + } +} + +void hold_piece(void) +{ + if (!held) { if (hold == 7) { hold = current_piece.type; current_piece.type = piece_queue[current_piece_index]; @@ -235,6 +305,7 @@ void handle_hold(void) current_piece.type = hold; hold = temp; } + phase_time = 0.0; game_phase = FALL; current_piece.rotation = NORTH; current_piece.pos_x = 4; @@ -246,165 +317,108 @@ void handle_hold(void) } } -void handle_rotate(void) -{ - static int rotated_cw = 0; - static int rotated_ccw = 0; - if (game_phase == FALL || game_phase == LOCK) { - int *kick_table; - int can_rotate = 0; - int i; - if (IsKeyDown(KEY_L) && !rotated_cw) { - kick_table = tetrominos[current_piece.type].cw_kick_table[current_piece.rotation]; - current_piece.rotation++; - current_piece.rotation = current_piece.rotation % 4; - for (i = 0; i < 10 && !can_rotate; i += 2) { - if (!is_overlap(kick_table[i], kick_table[i+1])) { - current_piece.pos_x += kick_table[i]; - current_piece.pos_y += kick_table[i+1]; - can_rotate = 1; - if (game_phase == LOCK) { - phase_time = 0.0; - } - } - } - if (!can_rotate) { - current_piece.rotation--; - if (current_piece.rotation < 0) current_piece.rotation = 3; - } - rotated_cw = 1; - } - if (IsKeyUp(KEY_L)) { - rotated_cw = 0; - } - if (IsKeyDown(KEY_J) && !rotated_ccw) { - kick_table = tetrominos[current_piece.type].ccw_kick_table[current_piece.rotation]; - current_piece.rotation--; - if (current_piece.rotation < 0) current_piece.rotation = 3; - for (i = 0; i < 10 && !can_rotate; i += 2) { - if (!is_overlap(kick_table[i], kick_table[i+1])) { - current_piece.pos_x += kick_table[i]; - current_piece.pos_y += kick_table[i+1]; - can_rotate = 1; - if (game_phase == LOCK) { - phase_time = 0.0; - } - } - } - if (!can_rotate) { - current_piece.rotation++; - current_piece.rotation = current_piece.rotation % 4; - } - rotated_ccw = 1; - } - if (IsKeyUp(KEY_J)) { - rotated_ccw = 0; +int handle_input(void) { + static int moved_l = 0; + static int moved_r = 0; + static int moved_cw = 0; + static int moved_ccw = 0; + static int hard_dropped = 0; + + if (IsKeyDown(KEY_A)) { + if (!moved_l) { + moved_l = move_piece(-1); + return MOVED; } + } else { + moved_l = 0; } -} -void move_right(void) -{ - if (is_overlap(1, 0)) { - return; - } - if (game_phase == LOCK) { - phase_time = 0.0; + if (IsKeyDown(KEY_D)) { + if (!moved_r) { + moved_r = move_piece(+1); + return MOVED; + } + } else { + moved_r = 0; } - current_piece.pos_x++; -} -void move_left(void) -{ - if (is_overlap(-1, 0)) { - return; - } - if (game_phase == LOCK) { - phase_time = 0.0; + if (IsKeyDown(KEY_L)) { + if (!moved_cw) { + moved_cw = rotate_piece(+1); + return MOVED; + } + } else { + moved_cw = 0; } - current_piece.pos_x--; -} -void handle_lr(void) -{ - static int moved_right = 0; - static int moved_left = 0; - if (game_phase == FALL || game_phase == LOCK) { - if (IsKeyDown(KEY_D) && !moved_right) { - move_right(); - moved_right = 1; - } - if (IsKeyUp(KEY_D)) { - moved_right = 0; - } - if (IsKeyDown(KEY_A) && !moved_left) { - move_left(); - moved_left = 1; - } - if (IsKeyUp(KEY_A)) { - moved_left = 0; + if (IsKeyDown(KEY_J)) { + if (!moved_ccw) { + moved_ccw = rotate_piece(-1); + return MOVED; } + } else { + moved_ccw = 0; } -} -void move_piece_to_matrix(void) -{ - for (int i = 0; i < tetrominos[current_piece.type].size; i++) { - for (int j = 0; j < tetrominos[current_piece.type].size; j++) { - if (tetrominos[current_piece.type].directions[current_piece.rotation][j][i] == 1) { - matrix[current_piece.pos_x + i - 1][current_piece.pos_y + j - 1] = tetrominos[current_piece.type].color; + if (IsKeyDown(KEY_W)) { + if (!hard_dropped) { + hard_dropped = 1; + while (!is_overlap(0, -1)) { + current_piece.pos_y--; } + return HARD_DROPPED; } + } else { + hard_dropped = 0; } -} -void handle_fall(void) -{ - phase_time += GetFrameTime(); - if (game_phase == FALL) { - if (!hard_drop && ((!IsKeyDown(KEY_S) && phase_time < FALL_TICK) || phase_time < FALL_TICK / SOFT_DROP_MULT)) { - return; - } else { - phase_time = 0.0; - } + if (IsKeyDown(KEY_S)) { + fall_tick = FALL_TICK / SOFT_DROP_MULT; + } else { + fall_tick = FALL_TICK; } - if (is_overlap(0, -1)) { - game_phase = LOCK; - } else { - game_phase = FALL; - current_piece.pos_y--; + if (IsKeyDown(KEY_SPACE)) { + hold_piece(); } - if (is_overlap(0, -1) && (phase_time >= LOCK_TICK || hard_drop)) { - move_piece_to_matrix(); - generation_phase(); - held = 0; + return NONE; +} + +void lock_phase(void) { + enum InputResult action = handle_input(); + if (action == MOVED) { + phase_time = 0.0; + } + if (!is_overlap(0, -1)) { + phase_time = 0.0; game_phase = FALL; + } else if (phase_time >= LOCK_TICK || action == HARD_DROPPED) { + move_piece_to_matrix(); phase_time = 0.0; - hard_drop = 0; - return; - } + game_phase = PATTERN; + } } -void handle_hard_drop(void) +void fall_phase(void) { - static int dropped = 0; - if (game_phase == FALL || game_phase == LOCK) { - if (IsKeyDown(KEY_W) && !dropped) { - dropped = 1; - hard_drop = 1; - while(!is_overlap(0, -1)) { - current_piece.pos_y--; - } - } - if (IsKeyUp(KEY_W)) { - dropped = 0; + enum InputResult action = handle_input(); + if (action == HARD_DROPPED) { + phase_time = 0.0; + game_phase = PATTERN; + } else { + if (is_overlap(0, -1)) { + phase_time = 0.0; + game_phase = LOCK; + } else if (phase_time >= fall_tick || action == HARD_DROPPED) { + phase_time = 0.0; + current_piece.pos_y--; } } } -void clear_line(int line) { +void clear_line(int line) +{ for (int y = line; y < MATRIX_HEIGHT - 1; y++) { for (int x = 0; x < MATRIX_WIDTH; x++) { matrix[x][y] = matrix[x][y+1]; @@ -415,8 +429,9 @@ void clear_line(int line) { } } -void handle_line_clears(void) +void pattern_phase(void) { + move_piece_to_matrix(); for (int y = 0; y < MATRIX_HEIGHT; y++) { int line_full = 1; for (int x = 0; x < MATRIX_WIDTH; x++) { @@ -425,9 +440,30 @@ void handle_line_clears(void) } } if (line_full) { - clear_line(y); + clear_line(y--); } } + phase_time = 0.0; + game_phase = GENERATION; +} + +void game_logic(void) +{ + phase_time += GetFrameTime(); + switch (game_phase) { + case GENERATION: + generation_phase(); + break; + case FALL: + fall_phase(); + break; + case LOCK: + lock_phase(); + break; + case PATTERN: + pattern_phase(); + break; + } } int main(void) @@ -436,30 +472,23 @@ int main(void) InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "~turnipGod's Tetris"); - // set all blocks to white + // set default block colors for (int y = 0; y < 40; y++) { for (int x = 0; x < 10; x++) { - matrix[x][y] = WHITE; - } - } - - for (int y = 0; y < 20; y++) { - for (int x = 0; x < 10; x++) { - matrix[x][y] = BLACK; + if (y < 20) { + matrix[x][y] = BLACK; + } else { + matrix[x][y] = WHITE; + } } } - game_phase = FALL; shuffle_bag(piece_queue); shuffle_bag(&(piece_queue[7])); - generation_phase(); + phase_time = 0.0; + game_phase = GENERATION; while (!WindowShouldClose()) { - handle_lr(); - handle_rotate(); - handle_hold(); - handle_hard_drop(); - handle_fall(); - handle_line_clears(); + game_logic(); BeginDrawing(); ClearBackground(WHITE); render_matrix(); |