diff --git a/.gitignore b/.gitignore index ce107ac..6ac837e 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,4 @@ src/.gpskip .gpskip ginpee.toml src/ginpee.toml +.vscode/launch.json diff --git a/src/brick_game/tetris/game_logic.c b/src/brick_game/tetris/game_logic.c index 9789c7b..cbc02b7 100644 --- a/src/brick_game/tetris/game_logic.c +++ b/src/brick_game/tetris/game_logic.c @@ -46,12 +46,11 @@ void init_game() { state->next_figure.rotation = 0; state->score = 0; - state->high_score = 0; state->level = 1; state->drop_time = time(NULL) * 1000; state->game_over = false; state->paused = false; - state->state = FSM_Start; + state->state = FSM_Start; // Начинаем в состоянии Start } void place_figure() { @@ -65,7 +64,7 @@ void place_figure() { int x = f->x + j; int y = f->y + i; if (y >= 0 && y < FIELD_HEIGHT && x >= 0 && x < FIELD_WIDTH) { - state->game_field[y][x] = 1; + state->game_field[y][x] = 1; // Фиксируем блок } } } @@ -74,12 +73,26 @@ void place_figure() { // Проверяем и удаляем заполненные строки clear_completed_lines(); - // Меняем состояние на Spawn для генерации новой фигуры - state->state = FSM_Spawn; + // Спавним новую фигуру + state->current_figure = state->next_figure; + state->current_figure.x = FIELD_WIDTH / 2 - 2; + state->current_figure.y = 0; + state->current_figure.rotation = 0; + + // Генерируем следующую фигуру + state->next_figure.type = get_random_figure(); + state->next_figure.rotation = 0; + + // Проверяем, возможно ли размещение новой фигуры + if (check_collision()) { + state->state = FSM_GameOver; + } else { + state->state = FSM_Moving; + } } void clear_completed_lines() { - GameStateData* state = get_instance(); + GameStateData* state = get_game_state(); int lines_cleared = 0; int write_row = FIELD_HEIGHT - 1; @@ -122,7 +135,7 @@ void clear_completed_lines() { } else { score_points = points[4]; // для > 4 линий } - state->score += score_points * state->level; + state->score += score_points; // УБРАЛ УМНОЖЕНИЕ НА УРОВЕНЬ if (state->score > state->high_score) { state->high_score = state->score; @@ -164,11 +177,11 @@ bool check_collision() { } void fsm_transition() { - GameStateData* state = get_instance(); + GameStateData* state = get_game_state(); switch (state->state) { case FSM_Start: - state->state = FSM_Spawn; + // Ожидание начала игры - не делаем ничего, пока не будет нажата Start break; case FSM_Spawn: @@ -202,7 +215,8 @@ void fsm_transition() { case FSM_Attaching: place_figure(); - state->state = FSM_Spawn; + // После place_figure проверяем, не произошел ли Game Over + // В place_figure уже устанавливается FSM_Spawn, но нужно проверить столкновение break; case FSM_GameOver: diff --git a/src/brick_game/tetris/tetris.c b/src/brick_game/tetris/tetris.c index aac41b7..bacc390 100644 --- a/src/brick_game/tetris/tetris.c +++ b/src/brick_game/tetris/tetris.c @@ -44,27 +44,14 @@ void userInput(UserAction_t action, bool hold) { GameInfo_t* game_info = get_game_info_instance(); switch (action) { - case Start: - if (state->state == FSM_GameOver) { - // Перезапуск игры - int saved_high_score = state->high_score; - init_game(); - state->high_score = saved_high_score; - state->state = FSM_Spawn; - } else { - state->paused = !state->paused; - } - break; - - case Pause: - state->paused = !state->paused; - break; - case Terminate: // Освобождаем память при завершении if (game_info->field != NULL) { for (int i = 0; i < FIELD_HEIGHT; i++) { - free(game_info->field[i]); + if (game_info->field[i] != NULL) { + free(game_info->field[i]); + game_info->field[i] = NULL; + } } free(game_info->field); game_info->field = NULL; @@ -72,15 +59,38 @@ void userInput(UserAction_t action, bool hold) { if (game_info->next != NULL) { for (int i = 0; i < 4; i++) { - free(game_info->next[i]); + if (game_info->next[i] != NULL) { + free(game_info->next[i]); + game_info->next[i] = NULL; + } } free(game_info->next); game_info->next = NULL; } + return; // ВАЖНО: выходим из функции, не делаем ничего после Terminate + + case Start: + if (state->state == FSM_GameOver) { + // Перезапуск игры после Game Over + int saved_high_score = state->high_score; + init_game(); + state->high_score = saved_high_score; + // Не меняем состояние, пусть остается в Start до следующего нажатия + } else if (state->state == FSM_Start) { + // Начинаем игру из состояния Start + state->state = FSM_Spawn; + } else { + // Для всех других состояний (Moving, Move) - ставим на паузу + state->paused = !state->paused; + } + break; + + case Pause: + state->paused = !state->paused; break; default: - if (state->state == FSM_GameOver || state->paused) { + if (state->state == FSM_GameOver || state->paused || state->state == FSM_Start) { break; } @@ -136,7 +146,7 @@ GameInfo_t updateCurrentState() { GameStateData* state = get_game_state(); GameInfo_t* game_info = get_game_info_instance(); - if (!state->game_over && !state->paused) { + if (state->state != FSM_Start && !state->game_over && !state->paused) { long long current_time = time(NULL) * 1000; // Определяем интервал падения в зависимости от уровня @@ -149,8 +159,10 @@ GameInfo_t updateCurrentState() { } } - // Выполняем переходы FSM - fsm_transition(); + // Выполняем переходы FSM (но не в состоянии Start) + if (state->state != FSM_Start) { + fsm_transition(); + } // Обновляем game_info.field из state->game_field for (int i = 0; i < FIELD_HEIGHT; i++) { @@ -159,7 +171,7 @@ GameInfo_t updateCurrentState() { } } - // Добавляем активную фигуру на поле для отображения (если не game_over) + // Добавляем активную фигуру на поле для отображения (если не в Start или GameOver) if ((state->state == FSM_Moving || state->state == FSM_Move) && !state->game_over) { Figure* f = &state->current_figure; const int (*shape)[4] = get_figure_shape(f->type, f->rotation); @@ -168,8 +180,12 @@ GameInfo_t updateCurrentState() { if (shape[i][j]) { int x = f->x + j; int y = f->y + i; + // Проверяем границы перед записью if (x >= 0 && x < FIELD_WIDTH && y >= 0 && y < FIELD_HEIGHT) { - game_info->field[y][x] = 1; + // Не перезаписываем уже зафиксированные блоки + if (state->game_field[y][x] == 0) { + game_info->field[y][x] = 1; + } } } } @@ -178,8 +194,8 @@ GameInfo_t updateCurrentState() { // Обновляем next const int (*next_shape)[4]; - if (state->state == FSM_GameOver) { - // При game_over показываем пустую фигуру + if (state->state == FSM_GameOver || state->state == FSM_Start) { + // При game_over или в начальном состоянии показываем пустую фигуру next_shape = empty_fig(); } else { next_shape = get_figure_shape(state->next_figure.type, state->next_figure.rotation); diff --git a/src/gui/cli/display.c b/src/gui/cli/display.c index 2bcb57f..214e168 100644 --- a/src/gui/cli/display.c +++ b/src/gui/cli/display.c @@ -3,9 +3,13 @@ #include "../../brick_game/tetris/tetris.h" void display_game() { + printf("DEBUG: display_game called\n"); clear(); GameInfo_t game_state = updateCurrentState(); + + printf("DEBUG: Got game state, field: %p, next: %p\n", + game_state.field, game_state.next); // Отображение игрового поля for (int i = 0; i < FIELD_HEIGHT; i++) { @@ -43,4 +47,5 @@ void display_game() { } refresh(); + printf("DEBUG: display_game completed\n"); } \ No newline at end of file diff --git a/src/gui/cli/main.c b/src/gui/cli/main.c index 6e6638a..a08d580 100644 --- a/src/gui/cli/main.c +++ b/src/gui/cli/main.c @@ -64,12 +64,12 @@ int main() { userInput(current_action, false); } - updateCurrentState(); - display_game(); + if (running) { // Обновляем состояние только если не завершаемся + updateCurrentState(); + display_game(); + } } - // Вызов userInput с Terminate для освобождения памяти - userInput(Terminate, false); endwin(); return 0; } \ No newline at end of file