С Новым годом! Форум программистов, компьютерный форум, киберфорум
Программирование игр
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.86/29: Рейтинг темы: голосов - 29, средняя оценка - 4.86
2 / 2 / 0
Регистрация: 08.06.2018
Сообщений: 66

Прошу критики игры "Змейка"

20.06.2018, 15:06. Показов 6199. Ответов 85
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет.
Недавно написал змейку.
Прошу оценить и покритиковать немного,мб какие-то предложения,поправки.
Вложения
Тип файла: rar Project.rar (12.87 Мб, 47 просмотров)
Тип файла: rar отдельно main.rar (1.3 Кб, 11 просмотров)
Тип файла: rar отдельно екзешник.rar (24.7 Кб, 25 просмотров)
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
20.06.2018, 15:06
Ответы с готовыми решениями:

Змейка, завершение игры
Нужно сделать чтобы змейка ела 5 яблок и игра заканчивалась, но не могу понять как это сделать( Вот сам код #include...

Прошу критики
Всем привет! Прошу старших коллег оценить код ниже. Любая критика приветствуется. Стоит задача спарсить страницы с объявлениями о...

Прошу вашей критики
Начинаю делать собственный проект www.geo-rus.ru. Жду вашей критики по всем фронтам. :) Главный вопрос: стоит ли он развития, или...

85
 Аватар для COKPOWEHEU
4082 / 2680 / 432
Регистрация: 09.09.2017
Сообщений: 11,900
21.06.2018, 10:42
Лучший ответ Сообщение было отмечено anton3d как решение

Решение

HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
Лучше так не делать. Консоль не предназначена для графической информации, она только для текста. Либо используйте псевдографику, либо создавайте нормальное окно.
char field[22][77]
Хардкод размера - плохая идея. Используйте константы или макроконстанты, а еще лучше - переменные и динамический размер.
SetConsoleTextAttribute(hConsole, (WORD)((0 << 4) | 1));
cout << field[i][j];
А, так все-таки используется псевдографика оО. Посмотрите лучше в сторону curses, там это сделано более по-человечески. Заодно можно будет избавиться от #include <windows.h> #include <conio.h> и т.п., поскольку в консольной программе они обычно не нужны.
switch (sdir)
{
case -32:
Там точно сравнение беззнакового char с отрицательным числом должно быть?
Ну и точно ли нужно sdir делать глобальной?
case -32:
case 75:
case 77:
case 80:
case 72:
Лично мне эти числа ничего не говорят. Используйте константы. Хотя бы так:
C
1
2
3
4
5
6
7
#define KEY_UP 'w'
#define KEY_DOWN 's'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'd'
...
case KEY_UP:
case KEY_DOWN:
В перспективе еще лучше будет заменить на переменные, чтобы можно было настроить раскладку
Sleep(60);
Вообще-то лучше еще считать сколько времени шла отрисовка предыдущего кадра. Впрочем, для такой игры можно и так.
int lastposx[100], lastposy[100], hscore, coutr, length, score, shposx, shposy, mposx, mposy;
Переменные, связанные с отдельными объектами лучше бы завернуть в struct или class. Просто для удобства.
.
В целом код неплохой. Нормальное форматирование. Комментариев, правда, нет, но код достаточно прозрачный, так что не особо и нужны. Недостатки, которые бросились в глаза, я указал.
0
2 / 2 / 0
Регистрация: 08.06.2018
Сообщений: 66
21.06.2018, 12:12  [ТС]
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Лучше так не делать. Консоль не предназначена для графической информации, она только для текста. Либо используйте псевдографику, либо создавайте нормальное окно.
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
А, так все-таки используется псевдографика оО. Посмотрите лучше в сторону curses, там это сделано более по-человечески. Заодно можно будет избавиться от #include <windows.h> #include <conio.h> и т.п., поскольку в консольной программе они обычно не нужны.
switch (sdir)
Эти места делал просто как ctrl+c сtrl+v с интернета,но теперь буду знать что нужно выучить)

Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Там точно сравнение беззнакового char с отрицательным числом должно быть?
Ну и точно ли нужно sdir делать глобальной?
Код -32 это общий код стрелочек,он иногда проскакивает,поэтому решил указать.

Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Вообще-то лучше еще считать сколько времени шла отрисовка предыдущего кадра. Впрочем, для такой игры можно и так.
Да-да делал так уже(вот тут вот все циклы пробовал-https://habr.com/post/136878/)но взял этот вариант просто ввиду его простоты(оно все одинаково выглядело все-равно)

Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Переменные, связанные с отдельными объектами лучше бы завернуть в struct или class. Просто для удобства.
А вот с классами и ооп я просто не знаком,у меня уровень школьного олимпиадного программирования)
Но если есть какие-то ресурсы где это объясняется доступным языком я бы прочитал,посоветуете что-нибудь?

