Снегопад с анимацией
Creado el: 10 de diciembre de 2024
Creado el: 10 de diciembre de 2024
#define _USE_MATH_DEFINES // Для определения M_PI в Visual Studio
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <cstring>
// Оборачиваем включение GLUT в extern "C", чтобы предотвратить конфликты имен
extern "C" {
#include <glut.h>
}
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
// Параметры окна
GLint Width = 800, Height = 600;
int delay = 5;
float lastTime = 0.0f;
// Параметры снега
const int NUM_SNOWFLAKES = 1000;
struct Snowflake {
float x;
float y;
float speed;
bool settled; // Флаг, что снежинка остановилась
};
Snowflake snow[NUM_SNOWFLAKES];
// Параметры сугробов
#define NUM_BANKS 5
struct Snowbank {
float start_x;
float end_x;
float height;
};
Snowbank snowbanks[NUM_BANKS];
const float MAX_BANK_HEIGHT_RATIO = 0.2f; // Максимальная высота сугроба как доля от высоты экрана
bool stopSnowflakes = false; // Флаг для остановки падения снежинок
// Параметры для анимации руки снеговика
float armAngle = 0.0f; // Текущий угол руки
bool armUp = true; // Направление движения руки
// Функция инициализации снежинок и сугробов
void InitSnow() {
srand(static_cast<unsigned>(time(NULL)));
// Инициализация сугробов
float bankWidth = static_cast<float>(Width) / NUM_BANKS;
for (int i = 0; i < NUM_BANKS; i++) {
snowbanks[i].start_x = i * bankWidth;
snowbanks[i].end_x = (i + 1) * bankWidth;
snowbanks[i].height = 0.0f;
}
text// Инициализация снежинок, равномерно распределённых по сугробам for (int i = 0; i < NUM_SNOWFLAKES; i++) { // Равномерное распределение снежинок по сугробам int bankIndex = i % NUM_BANKS; float currentBankWidth = snowbanks[bankIndex].end_x - snowbanks[bankIndex].start_x; snow[i].x = snowbanks[bankIndex].start_x + static_cast<float>(rand()) / RAND_MAX * currentBankWidth; snow[i].y = static_cast<float>((rand() % Height) + Height); // Начинаем "выше" экрана snow[i].speed = 0.5f + static_cast<float>(rand() % 100) / 100.0f; // Разная скорость snow[i].settled = false; }
}
// Функция проверки, достигли ли все сугробы максимальной высоты
bool AllSnowbanksMaxHeight() {
for (int i = 0; i < NUM_BANKS; i++) {
if (snowbanks[i].height < MAX_BANK_HEIGHT_RATIO * Height)
return false;
}
return true;
}
// Функция рисования снежинок
void DrawSnow() {
glPointSize(3.0f); // Увеличенный размер точек для снежинок
glEnable(GL_POINT_SMOOTH); // Включаем сглаживание точек
glBegin(GL_POINTS);
glColor3f(1.0f, 1.0f, 1.0f); // Белый цвет
for (int i = 0; i < NUM_SNOWFLAKES; i++) {
if (!snow[i].settled && snow[i].y >= 0.0f && snow[i].y <= Height)
glVertex2f(snow[i].x, snow[i].y);
}
glEnd();
glDisable(GL_POINT_SMOOTH); // Отключаем сглаживание точек
}
// Функция рисования сугробов
void DrawDrifts() {
for (int i = 0; i < NUM_BANKS; i++) {
if (snowbanks[i].height > 0.0f) {
glColor3f(1.0f, 1.0f, 1.0f); // Белый цвет
glBegin(GL_POLYGON);
text// Нижняя граница сугроба слева направо glVertex2f(snowbanks[i].start_x, 0.0f); glVertex2f(snowbanks[i].end_x, 0.0f); // Верхняя граница сугроба справа налево с волнистым краем int numPoints = 40; // Увеличенное количество точек для более плавной границы float bankWidth = snowbanks[i].end_x - snowbanks[i].start_x; for (int j = numPoints; j >= 0; j--) { // Идём от правого края к левому float x = snowbanks[i].start_x + (bankWidth * j) / numPoints; // Добавляем небольшую синусоиду для волнистости float variation = 3.0f * sinf(static_cast<float>(j) / numPoints * M_PI * 4); // 4 полных волны, амплитуда 3 float y = snowbanks[i].height + 3.0f + variation; // y >= height + 0 glVertex2f(x, y); } glEnd(); } }
}
// Функция рисования круга (используется для снеговика)
void DrawCircle(float centerX, float centerY, float radius) {
int numSegments = 100;
glBegin(GL_POLYGON);
for (int i = 0; i < numSegments; i++) {
float theta = 2.0f * M_PI * float(i) / float(numSegments);
float x = radius * cosf(theta);
float y = radius * sinf(theta);
glVertex2f(centerX + x, centerY + y);
}
glEnd();
}
// Функция рисования снеговика
void DrawSnowman() {
// Выбираем центральный сугроб для размещения снеговика
int centralBank = NUM_BANKS / 2;
float centerX = (snowbanks[centralBank].start_x + snowbanks[centralBank].end_x) / 2.0f;
float baseY = snowbanks[centralBank].height;
text// Размеры снеговика float baseRadius = 30.0f; float middleRadius = 20.0f; float headRadius = 10.0f; // Отрисовка основания glColor3f(1.0f, 1.0f, 1.0f); // Белый цвет DrawCircle(centerX, baseY + baseRadius, baseRadius); // Отрисовка средней части DrawCircle(centerX, baseY + baseRadius + middleRadius * 2.0f, middleRadius); // Отрисовка головы DrawCircle(centerX, baseY + baseRadius + middleRadius * 2.0f + headRadius * 2.0f, headRadius); // Отрисовка глаз glPointSize(2.0f); glBegin(GL_POINTS); glColor3f(0.0f, 0.0f, 0.0f); // Чёрный цвет glVertex2f(centerX - 3.0f, baseY + baseRadius + middleRadius * 2.0f + headRadius * 2.0f + 2.0f); glVertex2f(centerX + 3.0f, baseY + baseRadius + middleRadius * 2.0f + headRadius * 2.0f + 2.0f); glEnd(); // Отрисовка носа (оранжевый треугольник) glColor3f(1.0f, 0.5f, 0.0f); // Оранжевый цвет glBegin(GL_TRIANGLES); glVertex2f(centerX, baseY + baseRadius + middleRadius * 2.0f + headRadius * 2.0f); // Верхняя вершина glVertex2f(centerX + 10.0f, baseY + baseRadius + middleRadius * 2.0f + headRadius * 2.0f - 5.0f); // Нижняя правая glVertex2f(centerX, baseY + baseRadius + middleRadius * 2.0f + headRadius * 2.0f - 5.0f); // Нижняя левая glEnd(); // Отрисовка пуговиц glPointSize(4.0f); glBegin(GL_POINTS); glColor3f(0.0f, 0.0f, 0.0f); // Чёрный цвет glVertex2f(centerX, baseY + baseRadius + middleRadius * 2.0f + 10.0f); glVertex2f(centerX, baseY + baseRadius + middleRadius * 2.0f); glVertex2f(centerX, baseY + baseRadius + middleRadius * 2.0f - 10.0f); glEnd(); // Отрисовка рук (линии) glLineWidth(2.0f); glColor3f(0.6f, 0.3f, 0.0f); // Коричневый цвет glBegin(GL_LINES); // Левая рука (мах) glVertex2f(centerX - middleRadius, baseY + baseRadius + middleRadius * 2.0f + 10.0f); glVertex2f(centerX - middleRadius - 15.0f, baseY + baseRadius + middleRadius * 2.0f + 25.0f + sinf(armAngle) * 10.0f); // Правая рука (фиксированная) glVertex2f(centerX + middleRadius, baseY + baseRadius + middleRadius * 2.0f + 10.0f); glVertex2f(centerX + middleRadius + 15.0f, baseY + baseRadius + middleRadius * 2.0f + 25.0f); glEnd(); // Отрисовка основания (квадрат под снеговиком) glColor3f(1.0f, 1.0f, 1.0f); // Коричневый цвет для основания glBegin(GL_QUADS); float squareSize = 1000.0f; glVertex2f(centerX - squareSize / 2, baseY); glVertex2f(centerX + squareSize / 2, baseY); glVertex2f(centerX + squareSize / 2, baseY - squareSize / 2); glVertex2f(centerX - squareSize / 2, baseY - squareSize / 2); glEnd();
}
// Функция рисования текста
void DrawText(const char* text, float x, float y) {
glColor3f(1.0f, 1.0f, 1.0f); // Белый цвет
glRasterPos2f(x, y);
for (const char* c = text; *c != '\0'; c++) {
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *c);
}
}
// Функция обновления позиции снежинок и анимации руки снеговика
void MoveSnow() {
if (stopSnowflakes)
return;
textfor (int i = 0; i < NUM_SNOWFLAKES; i++) { if (!snow[i].settled) { snow[i].y -= snow[i].speed; // Определяем, к какому сугробу принадлежит снежинка int bankIndex = static_cast<int>(snow[i].x / (static_cast<float>(Width) / NUM_BANKS)); if (bankIndex >= NUM_BANKS) bankIndex = NUM_BANKS - 1; // Обработка граничных случаев // Проверяем, достигла ли снежинка вершины сугроба if (snow[i].y <= snowbanks[bankIndex].height) { // Устанавливаем снежинку на уровне сугроба snow[i].y = snowbanks[bankIndex].height; snow[i].settled = true; // Увеличиваем высоту сугроба с небольшой случайной вариацией float heightIncrement = 0.6f + static_cast<float>(rand() % 20) / 100.0f; // Между 0.6 и 0.8 snowbanks[bankIndex].height += heightIncrement; // Ограничиваем высоту сугроба до максимальной if (snowbanks[bankIndex].height > MAX_BANK_HEIGHT_RATIO * Height) { snowbanks[bankIndex].height = MAX_BANK_HEIGHT_RATIO * Height; } } } } // Проверяем, достигли ли все сугробы максимальной высоты if (AllSnowbanksMaxHeight()) { stopSnowflakes = true; }
}
// Функция обновления состояния программы
void Idle() {
float currentTime = static_cast<float>(clock()) / CLOCKS_PER_SEC * 1000.0f;
if (currentTime - lastTime < delay)
return;
lastTime = currentTime;
textMoveSnow(); // Обновление угла руки снеговика для анимации if (stopSnowflakes) { if (armUp) { armAngle += 0.05f; if (armAngle > M_PI / 6) { // Максимальный угол (30 градусов) armAngle = M_PI / 6; armUp = false; } } else { armAngle -= 0.05f; if (armAngle < -M_PI / 6) { // Минимальный угол (-30 градусов) armAngle = -M_PI / 6; armUp = true; } } } glutPostRedisplay();
}
// Функция отображения
void Display() {
glClearColor(0.0f, 0.0f, 0.1f, 1.0f); // Темный фон для контраста
glClear(GL_COLOR_BUFFER_BIT);
textDrawDrifts(); if (!stopSnowflakes) { DrawSnow(); } else { DrawSnowman(); // Отрисовка снеговика после формирования сугробов // Отрисовка текста над снеговиком int centralBank = NUM_BANKS / 2; float centerX = (snowbanks[centralBank].start_x + snowbanks[centralBank].end_x) / 2.0f; float baseY = snowbanks[centralBank].height; DrawText("Happy New Year!", centerX - 80.0f, baseY + 200.0f); } glutSwapBuffers(); // Двухбуферный режим
}
// Функция обработки изменения размера окна
void Reshape(int W, int H) {
Width = W;
Height = H;
glViewport(0, 0, W, H);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, static_cast<double>(W), 0, static_cast<double>(H), -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
// Функция обработки нажатия клавиш
void Keyboard(unsigned char key, int x, int y) {
if (key == ' ') {
// При нажатии пробела перезапускаем снегопад
stopSnowflakes = false;
InitSnow();
armAngle = 0.0f;
armUp = true;
}
}
// Функция инициализации OpenGL
void InitGL() {
glEnable(GL_POINT_SMOOTH); // Включаем сглаживание точек
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glClearColor(0.0f, 0.0f, 0.1f, 1.0f); // Темный фон
}
// Основная функция
int main(int argc, char** argv) {
// Инициализация GLUT
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(Width, Height);
glutInitWindowPosition(100, 100);
glutCreateWindow("Снегопад с Множественными Сугробами");
textInitSnow(); InitGL(); // Регистрация функций обратного вызова glutDisplayFunc(Display); glutReshapeFunc(Reshape); glutIdleFunc(Idle); glutKeyboardFunc(Keyboard); // Вход в основной цикл GLUT glutMainLoop(); return 0;
} напишите обьяснительную записку по данной программе.
Данный проект представляет собой компьютерную графическую программу, реализованную на языке C++ с использованием библиотеки OpenGL и GLUT. Программа визуализирует процесс снегопада с образованием нескольких сугробов и последующим появлением анимированного снеговика. Основной целью проекта является демонстрация базовых возможностей OpenGL для создания анимации и взаимодействия с пользователем.
Программа состоит из нескольких ключевых компонентов:
Инициализация и настройки OpenGL:
M_PI для использования математической константы π.Структуры данных:
Snowflake: описывает свойства одной снежинки, включая позицию (x, y), скорость падения (speed) и флаг settled, указывающий, достигла ли снежинка сугроба.Snowbank: описывает свойства сугроба, включая начальную и конечную координаты по оси X (start_x, end_x) и высоту сугроба (height).Инициализация снежинок и сугробов (InitSnow):
NUM_BANKS).Отрисовка элементов сцены:
DrawSnow): Отображаются как белые точки с увеличенным размером и сглаживанием.DrawDrifts): Отображаются как полигоны с волнистыми краями, создающими эффект естественного сугроба.DrawSnowman): Состоит из трёх кругов (основание, средняя часть, голова), глаз, носа, пуговиц, рук и основания под снеговиком.DrawText): Отображается поздравительное сообщение "Happy New Year!" над снеговиком после завершения снегопада.Анимация и обновление состояния:
MoveSnow): Снежинки постепенно падают вниз, увеличивая высоту соответствующего сугроба при достижении его вершины. При достижении максимальной высоты всех сугробов снегопад останавливается.Idle): После остановки снегопада рука снеговика начинает колебаться вверх и вниз, имитируя движение.Обработка событий:
Reshape): Обеспечивает корректное масштабирование сцены при изменении размеров окна.Keyboard): При нажатии пробела снегопад перезапускается, а сугробы и снеговик сбрасываются в начальное состояние.Основной цикл программы (main):
Равномерное распределение снежинок по сугробам:
bankIndex = i % NUM_BANKS), что обеспечивает равномерное покрытие области.Обновление позиций снежинок:
Ограничение высоты сугробов:
MAX_BANK_HEIGHT_RATIO), предотвращая чрезмерное накопление снега.Анимация руки снеговика:
Отрисовка графических элементов:
Данный проект демонстрирует основы компьютерной графики с использованием OpenGL и GLUT, включая создание анимации, обработку пользовательского ввода и управление состоянием сцены. Программа сочетает в себе визуальные эффекты снегопада, формирование сугробов и анимированного снеговика, что делает её наглядным примером применения графических библиотек для создания интерактивных визуальных эффектов.
Имя: [Ваше Имя]
Дата: [Дата создания документа]