Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.72/76: Рейтинг темы: голосов - 76, средняя оценка - 4.72
208 / 95 / 15
Регистрация: 27.07.2018
Сообщений: 323

Что изучать для совершенствования знаний по C++

08.11.2018, 09:25. Показов 21502. Ответов 361

Студворк — интернет-сервис помощи студентам
Изучил уже до ООП, вопрос что делать дальше? Могу ли я уже писать программы, с чего начинать?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
08.11.2018, 09:25
Ответы с готовыми решениями:

Что изучать после получения базовых знаний по c#
В каком направлении дальше двигаться? Или попытаться устроиться стажером для начала? А там дальше скажут в каком направлении двигаться...

Какой язык и технологию изучать после получения средних знаний
Здравствуйте! Я сейчас в 9 классе, буду поступать в техникум...Хорошие знания C#.NET, LINQ, ADO.NET, скоро буду начинать учить ASP.NET, и...

Ссылки для изучения и совершенствования
Ha всякий случай, несколько ссылок, больше на Rutracker. He знаю других трекеров c поиском в этих категориях. Темы c наибольшим спросом...

361
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,135
Записей в блоге: 243
13.12.2018, 11:03
Студворк — интернет-сервис помощи студентам
Я нашёл эту задачу, вбив в гугле название задачи: codewars sum of a sequence. Надо же, легко нашлось. Вот эта задача: https://www.codewars.com/kata/... /train/cpp

Первое, что я увидел на твоём скриншоте - красная рамка вокруг результатов прохождения тестов. Это говорит о том, что есть какая-то проблема.

Второе - надпись: "Time: 1778 ms". Это почти две секунды на выполнение тестов, а это очень много. Это может говорить от том, что твой алгоритм работает слишком долго.

Третье - надпись: "Exit Code: 132". Я не знал, что это означает, поэтому просто вбил в гугле: exit code 132 codewars. Я нашёл, что это "Segfault", то есть Segmentation Fault. А это уже знакомо, потому что практически все с этим сталкивались. Это ошибка возникает при пропытке записи или чтения данных, к которым у программы нет доступа. Например, если у тебя массив из 10 элементов, а ты пытаешься записать по индексу за пределом массива: arr[1001] = 123; Либо когда указатель указывает на то, что он не должен указывать и ты пытаешься либо прочитать данные, на которые указывает указатель, либо пытаешься записать данные, куда указывает указатель.

Теперь вопрос: почему у тебя возникает "Segfault"? Ведь ты не используешь ни массивов, ни указателей. Ошибка связана с тем, что ты сам добавил дополнительный параметр в функцию. Я позже попробую у себя. Сейчас нужно поправить, чтобы было так:
C++
1
2
3
4
5
6
7
8
int sequenceSum(int start, int end, int step)
{
    int sum = 0;
 
    // ...
 
    return sum;
}
0
 Аватар для COKPOWEHEU
4150 / 2728 / 433
Регистрация: 09.09.2017
Сообщений: 12,087
13.12.2018, 13:31
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Например, если у тебя массив из 10 элементов, а ты пытаешься записать по индексу за пределом массива: arr[1001] = 123;
А самое противное, что такие ошибки не всегда вызывают segfault. Если выход всего на пару элементов за пределы дозволенного, С/С++ и слова не скажут, просто будут молча затирать посторонние данные.
Один из самых мерзких классов ошибок.
1
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,135
Записей в блоге: 243
13.12.2018, 15:45
CyberGame, не пояснишь, что ты хотел сделать, когда добавил дополнительный параметр в функцию?

В первоначальном виде заготовка функции была такая:
C++
1
2
3
4
int sequenceSum(int start, int end, int step)
{
    return 0;
}
Задача: https://www.codewars.com/kata/... /train/cpp

Зачем ты добавил четвёртый параметр поумолчанию:

Кликните здесь для просмотра всего текста
0
60 / 45 / 15
Регистрация: 06.03.2018
Сообщений: 202
13.12.2018, 16:34
Цитата Сообщение от CyberGame Посмотреть сообщение
и не знаю что делать, ччто изучать и т.д.
Хватит изучать. Начинай писать. Как столкнешся с проблемами сразу поймешь что изучать дальше.
сори... не заметил что это давняя история...
1
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,135
Записей в блоге: 243
13.12.2018, 18:26
Цитата Сообщение от galeks1 Посмотреть сообщение
Хватит изучать. Начинай писать. Как столкнешся с проблемами сразу поймешь что изучать дальше.
Полностью поддерживаю. Программист - это писатель. Самое интересное в том, чтобы наблюдать, как твоё творение под твоими руками развивается, растёт, иногда болеет, чихает, теряет сознание, а ты лечишь и т.д. В этом и есть большое кайф программирования развивать свою программу, делать её всё более красивой и удобной.

CyberGame, ты плохо понимаешь как работает змейка, потому что ты не прокручиваешь время от времени код, как она работает. Не читаешь документацию по непонятным командам. Не пытаешься развивать. Не составляешь список, того, что можно добавить или изменить. Но ещё что плохо, то что весь код в функции main. Нужно будет растащить его на небольшие файлы. Я подумаю, как это лучше сделать.