Ну и по поводу того,что переменные которые не меняются запихивать в константы и через них выражать другие,чтобы потом пол кода не лопатить-понял принял-исправлюсь.
Именно то,что хотел услышать,большое спасибо)
0
 Аватар для COKPOWEHEU
4082 / 2680 / 432
Регистрация: 09.09.2017
Сообщений: 11,900
21.06.2018, 15:51
Цитата Сообщение от anton3d Посмотреть сообщение
но взял этот вариант просто ввиду его простоты
В принципе согласен, для простых задач sleep'а достаточно. Но, я надеюсь, вы на этом не остановитесь. В когда обсчет будет занимать все свободное время и чуть-чуть больше уже придется писать нормальную синхронизацию.
Цитата Сообщение от anton3d Посмотреть сообщение
А вот с классами и ооп я просто не знаком,у меня уровень школьного олимпиадного программирования)
А мы в школе на Паскале писали...
Поэтому на своем опыте не смогу назвать хорошую литературу. Но посмотрите в шапке подфорумов по Си и С++.
Самое простое - объединить в структуру
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Snake{ //объявляем тип данных - структура змейки
  int x, y;
  int dir, ldir;
};
 
struct Snake s; //конкретный экземпляр (в общем случае их может быть сколько угодно)
 
switch( s.dir ){ //доступ к полям структуры (и класса тоже) осуществляется через точку
  case 'L' : s.x--; break;
  case 'R' : s.x++; break;
  case 'U' : s.y--; break;
  case 'D' : s.y++; break;
  default: s.x=0; s.y=0;
}
0
2 / 2 / 0
Регистрация: 08.06.2018
Сообщений: 66
21.06.2018, 18:05  [ТС]
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
А мы в школе на Паскале писали...
На паскале меня тоже учили,а с++ это я уже сам изучал.

Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Самое простое - объединить в структуру
А вот эту структуру можно выводить в отдельный файл?
0
 Аватар для COKPOWEHEU
