Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

LabWork2

.pdf
Скачиваний:
8
Добавлен:
11.02.2015
Размер:
297.9 Кб
Скачать

Лабораторная работа №2 «Моделирование физического взаимодействия объектов»

Вданной работе рассмотрим основы моделирования физического взаимодействия объектов на примере шаров.

Шары должны взаимодействовать со стенками окна и друг с другом. Моделировать столкновения можно двумя способами.

Velocity-based – подход. Подход, основанный на прогнозировании соударений шаров путем расчета момента соударений на основании заданных векторов скоростей. Данный подход помогает получить наибольшую точность моделирования, но требует более сложных расчетов и более высокую вычислительную мощь.

Position-based – подход. Подход, основанный на мгновенном положении шаров и их расталкивании при столкновении в заданном направлении. Данный подход гораздо проще для моделирования, однако имеет ряд недостатков. Одним из недостатков является то, что время между двумя кадрами (конкретнее – расчетами положения) должно быть фиксированным. Другим недостатком является то, что для быстродвижущихся шаров (быстродвижущимися шарами считаются шары, которые за один кадр моделирования проходят расстояние сопоставимое с собственным радиусом).

Вработе для простоты будем использовать position-based подход.

Для экономии времени разработка проводится на базе созданного проекта LabWork2_Initial, который содержит шаблон оконного приложения, в котором установлена обработка сообщений WM_DESTROY и WM_SIZE (см. лабораторную работу №1).

Определим необходимое содержимое класса, описывающего объект шара:

1.Позиция шара в мире (окне) (x, y);

2.Радиус шара (r);

3. Вектор скорости шара (v_x, v_y); 4. Границы окна (rect).

Опишем класс (в файле CBall.h, реализация будет CBall.cpp):

Для того, чтобы не было проблем с определением типов системы Windows, не забываем подключить заголовочные файлы windows.h и windowsx.h.

Добавим метод Create для задания параметров:

Его реализация будет выглядеть так:

Продумаем, какие еще методы жизненно необходимы классу шара. Прежде всего это методы Move – для перемещения шара и Draw – для его отрисовки, также реализуем метод SetBounds для установки новых границ окна.

Реализуем метод Move по аналогии с лабораторной работой №1. (Не забудьте добавить описание метода в опеределение класса!):

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

Реализуем метод SetBounds:

Реализуем метод Draw, принимающий на вход контекст рисования:

Простейшая реализация класса шара готова. Добавим ее использование в основное приложение.

Добавим глобальную переменную типа CBall:

Добавим инициализацию параметров шара в функции WinMain непосредственно перед запуском цикла обработки оконных сообщений:

В обработку сообщения WM_SIZE добавляем вызов установки новых границ. Обработчик будет выглядеть так:

В обработку сообщения WM_PAINT добавляем вызов отрисовки. Обработчик будет выглядеть так:

Остается самая главная задача – реализовать OnIdle так, чтобы происходило движение шара.

Задачу расчета времени между кадрами мы переложили на главное приложение. Поэтому в глобальных переменных объявим переменную, отвечающую за время запуска предыдущего кадра:

И начальную инициализацию этого значения в WinMain непосредственно перед стартом цикла обработки сообщений:

Функция OnIdle должна получать текущее время, производить перемещение шара и генерировать сообщение о перерисовке:

Запустим программу и увидим отскакивающий от стенок шарик. Модифицируем приложение так, чтобы можно было работать с

произвольным количеством шариков.

Создадим CBallsArray, который будет управлять нашими шарами (файлы

BallsArray.h и BallsArray.cpp).

Описание класса:

Поле count – текущее число шаров в массиве. Поле max_balls – максимально возможное число шаров в массиве. Поле balls – массив шаров.

Конструктор принимает в качестве параметра максимально возможное число шаров. Метод Add возвращает указатель на новый добавляемый шар или NULL, если шар добавить нельзя.

Реализуем методы:

Введем в класс реализацию общих методов для шаров: Move, Draw, SetBounds. Это делается для того, чтобы переложить основную работу по вызову этих методов на класс CBallsArray.

Переработаем основную программу так, чтобы она работала не напрямую с шарами, а с массивом шаров.

Первым делом избавимся от всего, что работало в основной программе с классом CBall и уберем глобальную переменную CBall ball.

Добавим глобальную переменную CBallsArray:

Параметр 50 задает максимально допустимое число шаров в массиве. Строку:

заменяем на последовательность (для двух шаров):

В реализации обработчика сообщения WM_SIZE заменяем строку:

на

В реализации обработчика сообщения WM_PAINT заменяем строку:

на

В реализации OnIdle заменяем:

на

Если запустить приложение, то в результате мы увидим окно с двумя летающими шариками.

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