Как добавить генерацию новой еды в случайном месте в момент поедания еды змейкой. Бедём крайний код из сообщения #222

Сейчас еда хранится в списке std::list. Удаляем список с едой
C++
1
list<Vector2i> foods;
А вместо списка пишем:
C++
1
Vector2i food;
Дальше увидешь по коду.

Давай по очереди что-то добавлять. Сделай чтобы счёт (Score) увеличивался, когда съедается еда.

Название: Snake.gif
Просмотров: 112

Размер: 25.6 Кб

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
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
205
206
207
208
209
210
211
212
213
214
215
216
//#include <irrKlang.h>
//using namespace irrklang;
//ISoundEngine *soundEngine = createIrrKlangDevice();
//soundEngine->play2D("Audio/background.mp3", true);
//soundEngine->setSoundVolume(0.5f);
 
 
#include <GL/freeglut.h>
 
#include <iostream>
#include <string>
#include <list>
using namespace std;
 
int lives = 3;
int score = 0;
 
const int gameFieldSize = 20;
 
int fieldWidth = 260;
int fieldHeight = 260;
 
struct Color3f
{
    float r = 0.5f;
    float g = 0.5f;
    float b = 0.5f;
};
 
struct Vector2i
{
    int x, y;
};
 
Vector2i snakeDir{ 1, 0 };
 
list<Vector2i> snake;
Vector2i food;
 
void drawText(float x, float y, string text)
{
    glColor3f(1.0f, 1.0f, 1.0f);
 
    glRasterPos2f(x, y);
    glutBitmapString(GLUT_BITMAP_8_BY_13, (const unsigned char*)text.c_str());
}
 
void drawSquare(int x, int y, int size, Color3f color)
{
    const float padding = 0.1f;
 
    glColor3f(color.r, color.g, color.b);
 
    glBegin(GL_QUADS);
    glVertex2f(x + padding, y + padding);
    glVertex2f(x + size - padding, y + padding);
    glVertex2f(x + size - padding, y + size - padding);
    glVertex2f(x + padding, y + size - padding);
    glEnd();
}
 
void drawFood()
{
    Color3f foodColor;
    foodColor.r = 0.0f;
    foodColor.g = 0.5f;
    foodColor.b = 0.5f;
    drawSquare(food.x, food.y, 1, foodColor);
}
 
void drawSnake()
{
    Color3f snakeColor;
    snakeColor.r = 0.0f;
    snakeColor.g = 1.0f;
    snakeColor.b = 0.0f;
    for (auto const& cell : snake)
    {
        drawSquare(cell.x, cell.y, 1, snakeColor);
    }
}
 
void drawRectangle(float x, float y, float width, float height)
{
    glBegin(GL_QUADS);
    glVertex2f(x, y);
    glVertex2f(x + width, y);
    glVertex2f(x + width, y + height);
    glVertex2f(x, y + height);
    glEnd();
}
 
void draw()
{
    glClear(GL_COLOR_BUFFER_BIT);
    drawText(0, 19, "Score: " + to_string(score));
    drawText(15, 19, "Lives: " + to_string(lives));
 
    drawFood();
    drawSnake();
 
    glutSwapBuffers();
}
 
int getRandomInt(int max)
{
    return rand() % max;
}
 
void update(int value)
{
    Vector2i newPos;
    newPos.x = snake.front().x + snakeDir.x;
    newPos.y = snake.front().y + snakeDir.y;
    snake.push_front(newPos);
    snake.pop_back();
 
    int xHead = snake.front().x;
    int yHead = snake.front().y;
 
    if (xHead == food.x && yHead == food.y)
    {
        Vector2i cell = { food.x, food.y };
        snake.push_back(cell);
 
        // Generate a new food
        food.x = getRandomInt(gameFieldSize);
        food.y = getRandomInt(gameFieldSize);
    }
 
    glutTimerFunc(250, update, 0);
    glutPostRedisplay();
}
 
void specialKeyHandler(int key, int x, int y)
{
    switch (key)
    {
        case GLUT_KEY_UP:
            snakeDir.x = 0;
            snakeDir.y = 1;
            break;
        case GLUT_KEY_LEFT:
            snakeDir.x = -1;
            snakeDir.y = 0;
            break;
        case GLUT_KEY_DOWN:
            snakeDir.x = 0;
            snakeDir.y = -1;
            break;
        case GLUT_KEY_RIGHT:
            snakeDir.x = 1;
            snakeDir.y = 0;
            break;
        default:
            cout << "This key is not used: " << key << endl;
            break;
    }
}
 
void normalKeyHandler(unsigned char key, int x, int y)
{
    switch (key)
    {
        case 'w':
            snakeDir.x = 0;
            snakeDir.y = 1;
            break;
        case 'a':
            snakeDir.x = -1;
            snakeDir.y = 0;
            break;
        case 's':
            snakeDir.x = 0;
            snakeDir.y = -1;
            break;
        case 'd':
            snakeDir.x = 1;
            snakeDir.y = 0;
            break;
        default:
            cout << "This key is not used: " << key << endl;
            break;
    }
}
 
