Файл: Курсовая работа по дисциплине Основы программирования систем управления (наименование дисциплины).docx
Добавлен: 04.12.2023
Просмотров: 33
Скачиваний: 2
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
таймер при помощи класса Clock.
// Получаем время, прошедшее с начала отсчета, и конвертируем его
float time = clock.getElapsedTime().asSeconds();
clock.restart();
timer += time;
Затем будет идти обработка событий с окном и клавишами( вверх, влево, вправо): при нажатии на крестик в меню игры, окно закроется, и программа будет завершена; при нажатии стрелочки вверх, переменной rotate будет присвоено значение true;
при нажатии стрелочки влево переменной dx будет присвоено значение минус единицы; при нажатии стрелочки вправо переменной dx будет присвоено значение единицы;
// Обрабатываем очередь событий в цикле
Event event;
while (window.pollEvent(event))
{
if (event.type == Event::Closed) {
// тогда закрываем его
window.close();
return 0;
}
// Была нажата кнопка на клавиатуре?
if (event.type == Event::KeyPressed)
// Эта кнопка – стрелка вверх?…
if (event.key.code == Keyboard::Up) rotate = true;
// …или же стрелка влево?…
else if (event.key.code == Keyboard::Left) dx = -1;
// …ну тогда может это стрелка вправо?
else if (event.key.code == Keyboard::Right) dx = 1;
}
Дополнительно было введено ускорение падения тетрамино, уменьшением значения delay.
//Ускоряем падение тетрамино
if (Keyboard::isKeyPressed(Keyboard::Down)) delay = 0.05;
После обработки нажатий клавиш прописываем горизонтальное перемещение посредством прибавления к координатам фигуры dx.
//// Горизонтальное перемещение ////
for (int i = 0; i < 4; i++) { b[i] = a[i]; a[i].x += dx; }
При выходе за границы поля или наложении одной фигуры на другую возвращаем старые координаты.
// Вышли за пределы поля после перемещения возвращаем старые координаты
if (!check()) for (int i = 0; i < 4; i++) a[i] = b[i];
Далее реализуем вращение фигуры. Для реализации данного функционала нам понадобятся знания линейной алгебры, а именно то, что вращение спрайта вокруг заданной точки с координатами (x_0; y_0) описывается уравнениями следующего вида:
X = x_0 + (x − x_0) * cos(a) − (y − y_0 ) * sin(a);
Y = y_0 + (y − y_0) * cos(a) + (x − x_0 ) * sin(a);
Где — (x_0; y_0) это старые (исходные) координаты точки, (x; y) — это новые координаты (после вращения), а а — это угол поворота. Так как все повороты у нас идут исключительно на 90°, а из школьного курса алгебры мы знаем, что:
sin(90°) = 1
cos(90°) = 0
то, подставляя соответствующие значения синуса и косинуса, исходные уравнения упрощаются до следующего вида:
X = x_0 − (y − y_0);
Y = y_0 + (x − x_0);
Данный алгоритм будет выполняться при значении переменной rotate равной true.
//// Вращение ////
if (rotate)
{
Point p = a[1]; // задаем центр вращения
for (int i = 0; i < 4; i++)
{
int x = a[i].y - p.y; //y-y0
int y = a[i].x - p.x; //x-x0
a[i].x = p.x - x;
a[i].y = p.y + y;
}
// Вышли за пределы поля после поворота? Тогда возвращаем старые координаты
if (!check()) { for (int i = 0; i < 4; i++) a[i] = b[i]; }
}
Для движения тетрамино вниз, уже были созданы необходимые переменные. Теперь по истечении 0.3 секунды с начала отсчета времени, мы будем сдвигать все части тетрамино на 1 позицию вниз. Когда фигура занимает окончательное положение на поле, задаём цвет и тип следующей фигуре.
//// Движение тетрамино вниз////
if (timer > delay)
{
for (int i = 0; i < 4; i++)
{
b[i] = a[i];
a[i].y += 1;
}
if (!check())
{
for (int i = 0; i < 4; i++) field[b[i].y][b[i].x] = colorNum;
colorNum = 1 + rand() % 7;
n = rand() % 7;
for (int i = 0; i < 4; i++)
{
a[i].x = figures[n][i] % 2;
a[i].y = figures[n][i] / 2;
}
}
timer = 0;
}
По правилам тетриса заполненная линия должна удаляться, для этого реализован цикл, который будет проходить по полю снизу вверх и проверять заполнено ли поле.
//----ПРОВЕРКА ЛИНИИ----//
int k = M - 1;
for (int i = M - 1; i > 0; i--)
{
int count = 0;
for (int j = 0; j < N; j++)
{
if (field[i][j]) count++;
field[k][j] = field[i][j];
}
if (count < N) k--;
}
Необходимо было задать первоначальное положение тетрамино корректно, для этого прописан блок if(beginGame).
// Первое появление тетрамино на поле
if (beginGame)
{
beginGame = false;
n = rand() % 7;
for (int i = 0; i < 4; i++)
{
a[i].x = figures[n][i] % 2;
a[i].y = figures[n][i] / 2;
}
}
dx = 0; rotate = 0; delay = 0.3;
Код, расположенный внутри блока if(beginGame), вызывается только один раз при старте приложения. Благодаря ему задается первоначальный тип тетрамино.
После обработки событий произведена отрисовка самого поля и фигур уже присутствующих на нём.
//----ОТРИСОВКА----//
// Задаем цвет фона - белый
window.clear(Color::White);
window.draw(sprite_background);
for (int i = 0; i < M; i++)
for (int j = 0; j < N; j++)
{
if (field[i][j] == 0) continue;
sprite.setTextureRect(IntRect(field[i][j] * 18, 0, 18, 18));
sprite.setPosition(j * 18, i * 18);
sprite.move(28, 31); // смещение
window.draw(sprite);
}
Затем идёт отрисовка движущейся фигуры.
for (int i = 0; i < 4; i++)
{
// Разукрашиваем тетрамино
sprite.setTextureRect(IntRect(colorNum * 18, 0, 18, 18));
// Устанавливаем позицию каждого кусочка тетрамино
sprite.setPosition(a[i].x * 18, a[i].y * 18);
sprite.move(28, 31); // смещение
// Отрисовка спрайта
window.draw(sprite);
}
// Отрисовка фрейма
window.draw(sprite_frame);
// Отрисовка окна
window.display();
}
Прежде всего присваиваем переменной IsRun true и заполняем массив field нулями для подготовки к новой игре, если таковая будет.
IsRun = true;
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
field[i][j] = 0;
}
}
Затем создаём окно window2, размер меню которого 320 на 480 пикселей и в заголовке задано название игры– Tetris. Действия связанные с этим меню описываются в цикле, условием которого будет window2.isOpen() – открыто ли окно. Алгоритм этого цикла аналогичен циклу связанного с стартовым окном за исключением того, что вырисовываться будет спрайт sprite_game_over.
RenderWindow window2(VideoMode(320, 480), "Tetris");
while (window2.isOpen())
{
Event event;
while (window2.pollEvent(event))
{
// Пользователь нажал на «крестик» и хочет закрыть окно?
if (event.type == Event::Closed)
{
window2.close();
return 0;
}
}
window2.clear(Color::White);
window2.draw(sprite_game_over);
window2.display();
if (Keyboard::isKeyPressed(Keyboard::Space))
{
break;
}
}
}
}
После отработки этого цикла программа либо будет завершена, либо вернётся к основному алгоритму.
В результате выполнения курсовой работы по дисциплине «Основы программирования систем управления» была разработана игра Тетрис. Программа написана в среде разработки Microsoft Visual Studio Enterprise 2022 на языке С++ с использованием стандартной библиотеки и библиотеки SFML/Graphics.hpp.
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ И ЛИТЕРАТУРЫ
Приложение А
Листинг исходного программного кода
#include
#include
#include
using namespace sf;
const int M = 20;
const int N = 10;
int field[M][N] = { 0 }; // игровое поле
int figures[7][4] = // Массив фигурок-тетрамино
{
1,3,5,7, // I
2,4,5,7, // Z
3,5,4,6, // S
3,5,4,7, // T
2,3,5,7, // L
3,5,7,6, // J
2,3,4,5, // O
};
struct Point
{
int x, y;
}a[4], b[4];
// Проверка на выход за границы игрового поля
bool check()
{
for (int i = 0; i < 4; i++)
if (a[i].x < 0 || a[i].x >= N || a[i].y >= M) return 0;
else if (field[a[i].y][a[i].x]) return 0;
return 1;
};
bool endGame(RenderWindow* window)
{
for (int i = 0; i < N; i++)
{
if (field[2][i])
{
window->close();
return false;
}
}
}
int main()
{
srand(time(0));
// Создание и загрузка текстуры
Texture texture,
texture_background,
texture_frame,
texture_start,
texture_game_over;
texture.loadFromFile("tiles.png");
texture_background.loadFromFile("background.png");
texture_frame.loadFromFile("frame.png");
texture_start.loadFromFile("start.png");
texture_game_over.loadFromFile("game_over.png");
// Создание спрайта
Sprite sprite(texture),
sprite_background(texture_background),
sprite_frame(texture_frame),
sprite_start(texture_start),
sprite_game_over(texture_game_over);
sprite.setTextureRect(IntRect(0, 0, 18, 18));
// Переменные для горизонтального перемещения и вращения
int dx = 0; bool rotate = 0;
int colorNum = 1;
bool beginGame = true;
int n = rand() % 7;
// Переменные для таймера и задержки
float timer = 0, delay = 0.3;
Clock clock;
bool IsRun = true;
RenderWindow window0(VideoMode(320, 480), "Tetris");
while (window0.isOpen())
{
Event event;
while (window0.pollEvent(event))
{
// Пользователь нажал на «крестик»
if (event.type == Event::Closed)
{
window0.close();
return 0;
}
}
window0.clear(Color::White);
window0.draw(sprite_start);
window0.display();
if (Keyboard::isKeyPressed(Keyboard::Space))
{
window0.close();
break;
}
}
while (true) {
RenderWindow window(VideoMode(320, 480), "Tetris");
// Цикл игры. Выполняется, пока открыто окно
while (window.isOpen() && IsRun)
{
IsRun = endGame(&window);
if (!IsRun)
{
break;
}
// Получаем время, прошедшее с начала отсчета, и конвертируем его в
float time = clock.getElapsedTime().asSeconds();
clock.restart();
timer += time;
// Обрабатываем очередь событий в цикле
Event event;
while (window.pollEvent(event))
{
if (event.type == Event::Closed) {
// тогда закрываем его
window.close();
return 0;
}
// Была нажата кнопка на клавиатуре?
if (event.type == Event::KeyPressed)
// Эта кнопка – стрелка вверх?…
if (event.key.code == Keyboard::Up) rotate = true;
// …или же стрелка влево?…
else if (event.key.code == Keyboard::Left) dx = -1;
// …ну тогда может это стрелка вправо?
else if (event.key.code == Keyboard::Right) dx = 1;
}
//Ускоряем падение тетрамино
if (Keyboard::isKeyPressed(Keyboard::Down)) delay = 0.05;
//// Горизонтальное перемещение ////
for (int i = 0; i < 4; i++) { b[i] = a[i]; a[i].x += dx; }
// Вышли за пределы поля после перемещения возвращаем старые координаты
if (!check()) for (int i = 0; i < 4; i++) a[i] = b[i];
//// Вращение ////
if (rotate)
{
Point p = a[1]; // задаем центр вращения
for (int i = 0; i < 4; i++)
{
int x = a[i].y - p.y; //y-y0
int y = a[i].x - p.x; //x-x0
a[i].x = p.x - x;
a[i].y = p.y + y;
}
// Вышли за пределы поля после поворота? Тогда возвращаем старые координаты
if (!check()) { for (int i = 0; i < 4; i++) a[i] = b[i]; }
}
//// Движение тетрамино вниз////
if (timer > delay)
{
for (int i = 0; i < 4; i++)
{
b[i] = a[i];
a[i].y += 1;
}
if (!check())
{
for (int i = 0; i < 4; i++) field[b[i].y][b[i].x] =colorNum;
colorNum = 1 + rand() % 7;
n = rand() % 7;
for (int i = 0; i < 4; i++)
{
a[i].x = figures[n][i] % 2;
a[i].y = figures[n][i] / 2;
}
}
timer = 0;
}
//----ПРОВЕРКА ЛИНИИ----//
int k = M - 1;
for (int i = M - 1; i > 0; i--)
{
int count = 0;
for (int j = 0; j < N; j++)
{
if (field[i][j]) count++;
field[k][j] = field[i][j];
}
if (count < N) k--;
}
// Первое появление тетрамино на поле
if (beginGame)
{
beginGame = false;
n = rand() % 7;
for (int i = 0; i < 4; i++)
{
a[i].x = figures[n][i] % 2;
a[i].y = figures[n][i] / 2;
}
}
dx = 0; rotate = 0; delay = 0.3;
//----ОТРИСОВКА----//
// Задаем цвет фона - белый
window.clear(Color::White);
window.draw(sprite_background);
for (int i = 0; i < M; i++)
for (int j = 0; j < N; j++)
{
if (field[i][j] == 0) continue;
sprite.setTextureRect(IntRect(field[i][j] * 18, 0, 18, 18));
sprite.setPosition(j * 18, i * 18);
sprite.move(28, 31); // смещение
window.draw(sprite);
}
for (int i = 0; i < 4; i++)
{
// Разукрашиваем тетрамино
sprite.setTextureRect(IntRect(colorNum * 18, 0, 18, 18));
// Устанавливаем позицию каждого кусочка тетрамино
sprite.setPosition(a[i].x * 18, a[i].y * 18);
sprite.move(28, 31); // смещение
// Отрисовка спрайта
window.draw(sprite);
}
// Отрисовка фрейма
window.draw(sprite_frame);
// Отрисовка окна
window.display();
}
IsRun = true;
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
field[i][j] = 0;
}
}
RenderWindow window2(VideoMode(320, 480), "Tetris");
while (window2.isOpen())
{
Event event;
while (window2.pollEvent(event))
{
// Пользователь нажал на «крестик» и хочет закрыть окно?
if (event.type == Event::Closed)
{
window2.close();
return 0;
}
}
window2.clear(Color::White);
window2.draw(sprite_game_over);
window2.display();
if (Keyboard::isKeyPressed(Keyboard::Space))
{
break;
}
}
}
}
// Получаем время, прошедшее с начала отсчета, и конвертируем его
float time = clock.getElapsedTime().asSeconds();
clock.restart();
timer += time;
Затем будет идти обработка событий с окном и клавишами( вверх, влево, вправо): при нажатии на крестик в меню игры, окно закроется, и программа будет завершена; при нажатии стрелочки вверх, переменной rotate будет присвоено значение true;
при нажатии стрелочки влево переменной dx будет присвоено значение минус единицы; при нажатии стрелочки вправо переменной dx будет присвоено значение единицы;
// Обрабатываем очередь событий в цикле
Event event;
while (window.pollEvent(event))
{
if (event.type == Event::Closed) {
// тогда закрываем его
window.close();
return 0;
}
// Была нажата кнопка на клавиатуре?
if (event.type == Event::KeyPressed)
// Эта кнопка – стрелка вверх?…
if (event.key.code == Keyboard::Up) rotate = true;
// …или же стрелка влево?…
else if (event.key.code == Keyboard::Left) dx = -1;
// …ну тогда может это стрелка вправо?
else if (event.key.code == Keyboard::Right) dx = 1;
}
Дополнительно было введено ускорение падения тетрамино, уменьшением значения delay.
//Ускоряем падение тетрамино
if (Keyboard::isKeyPressed(Keyboard::Down)) delay = 0.05;
После обработки нажатий клавиш прописываем горизонтальное перемещение посредством прибавления к координатам фигуры dx.
//// Горизонтальное перемещение ////
for (int i = 0; i < 4; i++) { b[i] = a[i]; a[i].x += dx; }
При выходе за границы поля или наложении одной фигуры на другую возвращаем старые координаты.
// Вышли за пределы поля после перемещения возвращаем старые координаты
if (!check()) for (int i = 0; i < 4; i++) a[i] = b[i];
Далее реализуем вращение фигуры. Для реализации данного функционала нам понадобятся знания линейной алгебры, а именно то, что вращение спрайта вокруг заданной точки с координатами (x_0; y_0) описывается уравнениями следующего вида:
X = x_0 + (x − x_0) * cos(a) − (y − y_0 ) * sin(a);
Y = y_0 + (y − y_0) * cos(a) + (x − x_0 ) * sin(a);
Где — (x_0; y_0) это старые (исходные) координаты точки, (x; y) — это новые координаты (после вращения), а а — это угол поворота. Так как все повороты у нас идут исключительно на 90°, а из школьного курса алгебры мы знаем, что:
sin(90°) = 1
cos(90°) = 0
то, подставляя соответствующие значения синуса и косинуса, исходные уравнения упрощаются до следующего вида:
X = x_0 − (y − y_0);
Y = y_0 + (x − x_0);
Данный алгоритм будет выполняться при значении переменной rotate равной true.
//// Вращение ////
if (rotate)
{
Point p = a[1]; // задаем центр вращения
for (int i = 0; i < 4; i++)
{
int x = a[i].y - p.y; //y-y0
int y = a[i].x - p.x; //x-x0
a[i].x = p.x - x;
a[i].y = p.y + y;
}
// Вышли за пределы поля после поворота? Тогда возвращаем старые координаты
if (!check()) { for (int i = 0; i < 4; i++) a[i] = b[i]; }
}
Для движения тетрамино вниз, уже были созданы необходимые переменные. Теперь по истечении 0.3 секунды с начала отсчета времени, мы будем сдвигать все части тетрамино на 1 позицию вниз. Когда фигура занимает окончательное положение на поле, задаём цвет и тип следующей фигуре.
//// Движение тетрамино вниз////
if (timer > delay)
{
for (int i = 0; i < 4; i++)
{
b[i] = a[i];
a[i].y += 1;
}
if (!check())
{
for (int i = 0; i < 4; i++) field[b[i].y][b[i].x] = colorNum;
colorNum = 1 + rand() % 7;
n = rand() % 7;
for (int i = 0; i < 4; i++)
{
a[i].x = figures[n][i] % 2;
a[i].y = figures[n][i] / 2;
}
}
timer = 0;
}
По правилам тетриса заполненная линия должна удаляться, для этого реализован цикл, который будет проходить по полю снизу вверх и проверять заполнено ли поле.
//----ПРОВЕРКА ЛИНИИ----//
int k = M - 1;
for (int i = M - 1; i > 0; i--)
{
int count = 0;
for (int j = 0; j < N; j++)
{
if (field[i][j]) count++;
field[k][j] = field[i][j];
}
if (count < N) k--;
}
Необходимо было задать первоначальное положение тетрамино корректно, для этого прописан блок if(beginGame).
// Первое появление тетрамино на поле
if (beginGame)
{
beginGame = false;
n = rand() % 7;
for (int i = 0; i < 4; i++)
{
a[i].x = figures[n][i] % 2;
a[i].y = figures[n][i] / 2;
}
}
dx = 0; rotate = 0; delay = 0.3;
Код, расположенный внутри блока if(beginGame), вызывается только один раз при старте приложения. Благодаря ему задается первоначальный тип тетрамино.
После обработки событий произведена отрисовка самого поля и фигур уже присутствующих на нём.
//----ОТРИСОВКА----//
// Задаем цвет фона - белый
window.clear(Color::White);
window.draw(sprite_background);
for (int i = 0; i < M; i++)
for (int j = 0; j < N; j++)
{
if (field[i][j] == 0) continue;
sprite.setTextureRect(IntRect(field[i][j] * 18, 0, 18, 18));
sprite.setPosition(j * 18, i * 18);
sprite.move(28, 31); // смещение
window.draw(sprite);
}
Затем идёт отрисовка движущейся фигуры.
for (int i = 0; i < 4; i++)
{
// Разукрашиваем тетрамино
sprite.setTextureRect(IntRect(colorNum * 18, 0, 18, 18));
// Устанавливаем позицию каждого кусочка тетрамино
sprite.setPosition(a[i].x * 18, a[i].y * 18);
sprite.move(28, 31); // смещение
// Отрисовка спрайта
window.draw(sprite);
}
// Отрисовка фрейма
window.draw(sprite_frame);
// Отрисовка окна
window.display();
}
-
Меню окончания игры
Прежде всего присваиваем переменной IsRun true и заполняем массив field нулями для подготовки к новой игре, если таковая будет.
IsRun = true;
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
field[i][j] = 0;
}
}
Затем создаём окно window2, размер меню которого 320 на 480 пикселей и в заголовке задано название игры– Tetris. Действия связанные с этим меню описываются в цикле, условием которого будет window2.isOpen() – открыто ли окно. Алгоритм этого цикла аналогичен циклу связанного с стартовым окном за исключением того, что вырисовываться будет спрайт sprite_game_over.
RenderWindow window2(VideoMode(320, 480), "Tetris");
while (window2.isOpen())
{
Event event;
while (window2.pollEvent(event))
{
// Пользователь нажал на «крестик» и хочет закрыть окно?
if (event.type == Event::Closed)
{
window2.close();
return 0;
}
}
window2.clear(Color::White);
window2.draw(sprite_game_over);
window2.display();
if (Keyboard::isKeyPressed(Keyboard::Space))
{
break;
}
}
}
}
После отработки этого цикла программа либо будет завершена, либо вернётся к основному алгоритму.
ЗАКЛЮЧЕНИЕ
В результате выполнения курсовой работы по дисциплине «Основы программирования систем управления» была разработана игра Тетрис. Программа написана в среде разработки Microsoft Visual Studio Enterprise 2022 на языке С++ с использованием стандартной библиотеки и библиотеки SFML/Graphics.hpp.
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ И ЛИТЕРАТУРЫ
-
Википедия [сайт}. - Тетрис. - Режим доступа: общий.- Дата обновления: 06.05.2022.- URL: https://ru.wikipedia.org/wiki/Тетрис (Дата обращения: 12.05.2022). -
Довбуш, Галина Visual C++ на примерах / Галина Довбуш , Анатолий Хомоненко. - М.: БХВ-Петербург, 2012. - 528 c. -
Пахомов, Борис C/C++ и MS Visual C++ 2012 для начинающих / Борис Пахомов. - Москва: СИНТЕГ, 2015. - 518 c. -
Роберт, С. Сикорд Безопасное программирование на C и C++ / Роберт С. Сикорд. - Москва: РГГУ, 2014. - 496 c. -
Microsoft [сайт].- Reading Input Buffer Events.- Режим доступа: общий.- Дата обновления: 30.10.2022.- URL: https://docs.microsoft.com/en-us/windows/console/reading-input-buffer-events (Дата обращения: 04.05.2022). -
TIME [сайт].- The 50 Best Video Games of All Time.- Режим доступа: общий.- Дата обновления: 23.08.2016.- URL: https://time.com/4458554/best-video-games-all-time/ (Дата обращения: 11.05.2022). -
Microsoft [сайт].- Virtual-Key Codes.- Режим доступа: общий.- Дата обновления: 20.01.2022.- URL: https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes (Дата обращения: 04.05.2022).
Приложение А
Листинг исходного программного кода
#include
#include
#include
using namespace sf;
const int M = 20;
const int N = 10;
int field[M][N] = { 0 }; // игровое поле
int figures[7][4] = // Массив фигурок-тетрамино
{
1,3,5,7, // I
2,4,5,7, // Z
3,5,4,6, // S
3,5,4,7, // T
2,3,5,7, // L
3,5,7,6, // J
2,3,4,5, // O
};
struct Point
{
int x, y;
}a[4], b[4];
// Проверка на выход за границы игрового поля
bool check()
{
for (int i = 0; i < 4; i++)
if (a[i].x < 0 || a[i].x >= N || a[i].y >= M) return 0;
else if (field[a[i].y][a[i].x]) return 0;
return 1;
};
bool endGame(RenderWindow* window)
{
for (int i = 0; i < N; i++)
{
if (field[2][i])
{
window->close();
return false;
}
}
}
int main()
{
srand(time(0));
// Создание и загрузка текстуры
Texture texture,
texture_background,
texture_frame,
texture_start,
texture_game_over;
texture.loadFromFile("tiles.png");
texture_background.loadFromFile("background.png");
texture_frame.loadFromFile("frame.png");
texture_start.loadFromFile("start.png");
texture_game_over.loadFromFile("game_over.png");
// Создание спрайта
Sprite sprite(texture),
sprite_background(texture_background),
sprite_frame(texture_frame),
sprite_start(texture_start),
sprite_game_over(texture_game_over);
sprite.setTextureRect(IntRect(0, 0, 18, 18));
// Переменные для горизонтального перемещения и вращения
int dx = 0; bool rotate = 0;
int colorNum = 1;
bool beginGame = true;
int n = rand() % 7;
// Переменные для таймера и задержки
float timer = 0, delay = 0.3;
Clock clock;
bool IsRun = true;
RenderWindow window0(VideoMode(320, 480), "Tetris");
while (window0.isOpen())
{
Event event;
while (window0.pollEvent(event))
{
// Пользователь нажал на «крестик»
if (event.type == Event::Closed)
{
window0.close();
return 0;
}
}
window0.clear(Color::White);
window0.draw(sprite_start);
window0.display();
if (Keyboard::isKeyPressed(Keyboard::Space))
{
window0.close();
break;
}
}
while (true) {
RenderWindow window(VideoMode(320, 480), "Tetris");
// Цикл игры. Выполняется, пока открыто окно
while (window.isOpen() && IsRun)
{
IsRun = endGame(&window);
if (!IsRun)
{
break;
}
// Получаем время, прошедшее с начала отсчета, и конвертируем его в
float time = clock.getElapsedTime().asSeconds();
clock.restart();
timer += time;
// Обрабатываем очередь событий в цикле
Event event;
while (window.pollEvent(event))
{
if (event.type == Event::Closed) {
// тогда закрываем его
window.close();
return 0;
}
// Была нажата кнопка на клавиатуре?
if (event.type == Event::KeyPressed)
// Эта кнопка – стрелка вверх?…
if (event.key.code == Keyboard::Up) rotate = true;
// …или же стрелка влево?…
else if (event.key.code == Keyboard::Left) dx = -1;
// …ну тогда может это стрелка вправо?
else if (event.key.code == Keyboard::Right) dx = 1;
}
//Ускоряем падение тетрамино
if (Keyboard::isKeyPressed(Keyboard::Down)) delay = 0.05;
//// Горизонтальное перемещение ////
for (int i = 0; i < 4; i++) { b[i] = a[i]; a[i].x += dx; }
// Вышли за пределы поля после перемещения возвращаем старые координаты
if (!check()) for (int i = 0; i < 4; i++) a[i] = b[i];
//// Вращение ////
if (rotate)
{
Point p = a[1]; // задаем центр вращения
for (int i = 0; i < 4; i++)
{
int x = a[i].y - p.y; //y-y0
int y = a[i].x - p.x; //x-x0
a[i].x = p.x - x;
a[i].y = p.y + y;
}
// Вышли за пределы поля после поворота? Тогда возвращаем старые координаты
if (!check()) { for (int i = 0; i < 4; i++) a[i] = b[i]; }
}
//// Движение тетрамино вниз////
if (timer > delay)
{
for (int i = 0; i < 4; i++)
{
b[i] = a[i];
a[i].y += 1;
}
if (!check())
{
for (int i = 0; i < 4; i++) field[b[i].y][b[i].x] =colorNum;
colorNum = 1 + rand() % 7;
n = rand() % 7;
for (int i = 0; i < 4; i++)
{
a[i].x = figures[n][i] % 2;
a[i].y = figures[n][i] / 2;
}
}
timer = 0;
}
//----ПРОВЕРКА ЛИНИИ----//
int k = M - 1;
for (int i = M - 1; i > 0; i--)
{
int count = 0;
for (int j = 0; j < N; j++)
{
if (field[i][j]) count++;
field[k][j] = field[i][j];
}
if (count < N) k--;
}
// Первое появление тетрамино на поле
if (beginGame)
{
beginGame = false;
n = rand() % 7;
for (int i = 0; i < 4; i++)
{
a[i].x = figures[n][i] % 2;
a[i].y = figures[n][i] / 2;
}
}
dx = 0; rotate = 0; delay = 0.3;
//----ОТРИСОВКА----//
// Задаем цвет фона - белый
window.clear(Color::White);
window.draw(sprite_background);
for (int i = 0; i < M; i++)
for (int j = 0; j < N; j++)
{
if (field[i][j] == 0) continue;
sprite.setTextureRect(IntRect(field[i][j] * 18, 0, 18, 18));
sprite.setPosition(j * 18, i * 18);
sprite.move(28, 31); // смещение
window.draw(sprite);
}
for (int i = 0; i < 4; i++)
{
// Разукрашиваем тетрамино
sprite.setTextureRect(IntRect(colorNum * 18, 0, 18, 18));
// Устанавливаем позицию каждого кусочка тетрамино
sprite.setPosition(a[i].x * 18, a[i].y * 18);
sprite.move(28, 31); // смещение
// Отрисовка спрайта
window.draw(sprite);
}
// Отрисовка фрейма
window.draw(sprite_frame);
// Отрисовка окна
window.display();
}
IsRun = true;
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
field[i][j] = 0;
}
}
RenderWindow window2(VideoMode(320, 480), "Tetris");
while (window2.isOpen())
{
Event event;
while (window2.pollEvent(event))
{
// Пользователь нажал на «крестик» и хочет закрыть окно?
if (event.type == Event::Closed)
{
window2.close();
return 0;
}
}
window2.clear(Color::White);
window2.draw(sprite_game_over);
window2.display();
if (Keyboard::isKeyPressed(Keyboard::Space))
{
break;
}
}
}
}