Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
vsglhs
0 / 0 / 0
Регистрация: 25.07.2019
Сообщений: 2
1

Нужна конструктивная критика

25.07.2019, 19:38. Просмотров 324. Ответов 5
Метки нет (Все метки)

Добрый день, форумчане. Я только сегодня начал проходить ООП. С указателями еще не подружился.
Если можно, вы можете указать на ошибки, которые я допустил при написании простенькой змейки, а так же оценить насколько такой код приемлем в общем(нормально ли он написан).
И не могли бы вы еще подсказать на счет мигания экрана во время работы змейки. Не могу понять почему так происходит.
Заранее спасибо!
Змейка в трех файлах:

Main.cpp
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
 #include "Snake.h"
#include <iostream>
 
void SLEEP(int TIME); // Задержка изображения на экране
void CLEAR(); // Очищение экрана
 
void GAME_LOOP()
{
    SNAKE_DRAW OBJECT; // Самый нижний объект иерархии
 
    bool IS_OPEN = true;
    int TIME = 100;
 
    OBJECT.COORD_DEFAULT(); // Начальные координаты змейки
    OBJECT.DEFAULT_FOOD(); // Начальные координаты еды
    OBJECT.DISPLAY(); // Начальный вывод
    OBJECT.DEFAULT_DIRECTION(); // Программа ждет нажатия первой кнопки
 
    while (IS_OPEN)
    {
        CLEAR(); // Очищение экрана
        OBJECT.GET_DIRECTION(); // Получение направления движения змейки
        OBJECT.HEAD_MOVEMENT(OBJECT.RETURN_DIRECTION()); // Передвижение Х и У
        OBJECT.TAIL_COPY(); // Копирование хвоста змейки (на случай создания, если она съест еду)
        OBJECT.ETC_MOVEMENT(); // Движение всей змейки, кроме головы
        OBJECT.HEAD_COORD(); // Присвоение координат Х и У к первому элементу змейки
        OBJECT.CHECK_CRASH(); // Смотрим, не врезалась ли змейка в саму себя
        OBJECT.ATE(); // Не съела ли змейка еду
        OBJECT.IS_INCREASE(); // Если съела, то растет
        OBJECT.IS_SET(); // Если еда съедена, то ставим новую
        OBJECT.DISPLAY(); // Вывод змейки и еды на экран
        SLEEP(TIME); // Задержка в 100 миллисекунд
    }
}
 
int main()
{
    GAME_LOOP();
 
    system("pause");
    return 0;
}
Snake.cpp
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#include "Snake.h"
#include <iostream>
#include <Conio.h>
#include <Windows.h>
#include <ctime>
 
void SLEEP(int TIME)
{
    Sleep(TIME);
}
 
void CLEAR()
{
    system("cls");
}
 
void SNAKE::COORD_DEFAULT() // Начальные координаты змейки
{
    X = 3;
    Y = 1;
    X_COORD[0] = 3;
    X_COORD[1] = 2;
    X_COORD[2] = 1;
    Y_COORD[0] = 1;
    Y_COORD[1] = 1;
    Y_COORD[2] = 1;
}
 
void DIRECTION::GET_DIRECTION() // Получение направления движения змейки
{
    if (_kbhit()) // Если нажата клавиша,
    {
        switch (_getch()) // То считываем значение ключа
        {
        case 119: if (BUFFER_DIR != DOWN)  DIR = UP;    break; // Условные операторы чтобы змейка через себя не проходила
        case 115: if (BUFFER_DIR != UP)    DIR = DOWN;  break;
        case 97:  if (BUFFER_DIR != RIGHT) DIR = LEFT;  break;
        case 100: if (BUFFER_DIR != LEFT)  DIR = RIGHT; break;
        }
        BUFFER_DIR = DIR;
    }
    else DIR = BUFFER_DIR;
}
 
int DIRECTION::RETURN_DIRECTION() // Просто возвращаем значение направления
{
    return DIR;
}
 
void DIRECTION::DEFAULT_DIRECTION() // Начальный выбор направления движения змейки
{
    switch (_getch())
    {
    case 119: DIR = UP; break;
    case 115: DIR = DOWN; break;
    case 100: DIR = RIGHT; break;
    default: DEFAULT_DIRECTION(); break;
    }
    BUFFER_DIR = DIR;
}
void MOVEMENT::IS_BROAD() // Проверка выхода змейки за границу карты
{
    if (X > (MAX_MAP_SIZE - 1)) X = 0;
    if (X < 0) X = MAX_MAP_SIZE - 1;
    if (Y > (MAX_MAP_SIZE - 13)) Y = 0;
    if (Y < 0) Y = MAX_MAP_SIZE - 13;
}
 