4082 / 2680 / 432
Регистрация: 09.09.2017
Сообщений: 11,900
22.06.2018, 10:58
Можно, но зачем? Когда захотите посмотреть какие у нее поля (вдруг название забыли) или что-то добавить - удалить, придется лезть в другой файл, искать его, открывать. Это неудобно. Пока структура маленькая и идет прямой доступ к ее полям выносить не слишком полезно.
Тут вопрос что менее неприятно, каждый раз открывать соседний файл чтобы поправить какую-то мелочь или заниматься поиском в одном большом.
Обычно в отдельный файл (точнее, пару файлов, *.c/*.cpp + *.h/*.hpp) выносят конкретную библиотеку, имеющую минимум связей с остальной программой. Скажем, стандартная stdio / iostream занимается среднеуровневым вводом-выводом через файлы (более низкий уровень - системные вызовы вроде open/read/write или FileOpen/FileRead/..., более высокий - скажем, базы данных). И все! Неявных связей у нее мало, все операции достаточно независимые. И ее можно писать, отлаживать и применять независимо от первоначальной программы.
Точно так же имеет смысл вынести библиотеку работы с графикой (или псевдографикой), ввод-вывод (придется объединить с графикой - если хотите, потом подробнее расскажу). Работу с двух- и трехмерными векторами, матрицами (это уже если захотите заняться 3D а стандартные библиотеки не заинтересуют).
В общем, пока что разделение кода на несколько файлов принесет больше вреда чем пользы.
Я бы посоветовал для начала улучшить сам код, сделать его еще более простым и наглядным. Еще раз отмечу: в плане форматирования (отступы, стили именования и т.п.) и наглядности ваш код довольно хорош, но все же указанные мной ранее недочеты стоит исправить. Это сделает его более простым для дальнейшего совершенствования.
Собственно, если хотите, могу и более подробно помочь с программированием. Выкладывайте исправленный код (лучше не архивом, а копированием на форум и обрамлением тегами) и посмотрим что еще можно сделать.
в порядке полета фантазии
Давно хотел разобраться с сетевым взаимодействием. Можно было бы на примере вашего кода поэкспериментировать. Кстати, вынесение работы с сетью в отдельный файл тоже имеет смысл.
0
2 / 2 / 0
Регистрация: 08.06.2018
Сообщений: 66
22.06.2018, 23:31  [ТС]
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Пока структура маленькая и идет прямой доступ к ее полям выносить не слишком полезно.
Окей,это понятно,но как я понимаю структуры и классы это все более удобно применять к большим проектам,но все-равно перед большим нужно будет на маленьком все проверить))
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
если хотите, потом подробнее расскажу
Я весь Ваш,открыт для нового и жажду новых знаний!
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Собственно, если хотите, могу и более подробно помочь с программированием. Выкладывайте исправленный код (лучше не архивом, а копированием на форум и обрамлением тегами) и посмотрим что еще можно сделать.
Будет сделано!Правда у меня через неделю последний экзамен,поэтому насчет свободного времени пока туго...
Но лето есть лето,и я посвящу этому столько времени,сколько смогу.
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Давно хотел разобраться с сетевым взаимодействием. Можно было бы на примере вашего кода поэкспериментировать. Кстати, вынесение работы с сетью в отдельный файл тоже имеет смысл.
Мне это тоже интересно,может быть не сейчас,но в ближайшем будущем я буду только рад поэкспериментировать с Вами!
0
 Аватар для COKPOWEHEU
4082 / 2680 / 432
Регистрация: 09.09.2017
Сообщений: 11,900
23.06.2018, 10:30
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
ввод-вывод (придется объединить с графикой - если хотите, потом подробнее расскажу)
В общих чертах: ввод и вывод в современных системах идут только через вызову функций операционной системы и только с привязкой к конкретному окну программы (или терминалу). В отличие от, скажем, сети, где работа тоже идет через ОС, но уже без привязки к окну. Поэтому ввод и вывод хочешь не хочешь придется объединять. Зато можно создать абстрактный класс, не специфичный для конкретного вывода (псевдографика через curses, трехмерка через OpenGL или DirectX, ручная двухмерка через SDL), хотя это сложно и в большинстве случаев неоправдано.
Цитата Сообщение от anton3d Посмотреть сообщение
Правда у меня через неделю последний экзамен,поэтому насчет свободного времени пока туго...
Тогда не буду отвлекать конкретным кодом
Цитата Сообщение от anton3d Посмотреть сообщение
Окей,это понятно,но как я понимаю структуры и классы это все более удобно применять к большим проектам,но все-равно перед большим нужно будет на маленьком все проверить))
Не совсем. Классы (в частном случае - структуры) используются для визуального объединения переменных, относящихся к одной сущности. Вот хотя бы к той же змейке, чтобы была одна глобальная переменная, а не десяток. И это объединение можно делать на любом этапе.
0
 Аватар для COKPOWEHEU
4082 / 2680 / 432
Регистрация: 09.09.2017
Сообщений: 11,900
26.06.2018, 15:06
Вот простенький пример с использованием ncurses. Файл res/prog32.exe - скомпилированный бинарник, в mingw_include - заголовочные файлы для mingw32. Не знаю какой у вас компилятор и, если это не gcc, то не знаю как к нему подключать curses. Впрочем, Гугл знает наверняка.
makefile страшный, пока что смотреть его не рекомендую. Там накручена куча костылей для кросс-компиляции произвольной программы из нескольких исходников.
src/portability.h - файл совместимости между некоторыми линуксовыми и виндовыми функциями. Пока что он не нужен, но может пригодиться потом
src/main.cpp - собственно, файл исходника. Комментарии не расставлял специально. Загляните в документацию на curses, разберитесь как эти функции работают и прокомментируйте код.
Вложения
Тип файла: rar ncur_snake.rar (430.0 Кб, 31 просмотров)
0
9037 / 2937 / 494
Регистрация: 05.10.2013
Сообщений: 7,962
Записей в блоге: 216
27.06.2018, 11:15
anton3d, у меня есть предложение, чтобы вы перевели свой код, например, на OpenGL. Окно можно создать с помощью SDL2. Сначала сделать в 2D, а дальше будет несложно перейти в 3D. Здесь пример и видео туториал на русском.

По поводу сети, в SDL2 есть сеть. Книга на русском по сети на SDL2: Многопользовательские игры. Разработка сетевых приложений
0
 Аватар для COKPOWEHEU
4082 / 2680 / 432
Регистрация: 09.09.2017
Сообщений: 11,900
27.06.2018, 22:07
8Observer8, не спешите. Псевдографика все же программируется несколько проще, а потом и SDL + OpenGL можно добавить, и даже переключение графики на лету.
Лично для меня написать змейку что на ncurses, что на SDL + OpenGL, что даже на WinAPI + DirectX (хотя последний раз пользовался им лет 10 назад) не представляет особых проблем. Но в этой теме я хочу попытаться помочь ТСу улучшить качество его кода и немного потренироваться в коллективном программировании.
Короче, процесс важнее результата.
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Сначала сделать в 2D, а дальше будет несложно перейти в 3D.
Змейку в 3D? Идея, конечно, интересная, но все же не сейчас
0
9037 / 2937 / 494
Регистрация: 05.10.2013
Сообщений: 7,962
Записей в блоге: 216
28.06.2018, 14:02
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Змейку в 3D?
Ну да, сначала заменить квадраты на кубы, а потом можно будет .obj файл парсануть из бесплатного легковесного 3D-редактора Blender, откуда можно либо стандартые объекты экспортировать, типа сферы, либо свои простые объекты сделать (очень простые - тут не нужно быть крутым 3D моделлером в Blender'е). Сначала цветные объекты, а потом тектуры найти в инете и наложить через UV-развертку.

Может даже имеет смысл потом не трогать OpenGL, а сразу делать на Vulkan, потому что недавно (в начале июня этого года) OpenGL был объявлен deprecated на Mac и iOS в пользу Metal и Vulkan. Я думаю, это большой шаг к тому, что может пройти немного времени (может несколько лет или меньше) и тогда на остальных OC он тоже рано или поздно станет deprecated.
0
 Аватар для COKPOWEHEU
4082 / 2680 / 432
Регистрация: 09.09.2017
Сообщений: 11,900
28.06.2018, 15:17
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Ну да, сначала заменить квадраты на кубы, а потом можно будет .obj файл парсануть из бесплатного легковесного 3D-редактора Blender
Obj же не поддерживает скелетную анимацию. Не, если уж делать "реалистичную" змейку изменяемого размера, придется попотеть. С ходу даже идей нет как это делается. Ну, кроме процедурной генерации, конечно.
Вот для еды и ландшафта использовать готовые модельки вполне можно. Но, опять-таки, не спешите. Давайте идти последовательно. Мне понравился исходный код ТСа и я хочу помочь ему подняться хотя бы до своего уровня (на самом деле это немного). Но он говорил что сейчас занят, так что наберемся терпения и надеемся, что ему не надоест.
Хотя...

8Observer8, может, сами хотите поучаствовать в написании суперкрутой трехмерной змейки? Тогда можно набросать ТЗ с основными фичами... или сразу начать кодить.

Цитата Сообщение от 8Observer8 Посмотреть сообщение
Может даже имеет смысл потом не трогать OpenGL, а сразу делать на Vulkan
В принципе, попробовать можно. Не из-за apple'ов, конечно, но говорят что у vulkan выше производительность, хотя сам он сложнее. В любом случае, опробовать новую технологию будет интересно.
0
9037 / 2937 / 494
Регистрация: 05.10.2013
Сообщений: 7,962
Записей в блоге: 216
28.06.2018, 15:58
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Obj же не поддерживает скелетную анимацию. Не, если уж делать "реалистичную" змейку изменяемого размера, придется попотеть.
Я даже не думал про реалистичную змейку со скелетной анимацией. Я имел ввиду, например, заменить кубики из которых состоит змейки на что-то более интересное, что проще импортировать, чем делать программно, например, кубики заметить на сферы. Парсер из obj пишется один раз и применяется для импорта всех моделей. Зато в Blender'е можно сферы отредактировать как угодно, например, добавить шипы, быстренько набросал:
Название: SphereCell.png
Просмотров: 247

Размер: 13.7 Кб
0
 Аватар для COKPOWEHEU
4082 / 2680 / 432
Регистрация: 09.09.2017
Сообщений: 11,900
28.06.2018, 16:17
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Парсер из obj пишется один раз
Да парсер из obj вообще штука простая. Не так давно использовал его для вывода трехмерных моделек на 3.2" экран через stm32f103

0
9037 / 2937 / 494
Регистрация: 05.10.2013
Сообщений: 7,962
Записей в блоге: 216
28.06.2018, 19:28
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
https://www.youtube.com/watch?v=D9KuP8Q5qTM
Для вставки видео на форум нужно в тег YOUTUBE скопировать только то, что после "v=", иначе не будет рабоать.

Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Да парсер из obj вообще штука простая.
Один из вариантов парсера на Python, всего 53 строки кода. Можно легко перевести на C++, если автор темы решит потом изучать OpenGL, то следующий тутор может пригодится. Взято из тутора по GLFW + OpenGL 3+: Modern OpenGL programming in Python - part 15 - obj file format

youtube


ObjLoader.py
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import numpy as np
 
class ObjLoader:
    def __init__(self):
        self.vert_coords = []
        self.text_coords = []
        self.norm_coords = []
 
        self.vertex_index = []
        self.texture_index = []
        self.normal_index = []
 
        self.model = []
 
    def load_model(self, file):
        for line in open(file, 'r'):
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
 
            if values[0] == 'v':
                self.vert_coords.append(values[1:4])
            if values[0] == 'vt':
                self.text_coords.append(values[1:3])
            if values[0] == 'vn':
                self.norm_coords.append(values[1:4])
            if values[0] == 'f':
                face_i = []
                text_i = []
                norm_i = []
                for v in values[1:4]:
                    w = v.split('/')
                    face_i.append(int(w[0]) - 1)
                    text_i.append(int(w[1]) - 1)
                    norm_i.append(int(w[2]) - 1)
                self.vertex_index.append(face_i)
                self.texture_index.append(text_i)
                self.normal_index.append(norm_i)
 
        self.vertex_index = [y for x in self.vertex_index for y in x]
        self.texture_index = [y for x in self.texture_index for y in x]
        self.normal_index = [y for x in self.normal_index for y in x]
 
        for i in self.vertex_index:
            self.model.extend(self.vert_coords[i])
 
        for i in self.texture_index:
            self.model.extend(self.text_coords[i])
 
        for i in self.normal_index:
            self.model.extend(self.norm_coords[i])
 
        self.model = np.array(self.model, dtype = 'float32')
0
2 / 2 / 0
Регистрация: 08.06.2018
Сообщений: 66
29.06.2018, 19:49  [ТС]
COKPOWEHEU,
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Мне понравился исходный код ТСа и я хочу помочь ему подняться хотя бы до своего уровня (на самом деле это немного). Но он говорил что сейчас занят, так что наберемся терпения и надеемся, что ему не надоест.
Это большой комплимент,мне очень приятно.Спасибо))
Вчера все сдал и сейчас у меня несколько выходных,чуть позже дела еще кое-какие будут,но теперь я могу стабильно пару часов в день уделять этой теме,и приступаю уже сейчас)
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Загляните в документацию на curses, разберитесь как эти функции работают и прокомментируйте код.
Окей,будет сделано!

Добавлено через 13 минут
8Observer8,
Цитата Сообщение от 8Observer8 Посмотреть сообщение
у меня есть предложение, чтобы вы перевели свой код, например, на OpenGL. Окно можно создать с помощью SDL2. Сначала сделать в 2D, а дальше будет несложно перейти в 3D.
Нуу у меня много костылей и я бы предпочел под другую технологию(в данном случае под OpenGL)писать все заново,чтобы чистенько все сделать,да и я думаю пути другие можно будет найти,но вообще я планирую двигаться в эту сторону,но вот как я себе все это представляю:
1.Сначала я занимаюсь оптимизацией старого кода
2.Потом попробуем с товарищем COKPOWEHEU прикрутить сеть(если ему еще это интересно,а судя по всему интересно))
3.После этого плавно переходим к вопросу переноса на 2d графику opengl/dx/vulkan я еще не до конца все тут
понял,посмотрим что будет лучше
4.И тут перед вступлением в 3д я бы хотел склепать еще что нибудь по этой схеме для разогрева,какой-то тетрис или
любую простенькую аркаду(чтобы чувствовать себя чуть увереннее перед 3д)
5.И тут я бы приступил к 3д.
Короче-делать есть что,но я постараюсь быстренько до 3 пункта дойти и там уже начнется самое интересное)
0
 Аватар для COKPOWEHEU
4082 / 2680 / 432
Регистрация: 09.09.2017
Сообщений: 11,900
29.06.2018, 23:38
Интересное можно найти везде, в псевдографической версии тоже. Например, написание для той же змейки бота. Или просто составление кампании из ряда заготовленных карт с препятствиями, бонусами и пр. Или прикрутить консоль (да, к консольной программе!) чтобы вводить читы.
На счет 2Д и 3Д разница на самом деле невелика. В том смысле что OpenGL, DirectX и, возможно, Vulkan, не умеют работать в двумерном режиме. До DX7 (вроде) была отдельная библиотека DirectDraw, но сейчас ее, насколько я знаю, выпилили. Тем более что все что умела она, можно сделать и через трехмерку, причем иногда проще.
В принципе, сейчас у нас нет четкого ТЗ и плана работы, можем заниматься тем, что интересно в данный момент, благо на ту же змейку неплохо ложится большое количество технологий и идей, а значит из нее можно вырастить неплохую игрушку. И даже если не взлетит то хоть опыта наберемся.
0
2 / 2 / 0
Регистрация: 08.06.2018
Сообщений: 66
30.06.2018, 22:38  [ТС]
COKPOWEHEU,
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
из нее можно вырастить неплохую игрушку. И даже если не взлетит то хоть опыта наберемся.
Полностью согласен

Добавлено через 8 часов 24 минуты
Прокомментировал весь код,чуть занялся константами
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include <iostream>
#include <Windows.h>
#include <conio.h>
#include <ctime>
#include <fstream>
#include <iomanip>
 
using namespace std;
 
bool game_status;
const int fldwidth = 77, fldheight = 22,stime = 60;
char field[fldheight][fldwidth], shead, stail, msym, sdir, rkey, dir, ldir;
int lastposx[100], lastposy[100], hscore, coutr, length, score, shposx, shposy, mposx, mposy;//позиции выразить через костанты,намутить структур
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);//разобратся че это делает
unsigned int start_time = clock();//время
 
void set_food() {
    do
    {
        mposx = rand() % (fldwidth-4) + 2;//возле стенок очень просто подохнуть,поэтому костылем отнимаем 4ед(2 от правой стены/2 от левой(т.е.одна на символ стены,а вторая на пустой после стены-таким образом еда спавнится максимум за один символ от стены и меня никто не будет ругать за кривую механику поворота(заметка-попытатся починить потом)))
        mposy = rand() % (fldheight-4) + 2;//то же самое проделываем для нижней и верхней стенок
    } while (field[mposy][mposx] != ' ');//так мы избегаем спавна еды внутри змеи
    field[mposy][mposx] = msym;
}//создает еду на пустом рандомном месте
 
void move() {//функция постоянного движения
    field[lastposy[coutr - 1]][lastposx[coutr - 1]] = ' ';//затираем прошлые координаты
    field[0][0] = 201;//изза кривизны кода пропадает один уголок-этот костыль все чинит
    lastposx[coutr-1] = shposx;//двигаем по иксу
    lastposy[coutr-1] = shposy;//двигаем по игреку
    /*field[shposy][shposx] = ' ';*///уже не помню зачем я это делал,пока что убрал и вроде ничего не изменилось,пусть пока будет,а то вдруг баги какие-то появятся,если что-потом уберу
    switch (dir)//проверяем что ввел пользователь 
    {
    case 'L'://влево
        shposx -= 1;
        break;
    case 'R'://вправо
        shposx += 1;
        break;
    case 'D'://вниз
        shposy += 1;
        break;
    case 'U'://вверх
        shposy -= 1;
        break;
    }
    if (field[shposy][shposx] == stail)
        game_status = false;//если в координатах головы оказывается символ хвоста-заканчиваем игру
    if (shposx < 1 or shposx>75 or shposy<1 or shposy>20)
        game_status = false;//если координаты головы входят в стену-заканчиваем игру(можно было использовать способ выше,но делал это все в разное время,а сейчас лопатить код впадлу-учту на будущее
    if (shposx == mposx && shposy == mposy) {//если координаты головы и еды пересеклись
        ++score;//увеличиваем счет
        ++length;//увеличиваем длину
        set_food();//спавним новую еду,старая сама заменяется символом головы
    }
}
 