WM_LBUTTONDOWN – при нажатии кнопки и WM_LBUTTONUP – при отпускании кнопки. Если пользователь нажал кнопку и, не отпустив, перевел мышь в другое место, то координаты места нажатия кнопки и текущее положение курсора не будут совпадать. Исходя из логики добавление шара надо делать по событию WM_LBUTTONUP, чтобы координаты добавления шара и положение курсора мыши совпадали. Параметр lParam сообщения WM_LBUTTONUP содержит в младшем слове координату X, а в старшем слове – координату Y курсора мыши в момент отпускания мыши. В обработчике этого сообщения можно добавить в систему еще один шар.

Не забываем сделать проверку полученного ball на NULL на случай превышения числа шаров.

Запускаем приложение и щелкаем в окне левой кнопкой мыши.

К сожалению в данный момент мы не управляем ни направлением перемещения создаваемых шаров, ни их скоростью.

Реализуем это следующим образом. При помощи клавиш «влево» и «вправо» мы будем изменять угол скорости шара. При помощи «вверх» и «вниз» будем изменять модуль скорости движения. Перед щелчком мыши

клавиатурой задаем параметры, которые будут переданы создаваемому шару. Остается одна проблема, которую надо решить – пользователь не знает и не видит текущих настроек.

Реализуем визуальный элемент, который будет располагаться в углу окна и показывать текущие заданные скорость и направление движения. Например, скорость длиной стрелки, а направление – направлением стрелки.

Визуальный элемент реализуем в классе CBallSettingsMonitor.

Реализуем методы этого элемента:

В конструкторе задается скорость и направление движения по умолчанию.

Пара методов SpeedUp и SpeedDown увеличивает и уменьшает параметр скорости соответственно. При этом проверяется, если параметр скорости меньше 10 или больше 120, то изменений не происходит. Это сделано для того, чтобы пользователь не смог задать скорость больше максимально допустимой или меньше минимально допустимой.

Пара методов AngleUp и AngleDown аналогичным образом работает с направлением движения нового шарика.

Так как скорость шарика задается отдельно по x и по y, то производится расчет этих значений исходя из направления и скорости. Для работы с функциями sin и cos не забудьте подключить заголовочный файл math.h.

Метод Draw отрисовывает пользовательский элемент в окне.

Теперь модифицируем основную программу. Добавим в глобальные переменные наш объект пользовательского элемента (на забыв подключить заголовочный файл):

В обработчик WM_PAINT перед EndPaint добавляем вызов:

Добавляем обработчик клавиатурных сообщений, вызывая при нажатии клавиш-стрелок соответствующие функции:

Обработчик сообщения WM_LBUTTONUP переписываем следующим образом:

Запускаем программу и проверяем результат – стрелками выбираем скорость и направление, мышью запускаем новый шар.

Добавим реализацию столкновения шаров. Для этого сначала нужно вспомнить немного теории из физики.

Центральные столкновения тел

Рассмотрим два сферических объекта (шарика) с массами m1 и m2. Предположим, что эти шарики движутся без вращения по одной оси и испытывают центральное упругое соударение. В этом случае закон сохранения импульса запишется в виде:

m1v1i + m2v2i = m1v1 + m2v2

где v1i и v2i - начальные скорости каждого объекта, а v1 и v2 - их конечные скорости. Закон сохранения энергии записывается в виде:

m1v1i2 / 2 + m2v2i2 / 2 = m1v12 / 2 + m2v22 / 2

Закон сохранения импульса может быть преобразован следующим образом:

m1 (v1i - v1) = m2 (v2 - v2i)

Также преобразуем выражение для закона сохранения энергии

m1 (v1i2 - v12) = m2 (v22 - v2i2)

Если разница между начальной и конечной скоростями не равна нулю (то есть столкновение действительно произошло), мы можем разделить второе из двух последних уравнений на первое, что дает:

v1i + v1 = v2 + v2i

или

v1i - v2i = v2 - v1

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

Чтобы получить конечные скорости движения объектов через их начальные скорости и массы, нужно выразить v2 из последнего уравнения и подставить его в уравнение для закона сохранения импульса. Окончательно получаем:

v1 = v1i (m1 - m2) / (m1 + m2) + v2i (2 m2) / (m1 + m2)

Таким же способом находим выражение для v2

v2 = v1i (2 m1) / (m1 + m2) + v2i (m2 - m1) / (m2 + m1)

Далее предположим, что сталкиваются объекты с одинаковой массой, т.е. m1= m2 = m. В этом случае:

v1 = v1i (m - m) / (m + m) + v2i (2 m) / (m + m) v2 = v1i (2 m) / (m + m) + v2i (m - m) / (m + m)

Окончательно получаем, что

v1 = v2i и v2 = v1i

Соседние файлы в предмете Компьютерная Графика