void MOVEMENT::HEAD_MOVEMENT(int DIR) // Непосредственно изменение координат Х и У
{
    switch (DIR)
    {
    case UP: Y--; break;
    case DOWN: Y++; break;
    case LEFT: X--; break;
    case RIGHT: X++; break;
    }
    IS_BROAD();
}
 
void MOVEMENT::TAIL_COPY() // Копирование хвоста змейки
{
    X_BUFFER = X_COORD[SNAKE_SIZE];
    Y_BUFFER = Y_COORD[SNAKE_SIZE];
}
 
void MOVEMENT::HEAD_COORD() // Присвоение первому элементу змейки значений Х и У
{
    X_COORD[0] = X;
    Y_COORD[0] = Y;
}
 
void MOVEMENT::ETC_MOVEMENT() // Изменение координат всего тела змейки, кроме перового элемента
{
    for (int i = MAX_SNAKE_SIZE - 1; i > 0; i--)
    {
        X_COORD[i] = X_COORD[i - 1];
        Y_COORD[i] = Y_COORD[i - 1];
    }
}
 
void INCREASE::SNAKE_INCREASE() // Рост змейки
{
    X_COORD[SNAKE_SIZE + 1] = X_BUFFER;
    Y_COORD[SNAKE_SIZE + 1] = Y_BUFFER;
}
 
bool SNAKE_DRAW::SNAKE_CHECK(int x, int y) // Проверка: есть ли в этой точке змейка
{
    bool IS_CHECKED = false;
    for (int i = 0; i < SNAKE_SIZE; i++) if ((X_COORD[i] == x) && (Y_COORD[i] == y)) { IS_CHECKED = true; break; }
    return IS_CHECKED;
}
 
bool SNAKE_DRAW::FOOD_CHECK(int x, int y) // Проверка: есть ли в этой точке еда
{
    bool IS_CHECKED = false;
    if ((X_FOOD == x) && (Y_FOOD == y)) IS_CHECKED = true;
    return IS_CHECKED;
}
 
void SNAKE_DRAW::COORD_DISPLAY(int x, int y) // Проверка: какой символ нужно напечатать
{
    if (SNAKE_CHECK(x, y) == true) std::cout << SNAKE_SYM; else
        if (FOOD_CHECK(x, y) == true) std::cout << '@'; else std::cout << ' ';
}
 
void SNAKE_DRAW::DISPLAY() // Непосредственно сам вывод на экран
{
    for (int y = 0; y < MAX_MAP_SIZE - 12; y++)
    {
        for (int x = 0; x < MAX_MAP_SIZE; x++) COORD_DISPLAY(x, y);
        std::cout << std::endl;
    }
}
 
bool EATING::IS_EAT() // Съедено ли
{
    if (IS_EATING == true) { IS_EATING = false; return true; } else return false;
}
 
bool EATING::IS_PUT() // Поставлена ли еда
{
    if (IS_PUTTING == false) { IS_PUTTING = true; return true; } else return false;
}
 
void INCREASE::IS_INCREASE() // Если еда съедена, то растем
{
    if (IS_EAT() == true) { SNAKE_INCREASE(); SNAKE_SIZE++; IS_PUTTING = false; }
}
 
void EATING::ATE() // Проверка на съедение еды
{
    if ((X_FOOD == X) && (Y_FOOD == Y)) IS_EATING = true;
}
 
void FOOD_PUT::IS_SET() // Если еда не поставлена, то ставим ее
{
    if (IS_PUT() == true) { FOOD_SET(); IS_PUTTING = true; }
}
 
void FOOD_PUT::FOOD_SET() // Рандомная генерация координат еды и проверка: задевает ли она змейку. Если да, то все по новой
{
    srand(time(NULL));
 
    bool IS_OPEN = true;
    int COUNTER;
 
    while (IS_OPEN)
    {
        COUNTER = 0;
        X_FOOD = 0 + rand() % (MAX_MAP_SIZE - 1);
        Y_FOOD = 0 + rand() % (MAX_MAP_SIZE - 13);
 
        for (int i = 0; i < SNAKE_SIZE; i++)
            if ((X_FOOD != X_COORD[i]) || (Y_FOOD != Y_COORD[i])) COUNTER++;
        
        if (COUNTER == SNAKE_SIZE) IS_OPEN = false;
    }
}
 
void EATING::DEFAULT_FOOD() // Начальные координаты еды
{
    X_FOOD = 7;
    Y_FOOD = 9;
}
 
