Снегопад с анимацией

Creado el: 10 de diciembre de 2024

Respondido usando O1 por Chat01

Pregunta

#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;

text
for (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;

text
MoveSnow(); // Обновление угла руки снеговика для анимации 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);

text
DrawDrifts(); 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("Снегопад с Множественными Сугробами");

text
InitSnow(); InitGL(); // Регистрация функций обратного вызова glutDisplayFunc(Display); glutReshapeFunc(Reshape); glutIdleFunc(Idle); glutKeyboardFunc(Keyboard); // Вход в основной цикл GLUT glutMainLoop(); return 0;

} напишите обьяснительную записку по данной программе.

Pensamiento

Думал для секунда

Respuesta

Объяснительная записка

Тема проекта: Снегопад с множественными сугробами и анимированным снеговиком

Введение

Данный проект представляет собой компьютерную графическую программу, реализованную на языке C++ с использованием библиотеки OpenGL и GLUT. Программа визуализирует процесс снегопада с образованием нескольких сугробов и последующим появлением анимированного снеговика. Основной целью проекта является демонстрация базовых возможностей OpenGL для создания анимации и взаимодействия с пользователем.

Структура программы

Программа состоит из нескольких ключевых компонентов:

  1. Инициализация и настройки OpenGL:

    • Определение констант, таких как M_PI для использования математической константы π.
    • Установка параметров окна (ширина, высота) и временных задержек для анимации.
    • Инициализация структуры данных для снежинок и сугробов.
  2. Структуры данных:

    • Snowflake: описывает свойства одной снежинки, включая позицию (x, y), скорость падения (speed) и флаг settled, указывающий, достигла ли снежинка сугроба.
    • Snowbank: описывает свойства сугроба, включая начальную и конечную координаты по оси X (start_x, end_x) и высоту сугроба (height).
  3. Инициализация снежинок и сугробов (InitSnow):

    • Снежинки равномерно распределяются по нескольким сугробам, задавая начальные позиции выше экрана.
    • Сугробы инициализируются с нулевой высотой и равной шириной, распределенной по количеству сугробов (NUM_BANKS).
  4. Отрисовка элементов сцены:

    • Снежинки (DrawSnow): Отображаются как белые точки с увеличенным размером и сглаживанием.
    • Сугробы (DrawDrifts): Отображаются как полигоны с волнистыми краями, создающими эффект естественного сугроба.
    • Снеговик (DrawSnowman): Состоит из трёх кругов (основание, средняя часть, голова), глаз, носа, пуговиц, рук и основания под снеговиком.
    • Текст (DrawText): Отображается поздравительное сообщение "Happy New Year!" над снеговиком после завершения снегопада.
  5. Анимация и обновление состояния:

    • Движение снежинок (MoveSnow): Снежинки постепенно падают вниз, увеличивая высоту соответствующего сугроба при достижении его вершины. При достижении максимальной высоты всех сугробов снегопад останавливается.
    • Анимация руки снеговика (Idle): После остановки снегопада рука снеговика начинает колебаться вверх и вниз, имитируя движение.
  6. Обработка событий:

    • Изменение размера окна (Reshape): Обеспечивает корректное масштабирование сцены при изменении размеров окна.
    • Обработка нажатий клавиш (Keyboard): При нажатии пробела снегопад перезапускается, а сугробы и снеговик сбрасываются в начальное состояние.
  7. Основной цикл программы (main):

    • Инициализирует GLUT и OpenGL.
    • Регистрирует функции обратного вызова для отображения, изменения размера окна, анимации и обработки клавиатуры.
    • Запускает основной цикл обработки событий GLUT.

Основные алгоритмы и методы

  1. Равномерное распределение снежинок по сугробам:

    • Снежинки распределяются по разным сугробам с помощью индексации (bankIndex = i % NUM_BANKS), что обеспечивает равномерное покрытие области.
  2. Обновление позиций снежинок:

    • Каждая снежинка движется вниз с заданной скоростью. При достижении уровня сугроба её положение фиксируется, и высота сугроба увеличивается с учётом случайной вариации для естественности.
  3. Ограничение высоты сугробов:

    • Высота каждого сугроба ограничивается определённой долей от высоты окна (MAX_BANK_HEIGHT_RATIO), предотвращая чрезмерное накопление снега.
  4. Анимация руки снеговика:

    • Угол наклона руки изменяется с определённой скоростью в пределах заданных углов, создавая эффект колебания.
  5. Отрисовка графических элементов:

    • Используются примитивы OpenGL (точки, полигоны, линии, треугольники) для создания различных частей сцены.
    • Для гладкости и эстетичности применяются сглаживание точек и увеличение их размера.

Управление и взаимодействие с пользователем

  • Перезапуск снегопада: Нажатие пробела позволяет пользователю перезапустить процесс снегопада, сбрасывая все сугробы и снежинки в начальное состояние.
  • Изменение размеров окна: Программа автоматически адаптируется к изменению размеров окна, корректно масштабируя все элементы сцены.

Заключение

Данный проект демонстрирует основы компьютерной графики с использованием OpenGL и GLUT, включая создание анимации, обработку пользовательского ввода и управление состоянием сцены. Программа сочетает в себе визуальные эффекты снегопада, формирование сугробов и анимированного снеговика, что делает её наглядным примером применения графических библиотек для создания интерактивных визуальных эффектов.

Возможные улучшения

  • Добавление цвета и текстур: Внедрение цветных сугробов, текстур для снеговика и других элементов сцены для повышения реалистичности.
  • Более сложная анимация: Реализация более сложных анимаций для снеговика, например, движения глаз или моргания.
  • Интерактивность: Добавление возможности пользователю изменять параметры снегопада, такие как количество снежинок, скорость падения или количество сугробов.
  • Оптимизация производительности: При увеличении количества снежинок возможно потребуется оптимизация алгоритмов отрисовки для поддержания высокой частоты кадров.

Технические требования

  • Язык программирования: C++
  • Библиотеки: OpenGL, GLUT
  • Компилятор: Поддерживающий C++ и OpenGL (например, Visual Studio)

Автор

Имя: [Ваше Имя]
Дата: [Дата создания документа]

Compartir este Q&A