void setNewCoordSystem(int width, int height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0f, gameFieldSize, 0.0f, gameFieldSize, 0.0f, 1.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
 
int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(fieldWidth, fieldHeight);
    glutCreateWindow("Snake");
    glutDisplayFunc(draw);
    glutTimerFunc(250, update, 0);
 
    glutKeyboardFunc(normalKeyHandler);
    glutSpecialFunc(specialKeyHandler);
 
    setNewCoordSystem(fieldWidth, fieldHeight);
 
    Vector2i head = { 4, 1 };
    snake.push_back(head);
 
    glutMainLoop();
    return 0;
}
0
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,135
Записей в блоге: 243
14.12.2018, 12:37
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Ты собираешься решать эту задачу?
0
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,135
Записей в блоге: 243
15.12.2018, 12:20
Цитата Сообщение от 8Observer8 Посмотреть сообщение
Сделай, чтобы счёт (Score) увеличивался, когда съедается еда.
Это, наверное, сложная для тебя задача. Придумаю, что-нибудь попроще. Объясню подробно, как увеличивать Score при съедании еды. Нужно всегда помнить, что функция update() вызывается по таймеру, например, пусть она вызывается раз в секунду. У нас updtate вызывается раз в четверть секунды, то есть раз в 250 милисекунд. Само тело функции update() в идеале выполняется практически мгновенно. В этой функции происходит один игровой тик. За этот тик выполняется логика игры: змейка смещается на одну позицию, а если координата головы совпала с координатой еды, то в конец змейки (в list) добавляется ещё один элемент - пара {x, y}. На самом деле, на следующем тике этот последний добавленный элемент удаляется, но это отдельная тема по данному алгоритму - это нужно исследовать с помощью точек останова. Так же в update будут проверяться совпадения координаты головы: со своими звеньями, с препятствиями, с бонусами и т.д, что пока не реализовано. В самом конце, когда update отработала, то вызывается функция draw(), которая в одно мгновение стирает абсолютно всё и перерисовывает все объекты заново. Дальше, даётся 250 милисекунд показа экрана, чтобы человеческий глаз и мозг воспринял картинку. Этот механизм update -> draw -> пауза -> update -> draw -> пауза работает во всех играх. В играх с плавными перемещениями и анимациями пауза может быть равна 16 милисекунд, то есть 60 FPS - чаще всего почему то выбирают 60 FPS. Как минимум должно быть 24 FPS. Если пересчитать в милисекунды: 1000 / 24 ~= 41 милисекунда на паузу. Если будет меньше 24 FPS, то человеческий глаз и мозг будут видеть рывки, а не плавное движение или анимацию.

Вернёмся с Score. У нас в программе есть глобальная переменная для хранения Score:
C++
1
int score = 0;
Но она пока всегда равна нулю и её значение мы выводим в функции draw:
C++
1
2
3
4
5
6
7
void draw()
{
    // ...
    glClear(GL_COLOR_BUFFER_BIT); // Очищаем полностью экран
    drawText(0, 19, "Score: " + to_string(score)); // Переводим score из int в string и выводим на экран по координате (0, 19)
    // ...
}
Нужно добавить увеличение переменной score в функцию update() в тело условия, которое проверяет совпадение координат головы змейки с координатами еды:
C++
1
2
3
4
5
6
7
8
9
10
11
void update(int value)
{
    // ...
    if (xHead == food.x && yHead == food.y)
    {
        // ...
        score++;
        // ...
    }
    // ...
}
В проекте есть большая проблема. Весь код находится в функции main и эта проблема будет увеличиваться. Становится всё сложнее ориентироваться в коде. Нужно подумать, как лучше разбить код на файлы. У меня есть идеи.

Текущий код нашей змейки:
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
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
205
206
207
208
209
210
211
212
213
214
215
216
217
//#include <irrKlang.h>
//using namespace irrklang;
//ISoundEngine *soundEngine = createIrrKlangDevice();
//soundEngine->play2D("Audio/background.mp3", true);
//soundEngine->setSoundVolume(0.5f);
 
 
#include <GL/freeglut.h>
 
#include <iostream>
#include <string>
#include <list>
using namespace std;
 
int lives = 3;
int score = 0;
 
const int gameFieldSize = 20;
 
int fieldWidth = 260;
int fieldHeight = 260;
 
struct Color3f
{
    float r = 0.5f;
    float g = 0.5f;
    float b = 0.5f;
};
 
struct Vector2i
{
    int x, y;
};
 
Vector2i snakeDir{ 1, 0 };
 
list<Vector2i> snake;
Vector2i food;
 
void drawText(float x, float y, string text)
{
    glColor3f(1.0f, 1.0f, 1.0f);
 
    glRasterPos2f(x, y);
    glutBitmapString(GLUT_BITMAP_8_BY_13, (const unsigned char*)text.c_str());
}
 
void drawSquare(int x, int y, int size, Color3f color)
{
    const float padding = 0.1f;
 
    glColor3f(color.r, color.g, color.b);
 
    glBegin(GL_QUADS);
    glVertex2f(x + padding, y + padding);
    glVertex2f(x + size - padding, y + padding);
    glVertex2f(x + size - padding, y + size - padding);
    glVertex2f(x + padding, y + size - padding);
    glEnd();
}
 
