Всё фигня, давай по новой
This commit is contained in:
parent
485ac0ca40
commit
f8e1e664a7
13 changed files with 199 additions and 479 deletions
|
|
@ -1,10 +1,18 @@
|
|||
#ifndef GAME_LOGIC_H
|
||||
#define GAME_LOGIC_H
|
||||
#ifndef AUTOMATO_H
|
||||
#define AUTOMATO_H
|
||||
|
||||
#include "00_tetris.h"
|
||||
#include <stdbool.h>
|
||||
#include "tetris.h" // для использования GameInfo_t
|
||||
|
||||
// Типы фигур
|
||||
typedef enum {
|
||||
Init,
|
||||
Spawn,
|
||||
Moving,
|
||||
Move,
|
||||
Attaching,
|
||||
GameOver
|
||||
} Automato_t;
|
||||
|
||||
typedef enum {
|
||||
I = 0,
|
||||
J,
|
||||
|
|
@ -16,47 +24,45 @@ typedef enum {
|
|||
FIGURE_COUNT
|
||||
} FigureType;
|
||||
|
||||
// FSM состояния
|
||||
typedef enum {
|
||||
FSM_Start,
|
||||
FSM_Spawn,
|
||||
FSM_Moving,
|
||||
FSM_Move,
|
||||
FSM_Attaching,
|
||||
FSM_GameOver
|
||||
} FSMState_t;
|
||||
|
||||
// Структура фигуры
|
||||
typedef struct {
|
||||
int x, y; // Позиция фигуры на поле
|
||||
int mtrx[4][4]; // сама матрица
|
||||
FigureType type; // Тип фигуры
|
||||
int rotation; // Поворот (0–3)
|
||||
} Figure;
|
||||
|
||||
typedef struct {
|
||||
int game_field[FIELD_HEIGHT][FIELD_WIDTH];
|
||||
Figure current_figure;
|
||||
Figure next_figure;
|
||||
FSMState_t state;
|
||||
Figure curr;
|
||||
Figure next;
|
||||
Automato_t state;
|
||||
int field[FIELD_HEIGHT][FIELD_WIDTH];
|
||||
int score;
|
||||
int high_score;
|
||||
int level;
|
||||
long long drop_time;
|
||||
bool game_over;
|
||||
bool paused;
|
||||
} GameStateData;
|
||||
int speed;
|
||||
long long last_time;
|
||||
} GameState_t;
|
||||
|
||||
// Внутренние функции
|
||||
bool check_collision(void);
|
||||
void init_game(void);
|
||||
void fsm_transition(void);
|
||||
int get_random_figure(void);
|
||||
GameState_t* get_game_state(void);
|
||||
|
||||
// Функции состояний
|
||||
void do_start(void);
|
||||
void do_spawn(void);
|
||||
void do_move(void);
|
||||
void do_moving(void);
|
||||
void do_attaching(void);
|
||||
void do_gameover(void);
|
||||
|
||||
// Вспомогательные
|
||||
void place_figure_on_field();
|
||||
int check_collision();
|
||||
void clear_lines();
|
||||
int is_game_over();
|
||||
|
||||
// Функции фигур
|
||||
const int (*get_figure_shape(FigureType type, int rotation))[4];
|
||||
GameStateData* get_game_state(void);
|
||||
void place_figure(void);
|
||||
void clear_completed_lines(void);
|
||||
|
||||
// Фигуры
|
||||
// Остальные фигуры...
|
||||
const int (*i_fig_up())[4];
|
||||
const int (*i_fig_right())[4];
|
||||
const int (*i_fig_down())[4];
|
||||
|
|
@ -84,4 +90,5 @@ const int (*z_fig_down())[4];
|
|||
const int (*z_fig_left())[4];
|
||||
const int (*empty_fig())[4];
|
||||
|
||||
|
||||
#endif
|
||||
12
src/brick_game/tetris/02_automato.c
Normal file
12
src/brick_game/tetris/02_automato.c
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#include "01_automato.h"
|
||||
|
||||
static GameState_t g_state = {0};
|
||||
|
||||
GameState_t* get_game_state(void) {
|
||||
static int initialized = 0;
|
||||
if (!initialized) {
|
||||
g_state.state = GameOver;
|
||||
initialized = 1;
|
||||
}
|
||||
return &g_state;
|
||||
}
|
||||
63
src/brick_game/tetris/03_tetris.c
Normal file
63
src/brick_game/tetris/03_tetris.c
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#include "01_automato.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void userInput(UserAction_t action, bool hold) {
|
||||
GameState_t* state = get_game_state();
|
||||
|
||||
switch (action) {
|
||||
case Start:
|
||||
state->state = Start;
|
||||
break;
|
||||
case Terminate:
|
||||
if (state->score > state->high_score) {
|
||||
state->high_score = state->score;
|
||||
}
|
||||
exit(0);
|
||||
break;
|
||||
case Left:
|
||||
case Right:
|
||||
case Action:
|
||||
state->state = Moving;
|
||||
break;
|
||||
case Down:
|
||||
// Ускорение падения — будет обрабатываться в do_move
|
||||
break;
|
||||
case Pause:
|
||||
// Обработка на UI
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GameInfo_t updateCurrentState() {
|
||||
GameState_t* state = get_game_state();
|
||||
switch (state->state) {
|
||||
case Start:
|
||||
do_start();
|
||||
break;
|
||||
case Spawn:
|
||||
do_spawn();
|
||||
break;
|
||||
case Move:
|
||||
do_move();
|
||||
break;
|
||||
case Moving:
|
||||
do_moving();
|
||||
break;
|
||||
case Attaching:
|
||||
do_attaching();
|
||||
break;
|
||||
case GameOver:
|
||||
do_gameover();
|
||||
break;
|
||||
}
|
||||
|
||||
GameInfo_t info = {0};
|
||||
info.field = (int**)state->field;
|
||||
info.next = (int**)state->next.mtrx; // теперь next.mtrx
|
||||
info.score = state->score;
|
||||
info.high_score = state->high_score;
|
||||
info.level = state->level;
|
||||
info.speed = state->speed;
|
||||
info.pause = 0;
|
||||
return info;
|
||||
}
|
||||
14
src/brick_game/tetris/04_start.c
Normal file
14
src/brick_game/tetris/04_start.c
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include "01_automato.h"
|
||||
|
||||
void do_start(void) {
|
||||
GameState_t* state = get_game_state();
|
||||
// Очистка поля
|
||||
for (int i = 0; i < FIELD_HEIGHT; i++)
|
||||
for (int j = 0; j < FIELD_WIDTH; j++)
|
||||
state->field[i][j] = 0;
|
||||
|
||||
state->score = 0;
|
||||
state->level = 1;
|
||||
state->speed = 1;
|
||||
state->state = Spawn;
|
||||
}
|
||||
26
src/brick_game/tetris/05_spawn.c
Normal file
26
src/brick_game/tetris/05_spawn.c
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include "01_automato.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void do_spawn(void) {
|
||||
GameState_t* state = get_game_state();
|
||||
// Присваиваем curr = next
|
||||
state->curr = state->next;
|
||||
state->curr.x = FIELD_WIDTH / 2 - 2;
|
||||
state->curr.y = 0;
|
||||
|
||||
// Генерим следующую фигуру
|
||||
state->next.type = rand() % FIGURE_COUNT;
|
||||
state->next.rotation = 0;
|
||||
const int (*shape)[4] = get_figure_shape(state->next.type, 0);
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
state->next.mtrx[i][j] = shape[i][j];
|
||||
|
||||
// Проверка на GameOver
|
||||
if (check_collision()) {
|
||||
state->state = GameOver;
|
||||
return;
|
||||
}
|
||||
|
||||
state->state = Move;
|
||||
}
|
||||
8
src/brick_game/tetris/06_move.c
Normal file
8
src/brick_game/tetris/06_move.c
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#include "01_automato.h"
|
||||
|
||||
void do_move(void) {
|
||||
GameState_t* state = get_game_state();
|
||||
// Проверка таймера и перемещение вниз
|
||||
// Если hold Down — ускорение
|
||||
// Если коллизия — переход в Attaching
|
||||
}
|
||||
8
src/brick_game/tetris/07_moving.c
Normal file
8
src/brick_game/tetris/07_moving.c
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#include "01_automato.h"
|
||||
|
||||
void do_moving(void) {
|
||||
GameState_t* state = get_game_state();
|
||||
// Обработка Left/Right/Action
|
||||
// Проверка коллизии
|
||||
// Возврат в Move или остаться в Moving
|
||||
}
|
||||
19
src/brick_game/tetris/08_attaching.c
Normal file
19
src/brick_game/tetris/08_attaching.c
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include "01_automato.h"
|
||||
|
||||
void do_attaching(void) {
|
||||
GameState_t* state = get_game_state();
|
||||
// Закрепляем фигуру на поле
|
||||
place_figure_on_field();
|
||||
|
||||
// Удаляем линии
|
||||
clear_lines();
|
||||
|
||||
// Проверяем GameOver
|
||||
if (is_game_over()) {
|
||||
state->state = GameOver;
|
||||
return;
|
||||
}
|
||||
|
||||
// Переход в Spawn
|
||||
state->state = Spawn;
|
||||
}
|
||||
9
src/brick_game/tetris/09_gameover.c
Normal file
9
src/brick_game/tetris/09_gameover.c
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#include "01_automato.h"
|
||||
|
||||
void do_gameover(void) {
|
||||
GameState_t* state = get_game_state();
|
||||
// Сброс next в пустую фигуру
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
state->next.mtrx[i][j] = 0;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "game_logic.h"
|
||||
#include "01_automato.h"
|
||||
#include <string.h>
|
||||
|
||||
const int (*get_figure_shape(FigureType type, int rotation))[4] {
|
||||
|
|
@ -1,228 +0,0 @@
|
|||
#include "tetris.h"
|
||||
#include "game_logic.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
static GameStateData* get_instance() {
|
||||
static GameStateData instance = {0};
|
||||
static bool initialized_local = false;
|
||||
|
||||
if (!initialized_local) {
|
||||
// Инициализация экземпляра
|
||||
for (int i = 0; i < FIELD_HEIGHT; i++) {
|
||||
for (int j = 0; j < FIELD_WIDTH; j++) {
|
||||
instance.game_field[i][j] = 0;
|
||||
}
|
||||
}
|
||||
instance.score = 0;
|
||||
instance.high_score = 0;
|
||||
instance.level = 1;
|
||||
instance.state = FSM_Start;
|
||||
instance.game_over = false;
|
||||
instance.paused = false;
|
||||
initialized_local = true;
|
||||
}
|
||||
|
||||
return &instance;
|
||||
}
|
||||
|
||||
void init_game() {
|
||||
GameStateData* state = get_instance();
|
||||
|
||||
// Инициализация игрового поля
|
||||
for (int i = 0; i < FIELD_HEIGHT; i++) {
|
||||
for (int j = 0; j < FIELD_WIDTH; j++) {
|
||||
state->game_field[i][j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
state->next_figure.type = get_random_figure();
|
||||
state->next_figure.x = 0;
|
||||
state->next_figure.y = 0;
|
||||
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; // Начинаем в состоянии FSM_Start
|
||||
}
|
||||
|
||||
void place_figure() {
|
||||
GameStateData* state = get_instance();
|
||||
Figure* f = &state->current_figure;
|
||||
const int (*shape)[4] = get_figure_shape(f->type, f->rotation);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (shape[i][j]) {
|
||||
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; // Фиксируем блок
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Проверяем и удаляем заполненные строки
|
||||
clear_completed_lines();
|
||||
|
||||
// Спавним новую фигуру
|
||||
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();
|
||||
int lines_cleared = 0;
|
||||
int write_row = FIELD_HEIGHT - 1;
|
||||
|
||||
// Проходим снизу вверх
|
||||
for (int read_row = FIELD_HEIGHT - 1; read_row >= 0; read_row--) {
|
||||
bool line_complete = true;
|
||||
for (int j = 0; j < FIELD_WIDTH; j++) {
|
||||
if (state->game_field[read_row][j] == 0) {
|
||||
line_complete = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (line_complete) {
|
||||
lines_cleared++;
|
||||
} else {
|
||||
// Копируем неполные строки вниз
|
||||
if (write_row != read_row) {
|
||||
for (int j = 0; j < FIELD_WIDTH; j++) {
|
||||
state->game_field[write_row][j] = state->game_field[read_row][j];
|
||||
}
|
||||
}
|
||||
write_row--;
|
||||
}
|
||||
}
|
||||
|
||||
// Заполняем пустые строки наверху
|
||||
for (int i = 0; i <= write_row; i++) {
|
||||
for (int j = 0; j < FIELD_WIDTH; j++) {
|
||||
state->game_field[i][j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (lines_cleared > 0) {
|
||||
// Обновляем счет в соответствии с количеством очищенных линий
|
||||
int points[] = {0, 100, 300, 700, 1500}; // 0, 1, 2, 3, 4 линии
|
||||
int score_points = 0;
|
||||
if (lines_cleared <= 4) {
|
||||
score_points = points[lines_cleared];
|
||||
} else {
|
||||
score_points = points[4]; // для > 4 линий
|
||||
}
|
||||
state->score += score_points; // УБРАЛ УМНОЖЕНИЕ НА УРОВЕНЬ
|
||||
|
||||
if (state->score > state->high_score) {
|
||||
state->high_score = state->score;
|
||||
}
|
||||
|
||||
// Увеличиваем уровень каждые 600 очков, максимум 10
|
||||
int new_level = state->score / 600 + 1;
|
||||
if (new_level > 10) new_level = 10;
|
||||
if (new_level != state->level) {
|
||||
state->level = new_level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int get_random_figure() {
|
||||
return rand() % FIGURE_COUNT;
|
||||
}
|
||||
|
||||
bool check_collision() {
|
||||
GameStateData* state = get_instance();
|
||||
Figure* f = &state->current_figure;
|
||||
const int (*shape)[4] = get_figure_shape(f->type, f->rotation);
|
||||
bool collision = false;
|
||||
|
||||
for (int i = 0; !collision && i < 4; i++) {
|
||||
for (int j = 0; !collision && j < 4; j++) {
|
||||
if (shape[i][j]) {
|
||||
int x = f->x + j;
|
||||
int y = f->y + i;
|
||||
|
||||
if (x < 0 || x >= FIELD_WIDTH || y >= FIELD_HEIGHT
|
||||
|| (y >= 0 && state->game_field[y][x] != 0)) {
|
||||
collision = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return collision;
|
||||
}
|
||||
|
||||
void fsm_transition() {
|
||||
GameStateData* state = get_instance();
|
||||
|
||||
switch (state->state) {
|
||||
case FSM_Start:
|
||||
// Ожидание начала игры - не делаем ничего, пока не будет нажата Start
|
||||
break;
|
||||
|
||||
case 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;
|
||||
}
|
||||
break;
|
||||
|
||||
case FSM_Moving:
|
||||
break;
|
||||
|
||||
case FSM_Move:
|
||||
state->current_figure.y++;
|
||||
if (check_collision()) {
|
||||
state->current_figure.y--;
|
||||
state->state = FSM_Attaching;
|
||||
} else {
|
||||
state->state = FSM_Moving;
|
||||
}
|
||||
break;
|
||||
|
||||
case FSM_Attaching:
|
||||
place_figure();
|
||||
break;
|
||||
|
||||
case FSM_GameOver:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GameStateData* get_game_state() {
|
||||
return get_instance();
|
||||
}
|
||||
|
|
@ -1,218 +0,0 @@
|
|||
#include "tetris.h"
|
||||
#include "game_logic.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
static GameInfo_t* get_game_info_instance() {
|
||||
static GameInfo_t instance = {0};
|
||||
static bool initialized = false;
|
||||
|
||||
if (!initialized) {
|
||||
instance.field = malloc(FIELD_HEIGHT * sizeof(int*));
|
||||
for (int i = 0; i < FIELD_HEIGHT; i++) {
|
||||
instance.field[i] = malloc(FIELD_WIDTH * sizeof(int));
|
||||
}
|
||||
|
||||
instance.next = malloc(4 * sizeof(int*));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
instance.next[i] = malloc(4 * sizeof(int));
|
||||
}
|
||||
|
||||
// Инициализация полей
|
||||
for (int i = 0; i < FIELD_HEIGHT; i++) {
|
||||
for (int j = 0; j < FIELD_WIDTH; j++) {
|
||||
instance.field[i][j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
instance.next[i][j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
return &instance;
|
||||
}
|
||||
|
||||
void userInput(UserAction_t action, bool hold) {
|
||||
GameStateData* state = get_game_state();
|
||||
GameInfo_t* game_info = get_game_info_instance();
|
||||
|
||||
switch (action) {
|
||||
case Terminate:
|
||||
// Освобождаем память при завершении
|
||||
if (game_info->field != NULL) {
|
||||
for (int i = 0; i < FIELD_HEIGHT; 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;
|
||||
}
|
||||
|
||||
if (game_info->next != NULL) {
|
||||
for (int i = 0; i < 4; 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;
|
||||
// Не меняем состояние, пусть остается в FSM_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 || state->state == FSM_Start) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((state->state == FSM_Moving || state->state == FSM_Move) && !state->game_over) {
|
||||
int old_x = state->current_figure.x;
|
||||
int old_y = state->current_figure.y;
|
||||
int old_rot = state->current_figure.rotation;
|
||||
|
||||
switch (action) {
|
||||
case Left:
|
||||
state->current_figure.x--;
|
||||
break;
|
||||
case Right:
|
||||
state->current_figure.x++;
|
||||
break;
|
||||
case Down:
|
||||
state->current_figure.y++;
|
||||
break;
|
||||
case Up:
|
||||
state->current_figure.rotation = (state->current_figure.rotation + 1) % 4;
|
||||
break;
|
||||
case Action:
|
||||
if (hold) {
|
||||
// Быстрый сброс вниз
|
||||
while (!check_collision()) {
|
||||
state->current_figure.y++;
|
||||
}
|
||||
state->current_figure.y--; // Вернуть на место перед столкновением
|
||||
state->state = FSM_Attaching;
|
||||
} else {
|
||||
state->current_figure.rotation = (state->current_figure.rotation + 1) % 4;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (check_collision()) {
|
||||
// Возвращаем старые значения
|
||||
state->current_figure.x = old_x;
|
||||
state->current_figure.y = old_y;
|
||||
state->current_figure.rotation = old_rot;
|
||||
} else if (action == Down) {
|
||||
// Если перемещение вниз успешно, обновляем время падения
|
||||
state->drop_time = time(NULL) * 1000;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GameInfo_t updateCurrentState() {
|
||||
GameStateData* state = get_game_state();
|
||||
GameInfo_t* game_info = get_game_info_instance();
|
||||
|
||||
if (state->state != FSM_Start && !state->game_over && !state->paused) {
|
||||
long long current_time = time(NULL) * 1000;
|
||||
|
||||
// Определяем интервал падения в зависимости от уровня
|
||||
int drop_interval = 1000 - (state->level - 1) * 50;
|
||||
if (drop_interval < 100) drop_interval = 100; // Минимальный интервал
|
||||
|
||||
if (current_time - state->drop_time >= drop_interval) {
|
||||
state->state = FSM_Move; // Переходим к автоматическому движению
|
||||
state->drop_time = current_time;
|
||||
}
|
||||
}
|
||||
|
||||
// Выполняем переходы FSM (но не в состоянии Start)
|
||||
if (state->state != FSM_Start) {
|
||||
fsm_transition();
|
||||
}
|
||||
|
||||
// Обновляем game_info.field из state->game_field
|
||||
for (int i = 0; i < FIELD_HEIGHT; i++) {
|
||||
for (int j = 0; j < FIELD_WIDTH; j++) {
|
||||
game_info->field[i][j] = state->game_field[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
// Добавляем активную фигуру на поле для отображения (если не в 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);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
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) {
|
||||
// Не перезаписываем уже зафиксированные блоки
|
||||
if (state->game_field[y][x] == 0) {
|
||||
game_info->field[y][x] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Обновляем next
|
||||
const int (*next_shape)[4];
|
||||
if (state->state == FSM_GameOver) {
|
||||
// При game_over показываем пустую фигуру
|
||||
next_shape = empty_fig();
|
||||
} else {
|
||||
next_shape = get_figure_shape(state->next_figure.type, state->next_figure.rotation);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
game_info->next[i][j] = next_shape[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
// Обновляем остальные поля
|
||||
game_info->score = state->score;
|
||||
game_info->high_score = state->high_score;
|
||||
game_info->level = state->level;
|
||||
game_info->speed = 0; // Заглушка
|
||||
game_info->pause = state->paused ? 1 : 0;
|
||||
|
||||
return *game_info;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue