#include #include // Пока оно true - будем крутиться в игре, // если станет false - выходим. static bool run = false; // Если true - значит проиграли и надо нарисовать плашку Game Over static bool gameOver; // Если true - у нас пауза, ничего не происходит, ждем нажатия кнопок static bool pause; //Ширина и высота терминального окна static int termWidth; static int termHeight; // Координаты головы static int playerX; static int playerY; // Координаты еды static int fruitX; static int fruitY; // Смещения по осям - куда бежать // 1 или -1 - бежим вдоль оси. 0 - не бежим static int dx; static int dy; // Очки static int score; // Начало и конец питона в массиве static int pythonStart; static int pythonEnd; // Максимальный размер массива, чтобы можно было теоретически покрыть весь экран static int maxPythonSize; // Предварительное описание, реализация позже будет. void DropFruit(); // Структурка для хранения координат в массиве. struct coord { int x; int y; }; // Массив для координат тела - определение static coord * python; // Тут мы инициализируем все что надо void InitGame() { // Инициализируем ncurses и выставляем ей разное initscr(); raw(); cbreak(); noecho(); keypad(stdscr, true); // Таймаут ввода, он же скорость игры timeout(200); // Получаем размер терминального окна getmaxyx(stdscr, termHeight, termWidth); // Убираем курсор curs_set(0); //Рисуем рамку box(stdscr, 0, 0); //Инициализируем разные переменные run = true; gameOver = false; pause = false; // Голову в центр экрана playerX = termWidth / 2; playerY = termHeight / 2; // Едем вправо dx = 1; dy = 0; // Очков пока ноль score = 0; // Высчитываем максимальный размер питона, исходя из размера экрана // (ну вдруг кто-то умудрится) maxPythonSize = (termWidth - 2) * (termHeight - 2); // Инициализируем массив под координаты частей тела python = new coord[maxPythonSize](); // Задаем начальные координаты python[0].x = playerX; python[0].y = playerY; // и указатели на хвост и голову pythonStart = 0; pythonEnd = 0; // Бросаем первую еду DropFruit(); } // Тут завершается ncurses void EndGame() { endwin(); } // Процедура, ловящая ввод и обрабатывающая его void Input() { // Получаем нажатую клавишу int c = getch(); // в зависимости от нажатой клавиши правим смещения switch (c) { // Если нажали q - ставим run в false, потому как надо выходить case 'q': run = false; break; case ' ': pause = !pause; break; case KEY_UP: // На каждый чих надо проверить, не пытается ли игрок поехать в противоположную сторону. // Если так - нафиг. Ничего не делаем. if (dy == 1) break; dx = 0; dy = -1; break; case KEY_DOWN: if (dy == -1) break; dx = 0; dy = 1; break; case KEY_LEFT: if (dx == 1) break; dx = -1; dy = 0; break; case KEY_RIGHT: if (dx == -1) break; dx = 1; dy = 0; } } // Микроскопическая процедурка, печатающая очки в углу void PrintScore() { mvprintw(0, termWidth - 20, "Score: %5d", score); } // Тут мы двигаем голову и проверяем все что можно void Logic() { // Двигаем по X, просто прибавляя к координатам смещение playerX += dx; // Проверяем на выход за рамку if (playerX > termWidth - 2 || playerX < 1) { // Если вылезли - ставим флаг GameOver и run в false, чтобы выйти gameOver = true; run = false; return; } playerY += dy; if (playerY > termHeight - 2 || playerY < 1) { gameOver = true; run = false; return; } // Тут мы проходим по куску массива с телом между началом и концом // чтобы выяснить, не куснули ли сами себя. int i = pythonStart; while (i <= pythonEnd) { // Если координаты головы совпадают с координатами из массива - Game over if (playerX == python[i].x && playerY == python[i].y) { gameOver = true; run = false; return; } i++; } // Проверяем, не куснули ли мы еду if (playerX == fruitX && playerY == fruitY) { // Если куснули - выкидываем новую DropFruit(); // Добавляем очков score++; // Сдвигаем хвост pythonEnd++; // Если хвост дошел до конца массива - переставляем его на начало if (pythonEnd == maxPythonSize) pythonEnd = 0; // Выводим новые очки в угол PrintScore(); } // Двигаем питона // Стираем хвост mvprintw(python[pythonEnd].y, python[pythonEnd].x, " "); // Двигаем указатель головы назад по массиву pythonStart--; // Не забывая его переставить, если он дошел до нуля if (pythonStart < 0) pythonStart = maxPythonSize - 1; // Тоже и с указателем хвоста pythonEnd--; if (pythonEnd < 0) pythonEnd = maxPythonSize - 1; // Записываем новое положение головы по указателю python[pythonStart].x = playerX; python[pythonStart].y = playerY; // Рисуем по новым координатам голову mvprintw(playerY, playerX, "@"); } // Жуткая процедура рисования окошка с Game Over void DrawGameOver() { int winWidth = termWidth / 2 + 10; int winHeight = 7; int winX = (termWidth - winWidth) / 2; int winY = (termHeight - winHeight) / 2; WINDOW * gameOverWin = newwin(winHeight, winWidth, winY, winX); box(gameOverWin, 0, 0); std::string str1 = "GAME OVER!"; std::string str2 = "Score: " + std::to_string(score); mvwprintw(gameOverWin, 2, (winWidth - (int)str1.length()) / 2, str1.c_str()); mvwprintw(gameOverWin, 4, (winWidth - (int)str2.length()) / 2, str2.c_str()); wrefresh(gameOverWin); notimeout(gameOverWin, TRUE); wgetch(gameOverWin); } // Здесь мы крутимся, пока игра идет void GameLoop() { while (run) { // Обрабатываем ввод Input(); if (!pause) { // Обрабатываем логику Logic(); } } // Сюда мы выйдем, если игра так или иначе кончится // Если Game over - рисуем плашку с очками if (gameOver) DrawGameOver(); } // Выбрасываем новую еду void DropFruit() { // Новые координаты в переменные fruitX = (rand() % (termWidth - 2)) + 1; fruitY = (rand() % (termHeight - 2)) + 1; // и нарисовать mvprintw(fruitY, fruitX, "#"); } // Главная функция - просто вызывает все предыдущие последовательно int main(int argc, const char * argv[]) { InitGame(); getch(); PrintScore(); GameLoop(); EndGame(); return 0; }