void drawFood()
{
    Color3f foodColor;
    foodColor.r = 0.0f;
    foodColor.g = 0.5f;
    foodColor.b = 0.5f;
    drawSquare(food.x, food.y, 1, foodColor);
}
 
void drawSnake()
{
    Color3f snakeColor;
    snakeColor.r = 0.0f;
    snakeColor.g = 1.0f;
    snakeColor.b = 0.0f;
    for (auto const& cell : snake)
    {
        drawSquare(cell.x, cell.y, 1, snakeColor);
    }
}
 
void drawRectangle(float x, float y, float width, float height)
{
    glBegin(GL_QUADS);
    glVertex2f(x, y);
    glVertex2f(x + width, y);
    glVertex2f(x + width, y + height);
    glVertex2f(x, y + height);
    glEnd();
}
 
void draw()
{
    glClear(GL_COLOR_BUFFER_BIT); // Очищаем полностью экран
    drawText(0, 19, "Score: " + to_string(score)); // Переводим score из int в string и выводим на экран по координате (0, 19)
    drawText(15, 19, "Lives: " + to_string(lives));
 
    drawFood();
    drawSnake();
 
    glutSwapBuffers();
}
 
int getRandomInt(int max)
{
    return rand() % max;
}
 
void update(int value)
{
    Vector2i newPos;
    newPos.x = snake.front().x + snakeDir.x;
    newPos.y = snake.front().y + snakeDir.y;
    snake.push_front(newPos);
    snake.pop_back();
 
    int xHead = snake.front().x;
    int yHead = snake.front().y;
 
    if (xHead == food.x && yHead == food.y)
    {
        Vector2i cell = { food.x, food.y };
        snake.push_back(cell);
        score++;
 
        // Generate a new food
        food.x = getRandomInt(gameFieldSize);
        food.y = getRandomInt(gameFieldSize);
    }
 
    glutTimerFunc(250, update, 0);
    glutPostRedisplay();
}
 
void specialKeyHandler(int key, int x, int y)
{
    switch (key)
    {
        case GLUT_KEY_UP:
            snakeDir.x = 0;
            snakeDir.y = 1;
            break;
        case GLUT_KEY_LEFT:
            snakeDir.x = -1;
            snakeDir.y = 0;
            break;
        case GLUT_KEY_DOWN:
            snakeDir.x = 0;
            snakeDir.y = -1;
            break;
        case GLUT_KEY_RIGHT:
            snakeDir.x = 1;
            snakeDir.y = 0;
            break;
        default:
            cout << "This key is not used: " << key << endl;
            break;
    }
}
 
void normalKeyHandler(unsigned char key, int x, int y)
{
    switch (key)
    {
        case 'w':
            snakeDir.x = 0;
            snakeDir.y = 1;
            break;
        case 'a':
            snakeDir.x = -1;
            snakeDir.y = 0;
            break;
        case 's':
            snakeDir.x = 0;
            snakeDir.y = -1;
            break;
        case 'd':
            snakeDir.x = 1;
            snakeDir.y = 0;
            break;
        default:
            cout << "This key is not used: " << key << endl;
            break;
    }
}
 
void setNewCoordSystem(int width, int height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0f, gameFieldSize, 0.0f, gameFieldSize, 0.0f, 1.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
 
int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(fieldWidth, fieldHeight);
    glutCreateWindow("Snake");
    glutDisplayFunc(draw);
    glutTimerFunc(250, update, 0);
 
    glutKeyboardFunc(normalKeyHandler);
    glutSpecialFunc(specialKeyHandler);
 
    setNewCoordSystem(fieldWidth, fieldHeight);
 
    Vector2i head = { 4, 1 };
    snake.push_back(head);
 
    glutMainLoop();
    return 0;
}


Название: Snake.gif
Просмотров: 99

Размер: 22.8 Кб
0
208 / 95 / 15
Регистрация: 27.07.2018
Сообщений: 323
20.12.2018, 09:17  [ТС]
8Observer8,

C++ (Qt)
1
2
3
4
5
6
7
if (food.x == coordHead.x && food.y == coordHead.y)
    {
        int HeadX = getRandomInt(20);
        int HeadY = getRandomInt(20);
        Vector2i food = { HeadX, HeadY };
        foods.push_back(food);
    }
Написал такой код для спавна еды, почему то не работает, всё же верно?
0
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,135
Записей в блоге: 243
20.12.2018, 10:04
CyberGame, скинь весь код.

Добавлено через 17 минут
Я хотел посмотреть, есть ли у тебя хранилище для еды foods. По идее его не должно быть. Мы договорились, что еда на поле всегда появляется одна, как в классической змейке. Когда игра начинается, то еда на поле одна. Когда змейка съедает еду, то еда появляется в другом месте. Всегда одна еда на поле. Поэтому я не понимаю, зачем оставил хранилище еды foods от прошлой версии. Тем более, я думал, что ты внимательно читал это сообщение, где я генерацию еды уже сделал.