void init() {//функция инициализации
    ifstream in("highscore.txt");//подключаем файл с рекордом,если таковой имеется
    in >> hscore;//считываем рекорд
    in.close();//закрываем файл
    system("color 0f");//играем с цветами
    SetConsoleTextAttribute(hConsole, (WORD)((0 << 4) | 2));//играем с цветами
    srand(time(NULL));//считаем время
    game_status = true;//запускаем игру
    
    for (int i = 1; i < 21; ++i) {
        for (int j = 1; j < 76; ++j) {
            field[i][j] = ' ';
        }
    }//зарисовываем все пустотой 
    
    for (int i = 1; i < 21; ++i) {//стены вертикальные
        field[i][0] = 186;
    }
    for (int i = 1; i < 21; ++i) {//стены вертикальные
        field[i][76] = 186;
    }
    for (int i = 1; i < 76; ++i) {//стены горизонтальные
        field[0][i] = 205;
    }
    for (int i = 1; i < 76; ++i) {//стены горизонтальные
        field[21][i] = 205;
    }
    field[0][0] = 201;//углы
    field[0][76] = 187;
    field[21][76] = 188;
    field[21][0] = 200;
    score = 0;//счет
    shposx = 11;//первая позиция головы по иксу
    shposy = 11;//первая позиция головы по игреку
    coutr = 1;//счетчик
    length = 4;//стартовая длина
    dir = 'R';//стартовое направление
    ldir = 'R';//стартовое прошлое направление 
    msym = '*';//символ еды
    shead = '@';//символ головы
    stail = 'o';//символ хвоста
    set_food();
}
 
void update() {//функция обновления положения змеи
    move();
    if (_kbhit()) {//если была нажата клавиша
        rkey = _getch();//считываем ее
        sdir = static_cast<int>(rkey);//переводим
        ldir = dir;//перед тем как присвоить новое направление-сохраняем старое
        switch (sdir)//новое направление 
        {
        case 75://влево
            if (ldir != 'R')
            dir = 'L';
            break;
        case 77://вправо
            if (ldir != 'L')
            dir = 'R';
            break;
        case 80://вниз
            if (ldir != 'U')
            dir = 'D';
            break;
        case 72://вверх
            if (ldir != 'D')
            dir = 'U';
            break;
        }
    };
    field[shposy][shposx] = shead;//новое положение головы
    field[lastposy[coutr - 1]][lastposx[coutr - 1]] = 'o';//тут дальше сложная магия которая отрисовывает нам хвост и когда счетчик доходит до длины рисует новый хвост на 1ед длинне старого(только если длина увеличилась)
    if (length == coutr) {
        for (int i = 1; i <= length; ++i) {
            field[lastposy[coutr - i]][lastposx[coutr - i]] = 'o';
        }
    }
    if (coutr == length)
        coutr = 0;
    ++coutr;
}
 
void render() {//функция отображения поля с текущими параметрами
    for (int i = 0; i < 22; ++i) {
        for (int j = 0; j < 77; ++j) {
            if ((i == 0)or(i == 21)or(j == 0)or(j == 76)) {
                SetConsoleTextAttribute(hConsole, (WORD)((0 << 4) | 1));//играем с цветами для стен
                cout << field[i][j];
                SetConsoleTextAttribute(hConsole, (WORD)((0 << 4) | 2));//играем с цветами для змейки
            }
            else {
                if (field[i][j] == '*') {
                    SetConsoleTextAttribute(hConsole, (WORD)((0 << 4) | 12));//играем с цветами для еды
                    cout << field[i][j];
                    SetConsoleTextAttribute(hConsole, (WORD)((0 << 4) | 2));//играем с цветами для змейки
                }
                else {
                    cout << field[i][j];
                }
            }
        }
        cout << endl;
    }
    unsigned int end_time = clock();//считаем время-вообще нужно бы засунуть это в апдейт
    unsigned int search_time = end_time - start_time;
    SetConsoleTextAttribute(hConsole, (WORD)((0 << 4) | 7));//играем с цветами для счета
    cout << "SCORE:" << ' ' << score << ' ' << "Time:"<< ' ' << fixed << setprecision(2) << search_time/1000.0 << 's' << ' '<<"HIGHSCORE:" << ' ' << hscore;
    SetConsoleTextAttribute(hConsole, (WORD)((0 << 4) | 2));//возвращаем цвет змеи
    Sleep(stime);//спим для плавности картинки
    system("cls");//чистим экран
}
 
int main() {//мейн
    init();//инициализируем
    while (game_status) {//пока идет игра
        update();//обновляем
        render();//рисуем
    }
    if (score > hscore) {//в конце игры проверяем побили ли мы рекорд/засунуть бы это все в функцию,а то не красиво
        hscore = score;
        ofstream out("highscore.txt");
        out << hscore;
        out.close();
    }
    return 0;//кАнец
}//заметка-сделать функцию рестарта
0
 Аватар для COKPOWEHEU
4082 / 2680 / 432
Регистрация: 09.09.2017
Сообщений: 11,900
01.07.2018, 08:49
Цитата Сообщение от anton3d Посмотреть сообщение
Прокомментировал весь код,чуть занялся константами
Я ожидал что вы прокомментируете мой код заготовки ncurses
Цитата Сообщение от anton3d Посмотреть сообщение
//создает еду на пустом рандомном месте
Обычно комментарий о назначении функции пишется перед ней:
C
1
2
3
4
5
/*создает еду в случайной точке на расстоянии не менее 2 клеток от стен
Входные параметры: нет
Возвращаемое значение: нет
*/
void set_food(){
С комментированием вы перестарались. Как я уже говорил, ваш код из 1-го поста достаточно простой и понятный, он почти не нуждается в комментариях.
Важный момент который вы упустили: комментировать надо не то КАК работает код, а ЧТО он делает.
Цитата Сообщение от anton3d Посмотреть сообщение
++score;//увеличиваем счет
Здесь комментарий только создает визуальный шум.
Цитата Сообщение от anton3d Посмотреть сообщение
for (int i = 1; i < 21; ++i) {//стены вертикальные
А если размер консоли меньше чем 76х21 ?
Цитата Сообщение от anton3d Посмотреть сообщение
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);//разобратся че это делает
При запуске консольной программы windows создает окно эмулятора терминала, с заголовком, кнопками и прочим. Добропорядочная консольная программа об этом старательно не знает, ей должно быть безразлично как именно происходит ввод и вывод - через эмулятор терминала, через железный терминал (vt100, например), перенаправляется другим программам или в файл (перенаправление ввода-вывода prog.exe > file.txt). Но некоторые консольные программы пытаются узнать подробности. Ваша программа запрашивает идентификатор окна эмулятора терминала, чтобы обмениваться с ним оконными сообщениями. И все это всего лишь для изменения цвета и позиции курсора.
В линуксовом эмуляторе терминала это сделано более тонко и без нарушения консольной идеологии. Для управления параметрами терминала используются ESC-последовательности - непечатаемые наборы байт, передаваемые точно так же, как обычный текст.
Например, printf("\033[5;32;44m AAA \033[0m\n"); выводит AAA мигающим (5) зеленым цветом (32) синем фоне (44). Обратите внимание что работа идет обычными терминальными командами. Причем команды у разных типов терминалов могут отличаться.
Так вот, ncurses предназначена для кроссплатформенной работы с консолью, независимо от того какой именно используется. Если надо то используются и костыли вроде GetStdHandle, если нет - консольные команды.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
01.07.2018, 08:49
Помогаю со студенческими работами здесь

Прошу вашей критики
Народ, всем привет, в общем я только начал изучать верстку. Взял шаблон вот тут: Хотел сделать резиновую верстку, но остановился...

Прошу критики и рекомендаций
Уважаемые форумчане! Выношу на ваш суд свою БД. Раньше я никогда не занималась созданием баз, но рискнула взять на себя такую...

Прошу критики от профессионалов...
Все время работал с классическим html, но решил попробовать блогинг. Создал блог 29 января 2012 - сами видите-еще зародыш, но не успел...

Прошу критики моего списка
Я написал код, но я новичок, уверен, что в нем есть косяки. Например, как написать список, чтобы по нему можно было пройтись циклом...

Прошу критики веб-дизайна
Занимаюсь самообучением веб-дизайну. Хочу услышать адекватную критику и советы. Знаю, что еще очень многое не умею, но хотелось бы...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Новый CodeBlocs. Версия 25.03
palva 04.01.2026
Оказывается, недавно вышла новая версия CodeBlocks за номером 25. 03. Когда-то давно я возился с только что вышедшей тогда версией 20. 03. С тех пор я давно снёс всё с компьютера и забыл. Теперь. . .
Модель микоризы: классовый агентный подход
anaschu 02.01.2026
Раньше это было два гриба и бактерия. Теперь три гриба, растение. И на уровне агентов добавится между грибами или бактериями взаимодействий. До того я пробовал подход через многомерные массивы,. . .
Учёным и волонтёрам проекта «Einstein@home» удалось обнаружить четыре гамма-лучевых пульсара в джете Млечного Пути
Programma_Boinc 01.01.2026
Учёным и волонтёрам проекта «Einstein@home» удалось обнаружить четыре гамма-лучевых пульсара в джете Млечного Пути Сочетание глобально распределённой вычислительной мощности и инновационных. . .
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru