СОЗДАНИЕ КОНСОЛЬНОЙ ИГРЫ ЗМЕЙКА С ПОМОЩЬЮ СРЕДЫ РАЗРАБОТКИ VISUAL STUDIO Текст научной статьи по специальности «Компьютерные и информационные науки»
Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Журавлев Александр Александрович
Роль компьютерных игр в жизни современного человека достаточна велика. Они приносят большой заработок разработчикам, и приятное времяпрепровождение тем, кто в них играет. В данной статье представлен процесс создания игры «Змейка» с помощью консольного приложения среды разработки Visual Studio. Для игры необходимо создание структуры Position (позиция) для фиксации местоположения того или иного объекта. Игра включает в себя следующие объекты: змейка, препятствие и еда. После столкновения змейки с собственным хвостом, с краем игрового поля или препятствием игра завершается и пользователя (игрок) получает информацию о набранных очках. Работу программы можно считать корректным.
i Надоели баннеры? Вы всегда можете отключить рекламу.
Похожие темы научных работ по компьютерным и информационным наукам , автор научной работы — Журавлев Александр Александрович
СОЗДАНИЕ ТЕЛЕГРАМ-БОТА С ПОМОЩЬЮ СРЕДЫ РАЗРАБОТКИ VISUAL STUDIO
Создание имитационной модели одноканального передатчика кадров с буфером ограниченной емкости с помощью Visual Studio
Разработка компьютерной игры как консольного приложения на языке с++
Знакомство с языком с#
Библиотека LibGDX на языке программирования Java
i Не можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.
CREATION A CONSOLE SNAKE GAME USING THE VISUAL STUDIO DEVELOPMENT ENVIRONMENT
The role of computer games in the life of a modern person is quite large. They bring a lot of money to developers, and a pleasant pastime for those who play them. This article presents the process of creation a Snake game using the Visual Studio development environment console application. For the game, is it necessary to create a Position structure to fix the location of the object. The game includes the following objects: snake, obstacle and food. After the snake collides with its own tail, the edge of the playing field or an obstacle, the game ends and the user (player) receives information about the points scored. The program can be considered correct.
Текст научной работы на тему «СОЗДАНИЕ КОНСОЛЬНОЙ ИГРЫ ЗМЕЙКА С ПОМОЩЬЮ СРЕДЫ РАЗРАБОТКИ VISUAL STUDIO»
Научно-образовательный журнал для студентов и преподавателей «StudNet» №12/2020
СОЗДАНИЕ КОНСОЛЬНОЙ ИГРЫ ЗМЕЙКА С ПОМОЩЬЮ СРЕДЫ
РАЗРАБОТКИ VISUAL STUDIO
CREATION A CONSOLE SNAKE GAME USING THE VISUAL STUDIO
Журавлев Александр Александрович, студент, Уральский федеральный университет им. Б. Н. Ельцина, ИРИТ-РтФ, г. Екатеринбург
Zhuravlev А.А. SanyaProgrammer2503@gmail.com
Роль компьютерных игр в жизни современного человека достаточна велика. Они приносят большой заработок разработчикам, и приятное времяпрепровождение тем, кто в них играет. В данной статье представлен
процесс создания игры «Змейка» с помощью консольного приложения среды разработки Visual Studio. Для игры необходимо создание структуры Position (позиция) для фиксации местоположения того или иного объекта. Игра включает в себя следующие объекты: змейка, препятствие и еда. После столкновения змейки с собственным хвостом, с краем игрового поля или препятствием игра завершается и пользователя (игрок) получает информацию о набранных очках. Работу программы можно считать корректным.
The role of computer games in the life of a modern person is quite large. They bring a lot of money to developers, and a pleasant pastime for those who play them. This article presents the process of creation a Snake game using the Visual Studio development environment console application. For the game, is it necessary to create a Position structure to fix the location of the object. The game includes the following objects: snake, obstacle and food. After the snake collides with its own tail, the edge of the playing field or an obstacle, the game ends and the user (player) receives information about the points scored. The program can be considered correct.
Ключевые слова: создание, игра Змейка, среда разработки, Visual Studio.
Keywords: creation, Snake game, development environment, Visual Studio.
Роль компьютерных игр в жизни современного человека достаточна велика. Они приносят большой заработок разработчикам, и приятное времяпрепровождение тем, кто в них играет [1].
А как создаются игры? Для того чтобы ответить на этот вопрос необходима разработка собственной игры.
Объектом исследования данной статьи является игра «Змейка».
Цель статьи — с помощью консольного приложения среды разработки Visual Studio разработать игру «Змейка».
Материалом исследования является консоль среды разработки Visual Studio.
В статье используется эмпирический метод исследования, поскольку основной источник результатов — моделирование.
Игрок управляет змейкой, которая ползает по плоскости, собирая еду и избегая столкновения с собственным хвостом, краями игрового поля и препятствиями. Каждый раз, когда змея съедает кусок пищи, она становиться длиннее, что постепенно усложняет игру. Игрок управляет направлением движения змеи, а хвост змеи движется следом [2].
Для создания выше описанной игры используем консольное приложение среды разработки Visual Studio.
Для игры необходимо создать структуру Position (Позиция), который будет фиксировать положение того или иного объекта на консоли. Также в игре необходимо использовать змейку, еду и препятствия. Для того чтобы игра завершилась необходимо выполнение следующих условий: змейка столкнулась с собственным хвостом, краями игрового поля или препятствиями.
Основные моменты программы представлены ниже.
//Создание структуры «Позиция» для отображения положения объекта на конслоли
public struct Position
public int row; public int column;
public Position(int row, int column)
this.row = row; this.column = column;
//Создание массива направлений (вверх, вниз, лево, право)
Position[] directions = new Position[]
new Position(0, 1), new Position(0, -1), new Position(1, 0), new Position(-1, 0)
//Создание списка для хранения положений препятствий
new Position(10, 10), new Position(8, 16), new Position(5, 5), new Position(17, 17), new Position(6, 12), new Position(3, 9), new Position(7, 10)
//Изменение направление головы змейки в зависимости от направления движения
Console.WriteLine(«>»); indirection == left)
Console.WriteLine(«A»); if(direction == down) Console.WriteLine(«v»);
// Проверка на столкновение змейки с препятствиями и хвостом (игра завершается, выводятся очки пользователя)
if(snakeElements.Contains(snakeNewHead) 11 obstacles.Contains(snakeNewHead))
Console.SetCursorPosition(0, 0); Console.ForegroundColor = ConsoleColor.DarkRed; Console.WriteLine(«Игра закончена!»); int userPoints = snakeElements.Count * 100 — negativePoints; userPoints = Math.Max(userPoints, 0);
Console.WriteLine($»Ваши очки: «); return;
Интерфейс разработанной программы, а также окно, свидетельствующее об окончании игры представлены на рисунках 1 и 2 соответственно.
Рисунок 1 — Интерфейс игры «Змейка»
Рисунок 2 — Завершение игры
На рисунке 1 приняты следующие обозначения объектов:
1) «*>> и знак стрелки — змейка (главный элемент игры);
2) «=>> — препятствие, после столкновения с которым игра завершается;
3) «?>> — еда, которую необходимо собирать для получения очков;
4) «_>> — курсор, показывающий положение еды
После столкновения с хвостом, препятствия или краями поля, пользователь (игрок) пользователь получает сообщение об окончании игры и набранных очках.
В данной статье описан процесс создания игры «Змейка» с помощью консольного приложения среды разработки Visual Studio. Для игры понадобилось создание структуры Position (позиция) для фиксации местоположения того или иного объекта. Игра включает в себя следующие объекты: змейка, препятствие и еда. После столкновения змейки с собственным хвостом, с краем игрового поля или препятствием игра завершается и пользователя (игрок) получает информацию о набранных очках. Работу разработанного приложения можно считать корректным.
1. Роль и место компьютерных игр в массовом сознании [Электронный ресурс]. URL: https ://psy.wikireading.ru/2242
2. Snake (игра) [Электронный ресурс]. URL: https://ru.wikipedia.org/ wiki/Snake (игра)
3. Бхаргава А.. Грокаем алгоритмы. Иллюстрированное пособие для программистов и любопытствующих. — СПб.: Питер, 2017. — 288 С.
4. Клейнберг, Дж., Тардос Е.. Алгоритмы: разработка и применение. Классика Computers Science / Пер. с англ. Е. Матвеева. — СПб.: Питер, 2016. — 800 С.
5. Лафоре Р.. Структуры данных и алгоритмы в Java. Классика Computers Science. 2-е изд. — СПб.: Питер, 2013. — 704 С.
1. The role and place of computer games in the mass consciousness [Electronic resource]. URL: https: //psy. wikireading.ru/2242
2. Snake (game) [Electronic resource]. URL: https: //ru. wikipedia.org/ wiki/Snake (game)
3. Bhargava A.. Grokah algorithms. Illustrated guide for programmers and curious. — St. Petersburg: Peter, 2017 . — 288 P.
4. Kleiberg J., Tardos E.. Algorithms: development and application. Classic Computers Science / Translate from Eng E. Matveeva. — St. Peterburg: Peter, 2016. — 800 P.
Научно-образовательный журнал для студентов и преподавателей «StudNet» №12/2020
5. Lafore R.. Data structures and algorithms in Java. Classic Computers Science. 2nd ed. — St. Petersburg: Peter, 2013. — 704 P. ФОРМИРОВАНИЕ ЭКОЛОГИЧЕСКОЙ КУЛЬТУРЫ МЛАДШИХ ШКОЛЬНИКОВ СРЕДСТВАМИ ЭКСКУРСИОННО-КРАЕВЕДЧЕСКОЙ ДЕЯТЕЛЬНОСТИ FORMATION OF ECOLOGICAL CULTURE OF PRIMARY SCHOOL CHILDREN BY MEANS OF EXCURSION AND LOCAL HISTORY
Гареева Снежанна Сергеевна, магистрант 2 курса, БГПУ им. Акмуллы, г. Уфа
Gareeva S.S. ann_holmes_smith@mail.ru
В статье рассмотрено формирование экологической культуры младших школьников средствами экскурсионно-краеведческой деятельности.
Экологическая культура — часть общечеловеческой культуры, система социальных отношений, общественных и индивидуальных морально-этических норм, взглядов, установок и ценностей, касающихся взаимоотношения человека и природы, гармоничность сосуществования человеческого общества и окружающей природной среды; целостный коадаптивный механизм человека и природы, реализующийся через отношение человеческого общества к окружающей природной среде и к экологическим проблемам в целом.
Как создать змейку на c в visual studio
Скопируйте пример ниже и приведите его в порядок. Это можно сделать последовательно в три этапа (не забудьте запустить программу и разобраться в её работе перед выполнением первого этапа):
- Переведите все англоязычные комментарии на русский язык. Рекомендуется использовать онлайн-переводчики для поиска русскоязычных синонимов непонятного английского слова. Текст комментария должен понятно объяснять, что делает программа с точки зрения логики игры. Если оригинальный английский комментарий неверен или лишён смысла, нужно написать вместо него понятный русский комментарий. После перевода всех комментариев надо зафиксировать текущую версию программы в Git (а в случае технических проблем с Git — хотя бы в zip-архив, чтобы затем всё равно зафиксировать в Git)
- Заменить все глобальные переменные на локальные переменные и параметры функций. Если в функции становится слишком много параметров, можно для упаковки параметров объявить свои структуры или использовать готовые. Параметры передавать по константной ссылке ( const Type &value ), по ссылке ( Type &value ) или по значению ( Type value ) в зависимости от контекста. Также нужно заменить все “магические числа” на именованные константы. Полученную версию проверить на работоспособность, зафиксировать в Git.
- Добавить к программе визуализацию с помощью библиотеки SFML, т.е. сделать игру “Змейка” полноценным графическим приложением. Полученную версию проверить на работоспособность, зафиксировать в Git.
Полезные ссылки
- Проектирование структур на C++
- Вопрос о том, как лучше объявлять константы в C++ — “static const” vs “#define” vs “enum”
- Документация Visual Studio: “Навигация по коду с помощью отладчика”
- Документация Visual Studio: “Использование точек останова”
Пример консольной реализации (для Windows)
#include #include #pragma warning(disable:4996) // POSIX name deprecated void run(); void printMap(); void initMap(); void move(int dx, int dy); void update(); void changeDirection(char key); void clearScreen(); void generateFood(); char getMapValue(int value); // Map dimensions const int mapwidth = 20; const int mapheight = 20; const int size = mapwidth * mapheight; // The tile values for the map int map[size]; // Snake head details int headxpos; int headypos; int direction; // Amount of food the snake has (How long the body is) int food = 3; // Determine if game is running bool running; int main() run(); return 0; > // Main game function void run() // Initialize the map initMap(); running = true; while (running) // If a key is pressed if (kbhit()) // Change to direction determined by key pressed changeDirection(getch()); > // Upate the map update(); // Clear the screen clearScreen(); // Print the map printMap(); // wait 0.5 seconds _sleep(500); > // Print out game over text std::cout <"\t\t. Game over!" <std::endl <"\t\tYour score is: " <food; // Stop console from closing instantly std::cin.ignore(); > // Changes snake direction from input void changeDirection(char key) /* W A + D S 1 4 + 2 3 */ switch (key) case 'w': if (direction != 2) direction = 0; break; case 'd': if (direction != 3) direction = 1; break; case 's': if (direction != 4) direction = 2; break; case 'a': if (direction != 5) direction = 3; break; > > // Moves snake head to new location void move(int dx, int dy) // determine new head position int newx = headxpos + dx; int newy = headypos + dy; // Check if there is food at location if (map[newx + newy * mapwidth] == -2) // Increase food value (body length) food++; // Generate new food on map generateFood(); > // Check location is free else if (map[newx + newy * mapwidth] != 0) running = false; > // Move head to new location headxpos = newx; headypos = newy; map[headxpos + headypos * mapwidth] = food + 1; > // Clears screen void clearScreen() // Clear the screen system("cls"); > // Generates new food on map void generateFood() int x = 0; int y = 0; do // Generate random x and y values within the map x = rand() % (mapwidth - 2) + 1; y = rand() % (mapheight - 2) + 1; // If location is not free try again > while (map[x + y * mapwidth] != 0); // Place new food map[x + y * mapwidth] = -2; > // Updates the map void update() // Move in direction indicated switch (direction) case 0: move(-1, 0); break; case 1: move(0, 1); break; case 2: move(1, 0); break; case 3: move(0, -1); break; > // Reduce snake values on map by 1 for (int i = 0; i size; i++) if (map[i] > 0) map[i]--; > > // Initializes map void initMap() // Places the initual head location in middle of map headxpos = mapwidth / 2; headypos = mapheight / 2; map[headxpos + headypos * mapwidth] = 1; // Places top and bottom walls for (int x = 0; x mapwidth; ++x) map[x] = -1; map[x + (mapheight - 1) * mapwidth] = -1; > // Places left and right walls for (int y = 0; y mapheight; y++) map[0 + y * mapwidth] = -1; map[(mapwidth - 1) + y * mapwidth] = -1; > // Generates first food generateFood(); > // Prints the map to console void printMap() for (int x = 0; x mapwidth; ++x) for (int y = 0; y mapheight; ++y) // Prints the value at current x,y location std::cout <getMapValue(map[x + y * mapwidth]); > // Ends the line for next x value std::cout <std::endl; > > // Returns graphical character for display from map value char getMapValue(int value) // Returns a part of snake body if (value > 0) return 'o'; switch (value) // Return wall case -1: return 'X'; // Return food case -2: return 'O'; > return ' '; >
PS-Group
- PS-Group
- sshambir@gmail.com
- ps-group
- image/svg+xml sshambir
Пишем змейку на C++
Давным-давно, когда мониторы были зелёными, а 64Кб оперативы на борту считалось нормой, существовала игрушка под названием Snake. Она также была известна под названиями Змейка, Удав, Питон и даже Червяк. По прошествии времени появилось множество клонов этой игры под различные платформы: от Flash до мобильных телефонов и смартфонов. Но вот та реализация, работающая в текстовом режиме, видимо умерла вместе с теми компьютерами, для которых она была написана.
И вот, за пару свободных вечеров был написан очередной клон легендарного Snake, который я и представляю вашему вниманию: Oldschool Snake.
- Как играть
- Лицензия
- Замечания по реализации
- Исходный код
Как играть
Управление змейкой клавишами управления курсором. Esc — завершение игры. Для выхода из игры надо нажать Esc или клавишу N на вопрос «Once more?». Змейка не должна натыкаться на стенки и на собственный хвост. Это — смерть. Змейка не умеет ползать хвостом вперёд. Попытаться заставить её это сделать — верная смерть. Кормить змейку надо, естественно, долларами. Когда змейка ест, она растёт.
Top 10 определяется по рейтингу. Общий рейтинг складывается из суммы рейтинговых очков, полученных за каждую съеденную еду. Рейтинговые очки прямо пропорциональны длине змейки и обратно пропорциональны времени, затраченному на достижение очередной порции еды.
Окончание игры
Лицензия
GNU GPL. То есть можно свободно распространять, изучать исходный текст, вносить изменения в исходный текст, использовать в своих некоммерческих проектах.
Замечания по реализации
Игрушка очень простая. Основа игрушки была написана за пару вечеров. Правда потом, наверное, неделя ушла на отладку и, главным образом, на тестирование и допиливание. Вполне возможно, что где-то затаились недобитые баги. Отстрел разрешён.
В этот вариант программы уже заложены некоторые возможности по усовершенствованию игры. Но при этом теряется аутентичность.
Программа написана для Windows 2000 Professional (и выше). Для переноса под другие операционки необходимо переписать реализацию класса CScreen и иметь порт библиотеки conio.h .
Компилировал TDM-GCC 4.8.1 С другими компиляторами не проверял.
Вопросы, замечание, предложения, ошибки — пожалуйста в комментарии. Но, скажу сразу, не судите строго за стиль — написано было быстро и, что называется, «для себя».
Исходный код
main.cpp
#include #include "CScreen.h" #include "CGame.h" using namespace std; int main() < setlocale(LC_ALL, "Russian"); try < CScreen screen; screen.cursor_show(false); screen.text_attr((WORD)0x0a); screen.cls(); CGame game(screen, 80, 24, 120); game.logo(); game.read_top10(); game.top10(false); game.pak(18); do < game.game_loop(); game.top10(true); >while (game.once_more()); game.goodbye(); > catch(CSScreenException& ex) < cerr return 0; >
CScreen.h
/* Класс исключения для класса CScreen */ class CSScreenException < public: CSScreenException(int _err) : err(_err) <>const char *what(); // возвращает строку с описанием ошибки int err; // код ошибки >; /* Класс CScreen содержит системозависимые вызовы для вывода на консоль. Данная реализация предназначена для ОС MS Windows 2000 Professional и более поздних. Система координат: (0, 0) - левый верхний угол экрана ось X - горизонтально вправо ось Y - вертикально вниз (положительное направление) */ class CScreen < public: CScreen(); ~CScreen(); void cursor_show(bool visible); // показать/скрыть курсор void text_attr(WORD attr); // установить цвет текста/фона void pos(int x, int y, char ch = 0); // позиционирование курсора и // вывод символа, если ch != 0 void pos_str(int x, int y, const char *str); // позиционирование курсора // и вывод строки void cls(); // очистка экрана private: HANDLE hConsoleOutput; CONSOLE_CURSOR_INFO oldCursorInfo, curCursorInfo; WORD oldTextAttr; >; #endif // __CSCREEN_H__
CScreen.cpp
const char *msgs[] = < "", "Failed GetStdHandle(): INVALID_HANDLE_VALUE", "Failed GetConsoleCursorInfo()", "Failed SetConsoleCursorInfo()", "Failed SetConsoleCursorPosition()" >; const char *CSScreenException::what() < return msgs[err]; >CScreen::CScreen() < hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); if (hConsoleOutput == INVALID_HANDLE_VALUE) throw CSScreenException(1); // "INVALID_HANDLE_VALUE" if (!GetConsoleCursorInfo(hConsoleOutput, &oldCursorInfo)) throw CSScreenException(2); curCursorInfo.dwSize = oldCursorInfo.dwSize; curCursorInfo.bVisible = oldCursorInfo.bVisible; CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(hConsoleOutput, &csbi); oldTextAttr = csbi.wAttributes; >CScreen::~CScreen() < SetConsoleCursorInfo(hConsoleOutput, &oldCursorInfo); SetConsoleTextAttribute(hConsoleOutput, oldTextAttr); >void CScreen::cursor_show(bool visible) < curCursorInfo.bVisible = visible; if (!SetConsoleCursorInfo(hConsoleOutput, &curCursorInfo)) throw CSScreenException(3); >void CScreen::text_attr(WORD attr) < SetConsoleTextAttribute(hConsoleOutput, attr); >void CScreen::pos(int x, int y, char ch) < COORD point; point.X = static_cast(x); point.Y = static_cast(y); if (!SetConsoleCursorPosition(hConsoleOutput, point)) throw CSScreenException(4); if (ch > 0) _putch(ch); > void CScreen::pos_str(int x, int y, const char *str) < pos(x, y); _cprintf("%s", str); >void CScreen::cls()
SCoord.h
SCoord(int _x, int _y) : x(_x), y(_y) <> SCoord& operator +=(const SCoord& op); >; SCoord operator +(const SCoord& op1, const SCoord& op2); bool operator ==(const SCoord& op1, const SCoord& op2); #endif // __SCOORD_H__
SCoord.cpp
SCoord operator +(const SCoord& op1, const SCoord& op2) < return SCoord(op1.x + op2.x, op1.y + op2.y); >bool operator ==(const SCoord& op1, const SCoord& op2)
CSnake.h
#include "SCoord.h" #include "CScreen.h" using namespace std; typedef vector CoordVector; class CSnake < public: CSnake(); void reset(SCoord start_pos); // "сброс" змеи void draw(CScreen& scr); // первичная отрисовка змеи на экране void move(const SCoord& delta, CScreen& scr); // передвижение змеи на приращение координат void grow(const SCoord& pos, int growbits); // увеличение длины змеи bool into(const SCoord& pos); // проверка попадания координаты в тело змеи SCoord head(); // метод возвращает координаты головы змеи int size(); // метод возвращает длину змеи private: CoordVector worm; // вектор координат сегментов тела змеи char head_mark; // символ, которым отрисовывается голова змеи unsigned int drawn; // длина отрисованного тела змеи >; #endif // __CSNAKE_H__
CSnake.cpp
void CSnake::reset(SCoord start_pos) < worm.clear(); worm.reserve(1000); // зарезервировть память worm.push_back(start_pos); // добавить координаты головы worm.push_back(start_pos); // добавить координаты хвоста worm[0].x++; // координата x хвоста - на 1 правее >void CSnake::draw(CScreen& scr) < unsigned int wsize = worm.size() - 1; for (unsigned int i = 0; i < wsize; i++) scr.pos(worm[i].x, worm[i].y, SNAKE_TAIL); scr.pos(worm[wsize].x, worm[wsize].y, head_mark); drawn = worm.size(); >void CSnake::move(const SCoord& delta, CScreen& scr) < // При перемещении змеи перерисовывается только положение головы (и первого сегмента) // и положение хвоста. Остальные сегменты змеи не перерисовываются. // Перерисовка хвоста. // Длина змеи увеличивается, когда змея растёт (метод grow()), // но змея на экране не изменяется. Поэтому, если отрисованная длина змеи // совпадает с реальной длиной, то на экране затирается последний сегмент змеи (хвост). // В противном случае, хвост остаётся на месте, голова сдвигается на единицу, // а отрисованная длина увеличивается. if (drawn == worm.size()) scr.pos(worm[0].x, worm[0].y, ' '); else drawn++; // сдвиг координат в векторе без отрисовки for (unsigned int i = 1; i < worm.size(); i++) worm[i - 1] = worm[i]; worm[worm.size()-1] += delta; // координата головы изменяется на приращение // выбор символа для отрисовки головы в зависимости от направления движения if (delta.x < 0) head_mark = '0) head_mark = '>'; else if (delta.y < 0) head_mark = 'A'; else // (delta.y >0) head_mark = 'V'; // Перерисовка головы и первого сегмента змеи. scr.pos(worm[worm.size() - 1].x, worm[worm.size() - 1].y, head_mark); scr.pos(worm[worm.size() - 2].x, worm[worm.size() - 2].y, SNAKE_TAIL); > void CSnake::grow(const SCoord& pos, int growbits) < for (int i = 0; i < growbits; ++i) worm.insert(worm.begin(), pos); >bool CSnake::into(const SCoord& pos) < for (unsigned int i = 0; i < worm.size(); i++) if (worm[i].x == pos.x && worm[i].y == pos.y) return true; return false; >SCoord CSnake::head() < return worm[worm.size() - 1]; >int CSnake::size() < return static_cast(worm.size()); >
CGame.h
#include #include #include "CScreen.h" #include "CSnake.h" #include "SCoord.h" using namespace std; const int NAMELENGTH = 16; // размер буфера для имени игрока // Структура для хранения результата игры struct SRecord < char name[NAMELENGTH]; // имя игрока double rating; // рейтинг int length; // длина змеи double game_time; // время игры time_t date; // дата и время окончания игры SRecord(); void as_string(char *buffer); // отформатированная строка результата >; class CGame < public: CGame(CScreen& _scr, int _width = 80, int _height = 24, int _latency = 100); void game_loop(); // основной цикл игры void top10(bool after_game); // работа с таблицей 10 лучших результатов bool once_more(); // вывод запроса и приём ответа от игрока void pak(int y); // "Press any key for continue. " void read_top10(); // чтение из файла таблицы 10 лучших результатов void write_top10(); // запись в файл таблицы 10 лучших результатов void logo(); // вывод заставки игры void goodbye(); // вывод копирайта по окончании игры private: enum Command < CMD_NOCOMMAND = 0, CMD_EXIT, CMD_LEFT, CMD_RIGHT, CMD_UP, CMD_DOWN >; enum State < STATE_OK, STATE_EXIT, STATE_DIED >; typedef pair CmdPair; int width, height; // ширина и высота игрового поля int latency; // задержка между изменением позиции в миллисекундах CScreen scr; // подсистема визуализации CSnake snake; // змейка double duration_game; // длительность игры double rating, rating_i; // рейтинг итоговый и частичный SRecord ttop10[10]; // таблица 10 лучших результатов CmdPair cmd_table[5]; // таблица команд управления игрой void draw_field(); // прорисовка игрового поля SCoord make_food(); // вычисление позиции для еды void print_stat(); // вывод текущей статистики ниже игрового поля Command get_command(); // приём команды с клавиатуры void top10_table(); // вывод таблицы 10 лучших результатов >; #endif // __CGAME_H__
CGame.cpp
#include #include // форматная строка для форматирования результата игры const char *recordFormatStr = "%-15s %9.4f %4u %7.2f %s"; SRecord::SRecord() < name[0] = '\0'; rating = 0.0; length = 0; game_time = 0; date = static_cast(0); > void SRecord::as_string(char *buffer) < sprintf(buffer, recordFormatStr, name, rating, length, game_time, ctime(&date)); >ostream& operator istream& operator >> (istream& is, SRecord& rec) < is >> rec.rating >> rec.length >> rec.game_time >> rec.date; is.ignore(1); is.getline(&rec.name[0], 16); return is; > // Функция сравнения результатов по рейтингу. // Необходима для работы qsort() для сортировки по убыванию. int rec_compare(const void *_op1, const void *_op2) < const SRecord *op1 = reinterpret_cast(_op1); const SRecord *op2 = reinterpret_cast(_op2); return static_cast(op2->rating - op1->rating); > /*----- end of struct SRecord -------------------------------------*/ // очистка буфера клавиатуры void clearkeys() < while (_kbhit()) _getch(); >// Конструктор // _scr - объект, осуществляющий вывод на консоль // _width - ширина игрового поля (x) // _height - высота игрового поля (y) // _latency - задержка между изменением позиции в миллисекундах CGame::CGame(CScreen& _scr, int _width, int _height, int _latency) : width(_width), height(_height), latency(_latency), scr(_scr) < srand(static_cast(time(NULL))); duration_game = 0; rating = 0.0; // инициализация таблицы команд управления игрой cmd_table[0] = CmdPair(27, CMD_EXIT); // escape key cmd_table[1] = CmdPair('K', CMD_LEFT); // стрелка влево cmd_table[2] = CmdPair('M', CMD_RIGHT); // стрелка вправо cmd_table[3] = CmdPair('H', CMD_UP); // стрелка вверх cmd_table[4] = CmdPair('P', CMD_DOWN); // стрелка вниз > CGame::Command CGame::get_command() < int ch; ch = _getch(); if (ch == 0 || ch == 0xe0) < ch = _getch(); >for (int i = 0; i < 5; i++) < if (cmd_table[i].first == ch) < return cmd_table[i].second; >> return CMD_NOCOMMAND; > // Координата еды вычисляется случайным образом. // Ограничение: координата не должна попадать в тело змеи. SCoord CGame::make_food() < SCoord food; do < food.x = rand() % (width - 2) + 1; food.y = rand() % (height - 2) + 1; >while (snake.into(food)); return food; > const char BORDER = '#'; // символ для рисования рамки игрового поля void CGame::draw_field() < scr.cls(); for (int y = 0; y < height; y++) < if (y == 0 || y == height - 1) < for (int x = 0; x < width; x++) scr.pos(x, y, BORDER); >else < scr.pos(0, y, BORDER); scr.pos(width - 1, y, BORDER); >> scr.pos(0, height); _cprintf("Length: **** Rating: ****.**** (****.****) Time: ****.**"); > void CGame::print_stat() < scr.pos(8, height); _cprintf("%04u", snake.size()); scr.pos(22, height); _cprintf("%09.4f", rating); scr.pos(33, height); _cprintf("%09.4f", rating_i); scr.pos(51, height); _cprintf("%07.2f", duration_game); >void CGame::top10_table() < scr.cls(); char buf[80]; scr.pos_str(width / 2 - 12, 2, "***** T O P 1 0 *****"); scr.pos_str(5, 4, "Name Rating Length Time Date"); for (int i = 0; i < 10; i++) < ttop10[i].as_string(buf); scr.pos_str(5, 5 + i, buf); >> void CGame::top10(bool after_game) < char buf[80]; char buf_encoded[NAMELENGTH]; top10_table(); // показать таблицу 10 лучших результатов time_t date = time(NULL); if (after_game) < // если игра была сыграна, то показать текущий результат scr.pos(5, 16); _cprintf(recordFormatStr, "Your result", rating, snake.size(), duration_game, ctime(&date)); >if (rating > ttop10[9].rating) < // если рейтинг игры больше, чем меньший из 10 лучших. // запросить имя игрока scr.pos_str(5, 20, "Your name: _"); scr.pos(16, 20); cin.getline(&buf[0], NAMELENGTH); clearkeys(); OemToCharBuff(buf, buf_encoded, static_cast(NAMELENGTH)); // заменить последнюю запись в таблице 10 лучших результатов strcpy(ttop10[9].name, buf_encoded); ttop10[9].date = date; ttop10[9].game_time = duration_game; ttop10[9].length = snake.size(); ttop10[9].rating = rating; // отсортировать результаты по убыванию qsort(ttop10, 10, sizeof(SRecord), rec_compare); // обновить таблицу на экране top10_table(); // обновить файл с 10 лучшими результатами write_top10(); > > void CGame::pak(int y) < scr.pos_str(width / 2 - 15, y, "Press any key for continue. "); _getch(); clearkeys(); >bool CGame::once_more() < scr.pos_str(width / 2 - 12, height - 3, "O n c e m o r e ?"); int ch = _getch(); clearkeys(); if (ch == 'N' || ch == 'n' || ch == 27) return false; return true; >const char *top10_filename = "snake.dat"; // имя файла для хранения 10 лучших результатов void CGame::read_top10() < ifstream fin(top10_filename); if (fin) < for (int i = 0; i < 10; i++) fin >> ttop10[i]; > fin.close(); > void CGame::write_top10() < ofstream fout(top10_filename); if (fout) < for (int i = 0; i < 10; i++) fout fout.close(); > const char *ver_number = "v 1.1"; const char *copyright = "(c) Cranium, 2014."; void CGame::logo() < scr.pos_str(width / 2 - 9, 10, "O l d s c h o o l"); scr.pos_str(width / 2 - 7, 12, "S N A K E"); scr.pos_str(width / 2 - 3, 16, ver_number); scr.pos_str(width / 2 - 9, height, copyright); pak(22); >void CGame::goodbye() < scr.cls(); _cprintf("Oldschool Snake %s\n%s\n", ver_number, copyright); >const char FOOD = '$'; // символ для вывода еды void CGame::game_loop() < duration_game = 0; rating = rating_i = 0.0; draw_field(); // нарисовать игровое поле snake.reset(SCoord(width / 2, height / 2)); // установить змею: длина 2, // положение - в середине игрового поля, // направление - влево Command cmd = CMD_NOCOMMAND; State stt = STATE_OK; // delta содержит приращение координат (dx, dy) для каждого перемещения змеи по полю SCoord delta(-1, 0); // начальное движение - влево SCoord food = make_food(); // вычислить координаты еды scr.pos(food.x, food.y, FOOD); // вывести еду на экран snake.draw(scr); // первичное рисование змеи print_stat(); // вывести начальную статистику игры clock_t time1, time2, duration; time1 = clock(); do < if (_kbhit()) // если в буфере клавиатуры есть информация, cmd = get_command(); // то принять команду // обработка команд switch (cmd) < case CMD_LEFT: delta = SCoord(-1, 0); break; case CMD_RIGHT: delta = SCoord(1, 0); break; case CMD_UP: delta = SCoord(0, -1); break; case CMD_DOWN: delta = SCoord(0, 1); break; case CMD_EXIT: stt = STATE_EXIT; default: break; >; SCoord hd = snake.head(); // координата головы змеи hd += delta; // координата головы змеи после приращения (следующая позиция) // если голова змеи столкнулась с границей поля или со телом змеи, то змея умирает if (hd.x == 0 || hd.x == width-1 || hd.y == 0 || hd.y == height-1 || snake.into(hd)) stt = STATE_DIED; if (stt == STATE_OK) < // если змея ещё жива, то snake.move(delta, scr); // сдвинуть змею на delta if (snake.head() == food) < // если координата головы змеи совпадает с координатой еды, то snake.grow(food, 3); // увеличить длину змеи food = make_food(); // вычислить координаты новой еды scr.pos(food.x, food.y, FOOD); // вывести еду на экран // Вычисление времени игры, частичного и общего рейтинга. // Частичный рейтинг вычисляется как длина змеи, делённая на время в секундах, // затраченное на подход к еде (время от съедения предыдущей еды до съедения следующей). // Таким образом, чем чаще змея ест и чем она длиннее, тем выше частичный рейтинг. time2 = clock(); duration = time2 - time1; duration_game += static_cast(duration) / CLOCKS_PER_SEC; rating_i = static_cast(snake.size()) / duration * CLOCKS_PER_SEC; rating += rating_i; // общий рейтинг - сумма частичных рейтингов за игру time1 = time2; print_stat(); // вывод текущей статистики игры > Sleep(latency); // задержка перед следующим изменением позиции > > while (stt == STATE_OK); // играем, пока змея жива scr.pos_str(width / 2 - 8, 10, " G a m e o v e r "); clearkeys(); _getch(); clearkeys(); >
Автор статьи: Череп.
Своя змейка, или пишем первый проект. Часть 0
Привет Хабр! Меня зовут Евгений «Nage», и я начал заниматься программированием около года назад, в свободное от работы время. Просмотрев множество различных туториалов по программированию задаешься вопросом «а что же делать дальше?», ведь в основном все рассказывают про самые основы и дальше как правило не заходят. Вот после продолжительного времени за просмотром разных роликов про одно и тоже я решил что стоит двигаться дальше, и браться за первый проект. И так, сейчас мы разберем как можно написать игру «Змейка» в консоли со своими начальными знаниями.
Глава 1. Итак, с чего начнем?
Для начала нам ничего лишнего не понадобится, только блокнот (или ваш любимый редактор), и компилятор C#, он присутствует по умолчанию в Windows, находится он в С:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe. Можно использовать компилятор последней версии который поставляется с visual studio, он находится Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\Roslyn\csc.exe.
Создадим файл для быстрой компиляции нашего кода, сохранил файл с расширением .bat со следующим содержимым:
@echo off :Start set /p name= Enter program name: echo. С:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe "%name%.cs" echo. goto Start
«@echo off» отключает отображение команд в консоли. С помощью команды goto получаем бесконечный цикл. Задаем переменную name, а с модификатором /p в переменную записывается значение введенное пользователем в консоль. «echo.» просто оставляет пустую строчку в консоли. Далее вызываем компилятор и передаем ему файл нашего кода, который он скомпилирует.
Таким способом мы можем скомпилировать только один файл, поэтому мы будем писать все классы в одном документе (я не разобрался еще как компилировать несколько файлов в один .exe через консоль, да и это не тема нашей статьи, может кто нибудь расскажет в комментариях).
Для тех кто сразу хочет увидеть весь код.
Скрытый текст
using System; using System.Threading; using System.Collections.Generic; using System.Linq; namespace SnakeGame < class Game < static readonly int x = 80; static readonly int y = 26; static Walls walls; static Snake snake; static FoodFactory foodFactory; static Timer time; static void Main() < Console.SetWindowSize(x + 1, y + 1); Console.SetBufferSize(x + 1, y + 1); Console.CursorVisible = false; walls = new Walls(x, y, '#'); snake = new Snake(x / 2, y / 2, 3); foodFactory = new FoodFactory(x, y, '@'); foodFactory.CreateFood(); time = new Timer(Loop, null, 0, 200); while (true) < if (Console.KeyAvailable) < ConsoleKeyInfo key = Console.ReadKey(); snake.Rotation(key.Key); >> >// Main() static void Loop(object obj) < if (walls.IsHit(snake.GetHead()) || snake.IsHit(snake.GetHead())) < time.Change(0, Timeout.Infinite); >else if (snake.Eat(foodFactory.food)) < foodFactory.CreateFood(); >else < snake.Move(); >>// Loop() >// class Game struct Point < public int x < get; set; >public int y < get; set; >public char ch < get; set; >public static implicit operator Point((int, int, char) value) => new Point ; public static bool operator ==(Point a, Point b) => (a.x == b.x && a.y == b.y) ? true : false; public static bool operator !=(Point a, Point b) => (a.x != b.x || a.y != b.y) ? true : false; public void Draw() < DrawPoint(ch); >public void Clear() < DrawPoint(' '); >private void DrawPoint(char _ch) < Console.SetCursorPosition(x, y); Console.Write(_ch); >> class Walls < private char ch; private Listwall = new List(); public Walls(int x, int y, char ch) < this.ch = ch; DrawHorizontal(x, 0); DrawHorizontal(x, y); DrawVertical(0, y); DrawVertical(x, y); >private void DrawHorizontal(int x, int y) < for (int i = 0; i < x; i++) < Point p = (i, y, ch); p.Draw(); wall.Add(p); >> private void DrawVertical(int x, int y) < for (int i = 0; i < y; i++) < Point p = (x, i, ch); p.Draw(); wall.Add(p); >> public bool IsHit(Point p) < foreach (var w in wall) < if (p == w) < return true; >> return false; > >// class Walls enum Direction < LEFT, RIGHT, UP, DOWN >class Snake < private Listsnake; private Direction direction; private int step = 1; private Point tail; private Point head; bool rotate = true; public Snake(int x, int y, int length) < direction = Direction.RIGHT; snake = new List(); for (int i = x - length; i < x; i++) < Point p = (i, y, '*'); snake.Add(p); p.Draw(); >> public Point GetHead() => snake.Last(); public void Move() < head = GetNextPoint(); snake.Add(head); tail = snake.First(); snake.Remove(tail); tail.Clear(); head.Draw(); rotate = true; >public bool Eat(Point p) < head = GetNextPoint(); if (head == p) < snake.Add(head); head.Draw(); return true; >return false; > public Point GetNextPoint () < Point p = GetHead (); switch (direction) < case Direction.LEFT: p.x -= step; break; case Direction.RIGHT: p.x += step; break; case Direction.UP: p.y -= step; break; case Direction.DOWN: p.y += step; break; >return p; > public void Rotation (ConsoleKey key) < if (rotate) < switch (direction) < case Direction.LEFT: case Direction.RIGHT: if (key == ConsoleKey.DownArrow) direction = Direction.DOWN; else if (key == ConsoleKey.UpArrow) direction = Direction.UP; break; case Direction.UP: case Direction.DOWN: if (key == ConsoleKey.LeftArrow) direction = Direction.LEFT; else if (key == ConsoleKey.RightArrow) direction = Direction.RIGHT; break; >rotate = false; > > public bool IsHit(Point p) < for (int i = snake.Count - 2; i >0; i--) < if (snake[i] == p) < return true; >> return false; > >//class Snake class FoodFactory < int x; int y; char ch; public Point food < get; private set; >Random random = new Random(); public FoodFactory(int x, int y, char ch) < this.x = x; this.y = y; this.ch = ch; >public void CreateFood() < food = (random.Next(2, x - 2), random.Next(2, y - 2), ch); food.Draw(); >> >
Глава 2. Первые шаги
Подготовим поле нашей игры, начиная с точки входа в нашу программу. Задаем переменные X и Y, размер и буфер окна консоли, и скроем отображение курсора.
using System; using System.Collections.Generic; using System.Linq; class Game< static readonly int x = 80; static readonly int y = 26; static void Main()< Console.SetWindowSize(x + 1, y + 1); Console.SetBufferSize(x + 1, y + 1); Console.CursorVisible = false; >// Main() >// class Game
Для вывода на экран нашей «графики» создадим свой тип данных — точка. Он будет содержать координаты и символ, который будет выводится на экран. Также сделаем методы для вывода на экран точки и ее «стирания».
struct Point < public int x < get; set; >public int y < get; set; >public char ch < get; set; >public static implicit operator Point((int, int, char) value) => new Point ; public void Draw() < DrawPoint(ch); >public void Clear() < DrawPoint(' '); >private void DrawPoint(char _ch) < Console.SetCursorPosition(x, y); Console.Write(_ch); >>
Это интересно!
Оператор => называется лямбда-оператор, он используется в качестве определения анонимных лямбда выражений, и в качестве тела, состоящего из одного выражения, синтаксический сахар, заменяющий оператор return. Приведенный выше метод переопределения оператора (про его назначение чуть ниже) можно переписать так:
public static bool operator ==(Point a, Point b) < if (a.x == b.x && a.y == b.y)< return true; >else < return false; >>
Создадим класс стен, границы игрового поля. Напишем 2 метода на создание вертикальных и горизонтальных линий, и в конструкторе вызываем отрисовку всех 4х сторон заданным символом. Список всех точек в стенке нам пригодится позже.
class Walls < private char ch; private Listwall = new List(); public Walls(int x, int y, char ch) < this.ch = ch; DrawHorizontal(x, 0); DrawHorizontal(x, y); DrawVertical(0, y); DrawVertical(x, y); >private void DrawHorizontal(int x, int y) < for (int i = 0; i < x; i++)< Point p = (i, y, ch); p.Draw(); wall.Add(p); >> private void DrawVertical(int x, int y) < for (int i = 0; i < y; i++) < Point p = (x, i, ch); p.Draw(); wall.Add(p); >> >// class Walls
Как вы могли заметить для инициализации типа данных Point используется форма Point p = (x, y, ch); как и у встроенных типов, это становится возможным при переопределении оператора implicit, в котором описывается как задаются переменные.
Конструкция (int, int, char) называется кортежем, и работает только с .net 4.7+, по этому если у вас не установлен visual studio, то в вашем распоряжении только компилятор v4.0.30319 и нужно использовать стандартную инициализацию через оператор new.
Вернемся к классу Game и объявим поле walls, а в методе Main инициализируем ее.
class Game< static Walls walls; static void Main()< walls = new Walls(x, y, '#'); .
Все! Можно скомпилировать код и посмотреть, что наше поле построилось, и самая легкая часть позади.
Глава 3. А что сегодня на завтрак?
Добавим генерацию еды на нашем поле, для этого создадим класс FoodFactory, который и будет заниматься созданием еды внутри границ.
class FoodFactory < int x; int y; char ch; public Point food < get; private set; >Random random = new Random(); public FoodFactory(int x, int y, char ch) < this.x = x; this.y = y; this.ch = ch; >public void CreateFood() < food = (random.Next(2, x - 2), random.Next(2, y - 2), ch); food.Draw(); >>
Добавляем инициализацию фабрики и создадим еду на поле
class Game< static FoodFactory foodFactory; static void Main()< foodFactory = new FoodFactory(x, y, '@'); foodFactory.CreateFood(); .
Глава 4. Время главного героя
Перейдем к созданию самой змеи, и для начала определим перечисление направления движения змейки.
enum Direction
Теперь можем создать класс змейки, где опишем как она будет ползать, поворачивать. Определим список точек змеи, наше перечисление, шаг на сколько будет перемещаться за ход, и ссылки на хвостовую и головную точки, и конструктор, в котором рисуем змею в заданных координатах и заданной длинны при старте игры.
class Snake < private Listsnake; private Direction direction; private int step = 1; private Point tail; private Point head; bool rotate = true; public Snake(int x, int y, int length)< direction = Direction.RIGHT; snake = new List(); for (int i = x - length; i < x; i++) < Point p = (i, y, '*'); snake.Add(p); p.Draw(); >> //Методы движения и поворота в зависимости он направления движения змейки. public Point GetHead() => snake.Last(); public void Move() < head = GetNextPoint(); snake.Add(head); tail = snake.First(); snake.Remove(tail); tail.Clear(); head.Draw(); rotate = true; >public Point GetNextPoint() < Point p = GetHead(); switch (direction) < case Direction.LEFT: p.x -= step; break; case Direction.RIGHT: p.x += step; break; case Direction.UP: p.y -= step; break; case Direction.DOWN: p.y += step; break; >return p; > public void Rotation(ConsoleKey key) < if (rotate) < switch (direction) < case Direction.LEFT: case Direction.RIGHT: if (key == ConsoleKey.DownArrow) direction = Direction.DOWN; else if (key == ConsoleKey.UpArrow) direction = Direction.UP; break; case Direction.UP: case Direction.DOWN: if (key == ConsoleKey.LeftArrow) direction = Direction.LEFT; else if (key == ConsoleKey.RightArrow) direction = Direction.RIGHT; break; >rotate = false; > > >//class Snake
В методе поворота, что бы избежать возможности повернуть сразу на 180 градусов, просто указываем, что в каждом направлении мы можем повернуть только в 2 стороны. А проблему поворота на 180 градусов двумя нажатиями — поставив «переключатель», отключаем возможность поворачивать после первого нажатия, и включаем после очередного хода.
Осталось вывести ее на экран.
class Game< static Snake snake; static void Main()< snake = new Snake(x / 2, y / 2, 3); .
Готово! теперь у нас есть все что нужно, поле огороженное стенами, рандомно появляющаяся еда, и змейка. Пришла пора заставить все это взаимодействовать друг с другом.
Глава 5. Л-логика
Заставим нашу змейку двигаться, напишем бесконечный цикл для считывания клавиш нажатых на клавиатуре, и передаем клавишу в метод поворота змеи
class Game < static void Main () < while (true) < if (Console.KeyAvailable) < ConsoleKeyInfo key = Console.ReadKey (); snake.Rotation(key.Key); >.
для движения змеи воспользуемся классом .net который будет запускать метод Loop через определенные промежутки времени.
using System.Threading; class Game < static Timer time; static void Main () < time = new Timer (Loop, null, 0, 200); .
Теперь, перед тем как написать метод движения змейки, надо реализовать взаимодействие головы с едой, стенками и хвостом змеи. Для этого надо написать метод, позволяющий сравнивать две точки на совпадение координат. Переопределим оператор равенства и не равенства, их обязательно нужно переопределять в паре.
struct Point < public static bool operator == (Point a, Point b) =>(a.x == b.x && a.y == b.y) ? true : false; public static bool operator != (Point a, Point b) => (a.x != b.x || a.y != b.y) ? true : false; .
Теперь можно написать метод, который будет проверять совпадает ли интересующая нас точка с какой нибудь из массива стен.
class Walls < public bool IsHit (Point p) < foreach (var w in wall) < if (p == w) < return true; >> return false; > .
И похожий метод проверяющий не совпадает ли точка с хвостом.
class Snake < public bool IsHit (Point p) < for (int i = snake.Count - 2; i >0; i--) < if (snake[i] == p) < return true; >> return false; > .
И методом проверки съела ли еду наша змейка, и сразу делаем ее длиннее.
class Snake < public bool Eat (Point p) < head = GetNextPoint (); if (head == p) < snake.Add (head); head.Draw (); return true; >return false; > .
теперь можно написать метод движения, со всеми нужными проверками.
class Snake < static void Loop (object obj) < if (walls.IsHit (snake.GetHead ()) || snake.IsHit (snake.GetHead ())) < time.Change (0, Timeout.Infinite); >else if (snake.Eat (foodFactory.food)) < foodFactory.CreateFood (); >else < snake.Move (); >> .
Вот и все! Наша змейка в консоли закончена и можно поиграть.
Заключение
Мы посмотрели как можно реализовать первую простенькую игру с небольшим использованием ООП, научились перегружать операторы, посмотрели на кортежи и лямбда оператор, надеюсь это было полезно!
Это была пилотная статья, и если вам понравилось, я напишу про реализацию змейки на Unity.
Всем удачи!