Добавлено через 3 минуты
Раз мы совместно разрабатываем змейку, то зачем делать туже работу снова? Предложи, что ещё должна или не должна делать змейка. Проблем ещё много. Например, классическая змейка при врезании в свой хвост начиналась сначала, а одна жизнь убавлялась.

Добавлено через 2 минуты
Подумай, как сделать так, чтобы при врезании головы в одно из звеньев тела змейки происходил сброс игры на начало. Если это для тебя сложно, то придумай, что ещё можно изменить в игре.
0
208 / 95 / 15
Регистрация: 27.07.2018
Сообщений: 323
20.12.2018, 10:15  [ТС]
8Observer8,
Давай я попробую решить всё самостоятельно если не получиться обращусь.
Единственное я не понимаю, как работает вот это.
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for (auto it = foods.begin(); it != foods.end(); /* */)
    {
        int foodX = (*it).x;
        int foodY = (*it).y;
 
        if (x == foodX && y == foodY)
        {
            Vector2i cell = { x, y };
            snake.push_back(cell);
            it = foods.erase(it);
        }
        else
        {
            ++it;
        }
    }
Конкретнее, за что отвечает cell?

Добавлено через 6 минут
8Observer8,
C++ (Qt)
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
#include <GL/freeglut.h>
 
#include <iostream>
#include <string>
#include <list>
using namespace std;
 
int lives = 3; // Кол-во жизней
int score = 0; // Кол-во  очков
const int FieldSize = 20; // Размер поля
 
struct Color3f // Структура для определения цвета
{
    float r = 0.5f;
    float g = 0.5f;
    float b = 0.5f;
};
 
int getRandomInt(int max) // Выводит рандомное число
{
    return rand() % max;
}
 
struct Vector2i // Вектор
{
    int x, y;
} coordHead{ 5, 1 }, vectorDir{ 1, 0 }, food{ getRandomInt(20), getRandomInt(20) };
 
list<Vector2i> snake; // Расположение змейки
 
 
void drawText(float x, float y, string text) // Рисует текст
{
    glColor3f(1.0f, 1.0f, 1.0f);
 
    glRasterPos2f(x, y);
    glutBitmapString(GLUT_BITMAP_8_BY_13, (const unsigned char*)text.c_str());
}
 
void drawSquare(int x, int y, int size, Color3f color) // Функция рисует элементы змейки
{
    const float padding = 0.1f;
 
    glColor3f(color.r, color.g, color.b);
 
    glBegin(GL_QUADS);
    glVertex2f(x + padding, y + padding);
    glVertex2f(x + size - padding, y + padding);
    glVertex2f(x + size - padding, y + size - padding);
    glVertex2f(x + padding, y + size - padding);
    glEnd();
}
 
void drawFood() // Функция рисует еду
{
    //glColor3f(0.0f, 0.5f, 0.5f);
    Color3f foodColor = { 0.0f, 0.5f, 0.5f };
    drawSquare(food.x, food.y, 1, foodColor);
}
 
void drawSnake() // Функция рисует змейку
{
    //glColor3f(0.0f, 1.0f, 0.0f);
    Color3f snakeColor = { 0.0f, 1.0f, 0.0f };
    for (auto const& cell : snake)
    {
        drawSquare(cell.x, cell.y, 1, snakeColor);
    }
}
 
void drawRectangle(int x, int y, int width, int height) // Рисует поле
{
    glBegin(GL_QUADS);
    glVertex2f(x, y);
    glVertex2f(x + width, y);
    glVertex2f(x + width, y + height);
    glVertex2f(x, y + height);
    glEnd();
}
 
void draw() // Рисует всё
{
    glClear(GL_COLOR_BUFFER_BIT);
    drawText(0, 19, "Score: " + to_string(score));
    drawText(15, 19, "Lives: " + to_string(lives));
 
    drawFood();
    drawSnake();
 
    glutSwapBuffers();
}
 
void update(int value)
{
    Vector2i newPos;
    newPos.x = snake.front().x + vectorDir.x;
    newPos.y = snake.front().y + vectorDir.y;
    // Добавляем новый элемент в начало списка
    snake.push_front(newPos);
    // Удаляем старый элемент с конца списка
    snake.pop_back();
 
    int x = snake.front().x;
    int y = snake.front().y;
    int randX = getRandomInt(20);
    int randY = getRandomInt(20);
    if (x == food.x && y == food.y)
    {
        Vector2i cell = { x, y };
        snake.push_back(cell);
    }
    if (coordHead.x == food.x && coordHead.y == food.y)
    {
        score++;
        food.x = randX;
        food.y = randY;
    }
    
 
    glutTimerFunc(250, update, 0);
    glutPostRedisplay();
}
 
void keyboard(unsigned char key, int x, int y)
{
    switch (key)
    {
    case 'w':
        vectorDir.x = 0;
        vectorDir.y = 1;
        break;
    case 'a':
        vectorDir.x = -1;
        vectorDir.y = 0;
        break;
    case 's':
        vectorDir.x = 0;
        vectorDir.y = -1;
        break;
    case 'd':
        vectorDir.x = 1;
        vectorDir.y = 0;
        break;
    default:
        cout << "This key is not used: " << key << endl;
        break;
    }
}
 
void setNewCoordSystem(int width, int height, int const FieldSize)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0f, FieldSize, 0.0f, FieldSize, 0.0f, 1.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
 
int main(int argc, char** argv)
{
    int fieldWidth = 512;
    int fieldHeight = 512;
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(fieldWidth, fieldHeight);
    glutCreateWindow("Snake");
    glutDisplayFunc(draw);
    glutTimerFunc(250, update, 0);
    glutKeyboardFunc(keyboard);
    setNewCoordSystem(fieldWidth, fieldHeight, FieldSize);
 
    snake.push_back(coordHead);
    Vector2i cell1 = { 4, 1 };
    Vector2i cell2 = { 3, 1 };
    snake.push_back(cell1);
    snake.push_back(cell2);
 
    glutMainLoop();
    return 0;
}
Весь код.
0
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,135
Записей в блоге: 243
20.12.2018, 10:15
Массив snake состоит из элементов cell (ячеек). Каждая ячейка cell представляет из себя пару пару двух чисел: { x, y }. Здесь в коде логика такая. Пробегаемся по массиву элементов еды (по координатам элементов еды). Проверяем, если текущая координата головы змейки совпала с один из элементов еды, то нужно в массив элементов змейки добавить cell ({x, y}) с координатами еды.
0
208 / 95 / 15
Регистрация: 27.07.2018
Сообщений: 323
20.12.2018, 10:23  [ТС]
8Observer8, За голову змейки отвечает - coordHead
?
0
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,135
Записей в блоге: 243
20.12.2018, 10:42
У тебя в коде нарушена логина. Посмотри все места, где у тебя используется переменная coordHead.

Я перечислю. Сначала ты создаёшь переменную coordHead типа Vector2i. Это переменная хранит два числа: { x, y }
C++
1
2
3
4
struct Vector2i // Вектор
{
    int x, y;
} coordHead{ 5, 1 }
Потом ты эту переменную используешь в main(), чтобы добавить первый элемент cell в змейку:
C++
1
2
3
4
5
6
int main(int argc, char** argv)
{
    // ...
    snake.push_back(coordHead);
    // ...
}
И ещё один раз ты её используешь в функции update():
C++
1
2
3
4
5
6
    if (coordHead.x == food.x && coordHead.y == food.y)
    {
        score++;
        food.x = randX;
        food.y = randY;
    }
И всё, больше она (если её искать поиском по коду), то она нигде не меняется. У неё, как было значение { 5, 1 }, так оно и не меняется всю игру.

Добавлено через 4 минуты
Цитата Сообщение от CyberGame Посмотреть сообщение
За голову змейки отвечает - coordHead
Сейчас ни за что не отвечает. Раньше отвечала на стартовое положение головы змейки в начале игры. В крайней версии кода я удалил эту переменную и стартовое положение задаю в main:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(fieldWidth, fieldHeight);
    glutCreateWindow("Snake");
    glutDisplayFunc(draw);
    glutTimerFunc(250, update, 0);
 
    glutKeyboardFunc(normalKeyHandler);
    glutSpecialFunc(specialKeyHandler);
 
    setNewCoordSystem(fieldWidth, fieldHeight);
 
    Vector2i head = { 4, 1 };
    snake.push_back(head);
 
    glutMainLoop();
    return 0;
}
0
208 / 95 / 15
Регистрация: 27.07.2018
Сообщений: 323
20.12.2018, 19:54  [ТС]
8Observer8,
Вроде всё
C++ (Qt)
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
205
206
207
208
209
#include <GL/freeglut.h>
#include <iostream>
#include <string>
#include <list>
using namespace std;
 
int lives = 3;
int score = 0;
 
const int gameFieldSize = 20;
 
int fieldWidth = 260;
int fieldHeight = 260;
 
struct Color3f
{
    float r = 0.5f;
    float g = 0.5f;
    float b = 0.5f;
};
 
struct Vector2i
{
    int x, y;
};
 
Vector2i snakeDir{ 1, 0 };
 
list<Vector2i> snake;
Vector2i food;
 
void drawText(float x, float y, string text)
{
    glColor3f(1.0f, 1.0f, 1.0f);
 
    glRasterPos2f(x, y);
    glutBitmapString(GLUT_BITMAP_8_BY_13, (const unsigned char*)text.c_str());
}
 
void drawSquare(int x, int y, int size, Color3f color)
{
    const float padding = 0.1f;
 
    glColor3f(color.r, color.g, color.b);
 
    glBegin(GL_QUADS);
    glVertex2f(x + padding, y + padding);
    glVertex2f(x + size - padding, y + padding);
    glVertex2f(x + size - padding, y + size - padding);
    glVertex2f(x + padding, y + size - padding);
    glEnd();
}
 
void drawFood()
{
    Color3f foodColor;
    foodColor.r = 0.0f;
    foodColor.g = 0.5f;
    foodColor.b = 0.5f;
    drawSquare(food.x, food.y, 1, foodColor);
}
 