bool MOVEMENT::SNAKE_CRASH() // Разбилась ли змейка
{
    bool CRASHED = false;
 
    for (int i = 1; i < SNAKE_SIZE; i++) 
        if ((X == X_COORD[i]) && (Y == Y_COORD[i]))
        {
            CRASHED = true;
            break;
        }
    return CRASHED;
}
 
void MOVEMENT::CHECK_CRASH() // Если разбилась, то выходим
{
    if (SNAKE_CRASH() == true) exit(0);
}
Snake.h
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
#ifndef SNAKE_H
#define SNAKE_H
 
class SNAKE
{
public:
    const int MAX_MAP_SIZE = 24;
protected:
    static const int MAX_SNAKE_SIZE = 64;
 
    int SNAKE_SIZE = 3;
    int X, Y;
    int X_COORD[MAX_SNAKE_SIZE];
    int Y_COORD[MAX_SNAKE_SIZE];
    char SNAKE_SYM = '*';
public:
    void COORD_DEFAULT();
};
 
class DIRECTION : public SNAKE
{
 
protected:
    enum DIRECTIONS { UP, LEFT, DOWN, RIGHT } DIR, BUFFER_DIR;
public:
    void GET_DIRECTION();
    int RETURN_DIRECTION();
    void DEFAULT_DIRECTION();
};
 
class MOVEMENT : public DIRECTION
{
private:
    void IS_BROAD();
    bool SNAKE_CRASH();
protected:
    int X_BUFFER;
    int Y_BUFFER;
public:
    void HEAD_MOVEMENT(int DIR);
    void TAIL_COPY();
    void HEAD_COORD();
    void ETC_MOVEMENT();
    void CHECK_CRASH();
};
 
class EATING : public MOVEMENT
{
protected:
    bool IS_EATING = false;
    bool IS_PUTTING = true;
    int X_FOOD;
    int Y_FOOD;
 
    bool IS_EAT();
    bool IS_PUT();
public:
    void DEFAULT_FOOD();
    void ATE();
};
 
class FOOD_PUT : public EATING
{
private:
    void FOOD_SET();
public:
    void IS_SET();
};
 
class INCREASE : public FOOD_PUT
{
private:
    void SNAKE_INCREASE();
public:
    void IS_INCREASE();
};
 
class SNAKE_DRAW : public INCREASE
{
private:
    bool SNAKE_CHECK(int x, int y);
    bool FOOD_CHECK(int x, int y);
    void COORD_DISPLAY(int x, int y);
public:
    void DISPLAY();
};
 
void SLEEP(int TIME);
void CLEAR();
 
#endif // SNAKE_H
P.S.: Прошу прощение за столь малое количество комментариев. Не смог нормально дописать, т.к. уже 2.30 ночи. Еле дописал этот пост.
0
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
25.07.2019, 19:38
Ответы с готовыми решениями:

Нужна конструктивная критика по оформлению и читабельности кода (Game Trainer C++)
Относительно недавно начал изучать C++. Для обучения решил написать трейнер попутно изучая...

Нужна конструктивная критика: советы, замечания по заданному фрагменту кода
Есть входные данные, которые я кладу в вектор 5 1 2 3 4 5 Ваша критика #include...

Нужна конструктивная критика: удалось ли мне уловить хоть частицу ООП в моём проекте?
Добрый день, дорогие форумчане. Меня, как и многих, волнует мое будущее, и поэтому же меня волнует...

Собственная реализация паттерна "Слушатель" - нужна конструктивная критика
Добрый день, наворотил код по работе с паттерном слушатель - есть класс контейнер данных и при...

Требуется конструктивная критика
Я не волшебник, только учусь. Для обучения выбрал алгоритм поиска пути A*. Вот собственно моя...

5
zayats80888
2261 / 1341 / 557
Регистрация: 07.02.2019
Сообщений: 3,585
25.07.2019, 19:42 2
Цитата Сообщение от vsglhs Посмотреть сообщение
нормально ли он написан
Не вникая в суть, первое что бросается в глаза - все имена прописными буквами. Так не принято, прописными принято именовать макросы.
1
Andrey B
167 / 120 / 60
Регистрация: 06.02.2015
Сообщений: 300
Завершенные тесты: 1
25.07.2019, 20:14 3
Не вижу конструктора и деструктора. Про них не стоит забывать. Здесь может и не нужно, но в другом..
Дело вкуса, но мне код в таком виде читать тяжело
1
oleg-m1973
1859 / 1294 / 522
Регистрация: 07.05.2019
Сообщений: 4,172
Записей в блоге: 1
25.07.2019, 21:48 4
Цитата Сообщение от vsglhs Посмотреть сообщение
Добрый день, форумчане. Я только сегодня начал проходить ООП. С указателями еще не подружился.
Смотрю, сразу с Бейсика решил перескочить на С++. Похвально, но лучше начинать с каких-нибудь более простых задач.

Цитата Сообщение от vsglhs Посмотреть сообщение
И не могли бы вы еще подсказать на счет мигания экрана во время работы змейки. Не могу понять почему так происходит.
Ну так ты сначала очищаешь экран, потом ждёшь нажатия клавиши
Цитата Сообщение от vsglhs Посмотреть сообщение
CLEAR(); // Очищение экрана
* * * * OBJECT.GET_DIRECTION(); // Получение направления движения змейки
1
vsglhs
0 / 0 / 0
Регистрация: 25.07.2019
Сообщений: 2
26.07.2019, 10:18  [ТС] 5
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Смотрю, сразу с Бейсика решил перескочить на С++. Похвально, но лучше начинать с каких-нибудь более простых задач.
Я с Бейсиком не знаком. С программированием (в школе паскаль проходили, а там уже с++ заинтересовался) познакомился 2 года назад, но через пару месяцев забросил из-за определенных проблем. Сейчас снова начинаю писать.
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Ну так ты сначала очищаешь экран, потом ждёшь нажатия клавиши
Я попробовал переставить и так, и сяк, но практически не получилось исправить...
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
while (IS_OPEN)
    {
        CLEAR(); // Очищение экрана
        OBJECT.DISPLAY(); // Вывод змейки и еды на экран
        SLEEP(TIME); // Задержка в 100 миллисекунд
        OBJECT.GET_DIRECTION(); // Получение направления движения змейки
        OBJECT.HEAD_MOVEMENT(OBJECT.RETURN_DIRECTION()); // Передвижение Х и У
        OBJECT.TAIL_COPY(); // Копирование хвоста змейки (на случай создания, если она съест еду)
        OBJECT.ETC_MOVEMENT(); // Движение всей змейки, кроме головы
        OBJECT.HEAD_COORD(); // Присвоение координат Х и У к первому элементу змейки
        OBJECT.CHECK_CRASH(); // Смотрим, не врезалась ли змейка в саму себя
        OBJECT.ATE(); // Не съела ли змейка еду
        OBJECT.IS_INCREASE(); // Если съела, то растет
        OBJECT.IS_SET(); // Если еда съедена, то ставим новую
    }
Я нашел функцию SetConsoleCursorPosition. С ней мерцания полностью ушли.

И еще вопрос про организацию иерархии классов. Я хотел реализовать несколько иначе.
Что-то по типу:
1. Змея:
1.1. Передвигается:
1.1.1. Двигает свое тело
1.1.2. Изменяет направление движения
1.2. Ест:
1.2.1 Растет
1.2.2 Размещает еду
1.3. Рисует себя
1.3.1 Рисует голову ( символ головы хотел сделать в зависимости от направления движения )
1.3.2 Рисует остальное тело
Но не получилось, т.к. не знаю как можно получить доступ к методу из пункта 1.2 в метод в пункте 1.1. В итоге получилась, на мой взгляд, не очень хорошая иерархическая лесенка.
0
oleg-m1973
1859 / 1294 / 522
Регистрация: 07.05.2019
Сообщений: 4,172
Записей в блоге: 1
26.07.2019, 10:47 6
Цитата Сообщение от vsglhs Посмотреть сообщение
Я попробовал переставить и так, и сяк, но практически не получилось исправить...
Обычно для этого используется двойной буфер - нувую картинку рисуешь не на экране, а в буфере. Потом выводишь этот буфер не экран, поверх старого изображения.
Цитата Сообщение от vsglhs Посмотреть сообщение
Но не получилось, т.к. не знаю как можно получить доступ к методу из пункта 1.2 в метод в пункте 1.1. В итоге получилась, на мой взгляд, не очень хорошая иерархическая лесенка.
Ну да не очень - Движение наследуется от Змеи. Это как вообще? Скорее надоборот - Змея должна наследоваться от всех этих классов.
Хотя, я бы не заморачивался и сделал один класс - Змея, всё остальное движение, еда, рост и т.д. - его методы
1
26.07.2019, 10:47
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
26.07.2019, 10:47

Поиск популярного триплета. Конструктивная критика
Добрый день. Недавно помогал решать задачу про триплеты, и захотелось услышать критики по своему...

Разработал класс Money денежного счета, нужна критика и совет с функцией
Доброго времени суток! Очень прошу помоши, прошу бегло взглянуть на мой гавнокод и посоветовать, до...

[Нужна критика] Как правильно копировать объект-потомок по ссылке\указателю на родителя? + Пара мелких уточнений
Захотелось провести эксперимент и создать функцию для работы с обёрткой массива на стеке. Функция...


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

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.