Комментарии 6
Я просто хотел разобраться как работать с make и gcc и для примера решил написать змейку в консоли ¯_(ツ)_/¯
Ну, ога. У тебя тут один файл. Зачем нужен make?
Буду рад конструктивной критике.
Нормально получилось, есть места, где читатель может сам додумать как и что написать, а не просто скопипастить код.
Другое дело, что рассказ о том как вы писали игру для платформы Windows (см. вызываются специфические функции Win32), но почему-то указан тег "makefile" и вообще упомянуты make и gcc (которые больше ассоциируются с unix`ами), тогда как о виндовом характере программы в статье ни слова (только хаб сверху указан).
Упоминание про make и gcc вообще спокойно можно убрать из статьи - хуже не будет, тем более вы ничего про него не поясняете.
Если хотите и дальше немного экспериментировать с играми в консоли, как вариант, можете обратить внимание на функцию toupper()
из стандартной сишной библиотеки, чтобы вот такое не городить:
case 'W':
case 'w':
{
if (snakeLV == 'S' || snakeLV == 's') // защита от дурака
В среднем выглядит неплохо, если оно работает. А так
COORD *nSnake = (COORD *)realloc(Snake, snakeSize * sizeof(COORD));
учитывая, что действо происходит в терминале кажется достаточно выделить один буфер размером в терминал и больше не реаллоцировать змея. Заодно можно обойтись циклическим буфером - на одной итерации без еды и исчезает один хвост: держим массив с индексом координаты головы. На рендере змеи просто от координаты головы отсчитываем длину змея в обратную сторону.
[a b c _ _ _ _ _ _ _ _ _] len 3 head 2 # змейка на три клетки
[a b c d _ _ _ _ _ _ _ _] len 3 head 3 # змейка двинулась на клетку d
[a b c d e _ _ _ _ _ _ _] len 4 head 4 # змейка съела яблоко в клетке e
...
[a b c d e f g h a _ _ _] len 4 head 8 # голова в точке где когда-то был хвост
...
[l b c d e f g h a i j k] len 4 head 0 # змейка в координатах lkji
В реальности буффер будет наверное размером в терминал, то бишь что-нибудь в районе 30х140 ~ 4k+ элементов, так что до края голова доберётся не скоро.
if (true) var = true
это все же антипаттерн, мешающий читать код.
if (Snake[0].X == W || Snake[0].X == 0)
{
isGameEnd = TRUE; // укусила боковые границы
}
if (Snake[0].Y == H || Snake[0].Y == 0)
{
isGameEnd = TRUE; // укусила нижнюю или верхнюю границы
}
У вас есть возможность сложить это в меньшее количество строк, просто переназначив значение через оператор |=
. Ну и копипастить каждый раз тоже снижает читаемость: т.к. у вас в этом месте код не меняется обращение по индексу можно вынести в одну переменную.
const COORD* head = &Snake[0]; // чтобы не копипастить индекс каждый раз
isGameEnd |= head->X == W || head->X == 0; // укусила боковые границы
isGameEnd |= head->Y == H || head->Y == 0; // укусила нижнюю или верхнюю границы
for (int i = 1; i < snakeSize; i++)
{
// укусила себя
isGameEnd |= head->X == Snake[i].X
&& head->Y == Snake[i].Y;
}
[Hello, Habr!] Змейка в консоли. Разбираемся с с make и gcc