void drawSnake()
{
    Color3f snakeColor;
    snakeColor.r = 0.0f;
    snakeColor.g = 1.0f;
    snakeColor.b = 0.0f;
    for (auto const& cell : snake)
    {
        drawSquare(cell.x, cell.y, 1, snakeColor);
    }
}
 
void drawRectangle(float x, float y, float width, float height)
{
    glBegin(GL_QUADS);
    glVertex2f(x, y);
    glVertex2f(x + width, y);
    glVertex2f(x + width, y + height);
    glVertex2f(x, y + height);
    glEnd();
}
 
void draw()
{
    glClear(GL_COLOR_BUFFER_BIT);
    drawText(0, 19, "Score: " + to_string(score));
    drawText(15, 19, "Lives: " + to_string(lives));
 
    drawFood();
    drawSnake();
 
    glutSwapBuffers();
}
 
int getRandomInt(int max)
{
    return rand() % max;
}
 
void update(int value)
{
    Vector2i newPos;
    newPos.x = snake.front().x + snakeDir.x;
    newPos.y = snake.front().y + snakeDir.y;
    snake.push_front(newPos);
    snake.pop_back();
 
    int xHead = snake.front().x;
    int yHead = snake.front().y;
 
    if (xHead == food.x && yHead == food.y)
    {
        score++;
        Vector2i cell = { food.x, food.y };
        snake.push_back(cell);
 
        // Generate a new food
        food.x = getRandomInt(gameFieldSize);
        food.y = getRandomInt(gameFieldSize);
    }
 
    glutTimerFunc(250, update, 0);
    glutPostRedisplay();
}
 
void specialKeyHandler(int key, int x, int y)
{
    switch (key)
    {
    case GLUT_KEY_UP:
        snakeDir.x = 0;
        snakeDir.y = 1;
        break;
    case GLUT_KEY_LEFT:
        snakeDir.x = -1;
        snakeDir.y = 0;
        break;
    case GLUT_KEY_DOWN:
        snakeDir.x = 0;
        snakeDir.y = -1;
        break;
    case GLUT_KEY_RIGHT:
        snakeDir.x = 1;
        snakeDir.y = 0;
        break;
    default:
        cout << "This key is not used: " << key << endl;
        break;
    }
}
 
void normalKeyHandler(unsigned char key, int x, int y)
{
    switch (key)
    {
    case 'w':
        snakeDir.x = 0;
        snakeDir.y = 1;
        break;
    case 'a':
        snakeDir.x = -1;
        snakeDir.y = 0;
        break;
    case 's':
        snakeDir.x = 0;
        snakeDir.y = -1;
        break;
    case 'd':
        snakeDir.x = 1;
        snakeDir.y = 0;
        break;
    default:
        cout << "This key is not used: " << key << endl;
        break;
    }
}
 
void setNewCoordSystem(int width, int height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0f, gameFieldSize, 0.0f, gameFieldSize, 0.0f, 1.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
 
int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(fieldWidth, fieldHeight);
    glutCreateWindow("Snake");
    glutDisplayFunc(draw);
    glutTimerFunc(250, update, 0);
 
    glutKeyboardFunc(normalKeyHandler);
    glutSpecialFunc(specialKeyHandler);
 
    setNewCoordSystem(fieldWidth, fieldHeight);
 
    Vector2i head = { 4, 1 };
    snake.push_back(head);
 
    glutMainLoop();
    return 0;
}
Интересно почему всё же фрукты спавнятся в определенном порядке, сколько раз не перезапускал.

Что дальше?
0
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,135
Записей в блоге: 243
20.12.2018, 20:55
Цитата Сообщение от CyberGame Посмотреть сообщение
Что дальше?
Составь список того, что в змейке сейчас работает не так как должно и чего вообще нет, но должно быть. В порядке важности или в любом порядке. Пока можешь этот список для себя составлять в процессе кодинга. Просто часто возникает мысль, что вот это бы не забыть сделать и забываешь. Нужно всегда держать такой список под рукой, чтобы в любой момент в него что-то добавить, а что-то отметить, что это сделано. Я пишу список, а что сделано помечаю плюсами:

- Добавить то-то
+ Убрать это
+ Заменить вот это
- Добавить это
- Реализовать то

Глобальная задача, чтобы была играбельная версия игры, то есть, чтобы в ней была победа и проигрыш. Я предлагаю сделать пока простейший вариант победы - съесть три штуки еды. Вместо трёх можно будет любое число поставить потом, но три будет нормально, чтобы проще отлаживать. Когда змейка съедает три еды пусть выводится в середину экрана "You won the game". Не знаю, правильно ли это по английский: "Вы выиграли эту игру!". В общем-то и по русски не очень звучит. Надпись можно будет тоже потом поменять.

Из важных вещей можно будет добавить квадраты вокруг игрового поля, чтобы при врезании в них игра начиналась сначала, как у меня.

У меня бесконечная змейка на максимальный результат. Её бы расположить на хостинге с базой данных, чтобы сохранялись рекорд и имя.
0
208 / 95 / 15
Регистрация: 27.07.2018
Сообщений: 323
20.12.2018, 20:59  [ТС]
8Observer8,
Выведется надпись, а змейка должна будет остановиться или что?
0
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,135
Записей в блоге: 243
20.12.2018, 21:01
Цитата Сообщение от CyberGame Посмотреть сообщение
Интересно почему всё же фрукты спавнятся в определенном порядке, сколько раз не перезапускал.
Обычная практика вызвать srand и и передать в неё time(0)

http://www.cplusplus.com/reference/cstdlib/srand/

C++
1
2
3
4
5
6
7
8
9
10
11
#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
 
int main()
{
    srand(time(0));
    int random = rand();
    return 0;
}
0
208 / 95 / 15
Регистрация: 27.07.2018
Сообщений: 323
20.12.2018, 21:58  [ТС]
8Observer8,
Размеры поля -
От координаты 0 ( включительно ), до 20 ( включительно ), да?
0
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,135
Записей в блоге: 243
20.12.2018, 22:22
Цитата Сообщение от CyberGame Посмотреть сообщение
Выведется надпись, а змейка должна будет остановиться или что?
Да, лучше так.

Добавлено через 1 минуту
Цитата Сообщение от CyberGame Посмотреть сообщение
От координаты 0 ( включительно ), до 20 ( включительно ), да?
[0, 20)
0
9991 / 2963 / 497
Регистрация: 05.10.2013
Сообщений: 8,135
Записей в блоге: 243
21.12.2018, 13:21
Цитата Сообщение от CyberGame Посмотреть сообщение
Выведется надпись, а змейка должна будет остановиться или что?
Это легко и быстро делается. Передвижение объектов происходит в update. Ты заключи всю логику игры в условие, в котором проверяется boolean значение переменной обозначающей состояние - находимся ли мы в состоянии игры или в состоянии победы.

C++
1
2
3
4
5
6
7
8
9
bool isGame = true;
 
void update()
{
    if (isGame)
    {
        // Game logic
    }
}
Если isGame сделать равным false, то все вся игра будет на паузе.

Добавлено через 55 минут
Некоторые текущие недоработки в змейке. Список можно корректировать: изменять, добавлять, удалять пункты:
  • Нет цели игры. Либо сделать зарабатывание максимального числа очков с сохранением в файл, либо сделать чтобы после съедания определённого числа выводилось сообщение "You won the game!". Либо сделать несколько уровней с разными картами.
  • Нет проигрыша. Не выводится сообщение "Game Over. Try again", когда змейка врезается в свой хвост.
  • Змейка уходит за поле. Нужно либо огородить забором, либо пусть она вылезает с другой стороны
  • Голова змейки не должна двигаться в противоположенном направлении, через себя. То есть если она движется вверх по карте и если нажать внизу, то ничего не должно происходить

А вообще, хорошо бы сделать перевод на актуальный шейдерный OpenGL 3+, в 3D и импортом 3D моделей из редактора Blender. Я начинающий 3D моделлер. Могу сделать простые 3D модели и наложить текстуры на них. Но это если ты не решишь, что изучение линейной алгебры, OpenGL и т.д. - это не твоё. Из линейной алгебры нужно знать для змейки только правило умножения матрицы на вектор для перемещения объектов. В интернете очень много туторов для начинающих по линейной алгебре в OpenGL 3+, по языку шейдеров GLSL, в целом по OpenGL 3+ и написании простых игр на нём. Особенно, на английском, а так же много видео уроков, книг, статей. Рекомендую искать, изучать и практиковаться в шейдерном OpenGL на простых играх. На простых играх интереснее изучать программирование, алгоритмы и ООП.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
21.12.2018, 13:21

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

Подскажите, как лучше всего изучать язык, ежели в академии не дают достаточный объем знаний
хожу на курсы в академию уже 3 месяца, изучаем С++ по либерти, практики нету вообще, просто примеры по книге набираем...в общем туго идет,...

Какие паттерны можно использовать для совершенствования приложения
Доброго времени суток! У меня есть приложение реализованное на Qt C++ - тестирование студентов. Суть приложения заключается в...

Что изучать для работы
Всем здравствуйте. Ребята, такой вопрос. Какие технологии сейчас лучше изучать, чтобы было проще и быстрее, и при этом чтобы можно было...

Что изучать для создания сайтов
Привет всем, всех с новым годом! кто занимается web - разработкой, создание сайтов , хотелось у вас узнать ко э что. В каком порядки...


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

Или воспользуйтесь поиском по форуму:
260
Ответ Создать тему
Новые блоги и статьи
Запустил конкурс "тем и промптов для текстовых квестов созданных почти чисто ИИ"
Adler 06.10.2026
Всем привет! За последние три-четыре дня я создал более 16 текстовых квестовых игр используя преимущественно по одному запросу к ИИ на игру. Мне так понравилось смотреть все ветки/ сцены во всех. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Nekobox - outbounds[0].transport: unknown transport type: raw
damix 01.10.2026
Фикс ошибки Правым кликом по серверу -> отладочная информация -> edit Заменить "net": "raw", на "net": "tcp", Нажать кнопку reload.
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru