ПП_Лаб1
.pdf
перемещение шарика в зависимости от его скорости и направления движения.
Кроме того, раз мы оперируем скоростью, связанной с временем, то нужно реализовать алгоритм засекания временных промежутков между перерисовками, чтобы быстродействие системы не влияло на работу алгоритма. В этом может помочь функция GetTickCount, которая возвращает число миллисекунд, прошедшее с момента запуска системы. Пусть в команду Move будет передаваться текущее значение счетчика, а внутри класса будет запоминаться предыдущее показание счетчика (разница предыдущего и текущего значения даст время в мс между двумя перерисовками).
С учетом вышесказанного описание класса будет выглядеть так:
Реализация функций класса будет выглядеть так:
Внесем изменения в основной код. Прежде всего изменим определение глобальной переменной типа CBall так, чтобы в нее передавались необходимые параметры:
Далее необходимо переработать цикл обработки сообщений таким образом, чтобы в случае отсутствия сообщений можно было использовать процессорное время для реализации физики системы. В этом поможет замена функции GetMessage на функцию PeekMessage. Разница между этими функциями в том, что, если GetMessage ожидает наступления сообщения, то PeekMessage даже в случае отсутствия сообщений немедленно возвращает управление. Измените цикл обработки таким образом:
Функция OnIdle будет вызываться тогда, когда сообщений в очереди нет. Реализуем OnIdle:
InvalidateRect говорит системе, что указанное окно содержит неверную графическую информацию, в ответ на этот вызов система посылает приложению WM_PAINT.
Запуск приложения позволяет увидеть движение шарика, однако есть побочный эффект – мерцание из-за того, что экран постоянно очищается и перерисовывается.
Убрать эффект мерцания можно, если делать отрисовку сцены в памяти, а потом целиком копировать в окно. Однако в нашем случае (простые объекты, простое управление объектами) можно просто ограничить частоту перерисовок. Частота обновления ~50 кадров в секунду будет приемлемой для человеческого глаза. При помощи команды Sleep добавим паузу перед обновлением экрана размером в 20 мс. Мерцание заметно, но уже не настолько:
Далее необходимо подобрать размер шарика и его скорость так, чтобы движение выглядело достаточно динамичным.
Следующим шагом будет реализация отталкивания шарика от стенок окна. Вся реализация алгоритма будет находиться в методе Move класса CBall. Для работы не хватает информации о границах окна. Добавим в класс поле типа RECT, которое будет описывать прямоугольник границ окна. Также добавим метод, устанавливающий границы.
Реализуем метод SetBounds:
Модифицируем метод Move так, чтобы границы окна учитывались при движении:
Дополнительная проверка на знак скорости нужна для того, чтобы избежать залипания шарика, если вдруг он по какой-то причине перейдет границу экрана.
Модифицируем основную программу, чтобы при старте шару передавались текущие границы окна:
Остался один нерешенный момент. Пользователь может изменить размеры окна. При этом необходимо передать новые границы окна шарику.
При изменении размеров окна система отправляет сообщение WM_SIZE. Сделаем обработку этого сообщения:
Здесь создается объект типа RECT, куда записываются значение ширины и высоты окна. Данные значения берутся из параметра lParam сообщения
WM_SIZE.
Добавление дополнительных препятствий
Реализуем дополнительные препятствия. Для простоты препятствие может быть только горизонтальным и будет иметь ширину 1 пиксел.
В отдельном файле CHLimiter.h опишем класс препятствия:
Препятствие характеризуется параметром y – высота расположения и параметрами xmin, xmax – размер и положение по горизонтали. Не забудьте добавить включение файла windows.h.
В файле CHLimiter.cpp реализуем кламм CHLimiter:
Метод MoveToEx перемещает позицию рисования, а метод LineTo – отрисовывает линию с текущей позиции до указанной.
Для добавления границы в программу внесем доработки в основной код программы.
1. Создание объекта:
2. Добавление объекта в отрисовку:
В результате граница появилась на экране, однако пока никакой реакции шарика на эту границу нет.
Добавим в класс шарика параметр – указатель на объект границы и метод передачи границы:
Не забудьте добавить заголовочный файл CHLimiter.h. Реализация метода SetHLimiter:
Модифицируем код приложения, чтобы при инициализации шарика к нему добавлялась информация о границе:
Шарик по-прежнему не реагирует на границу. Для получения реакции нужно модифицировать метод Move класса CBall:
Методику расчета координат шарика и сравнение их с координатами препятствия предлагается изучить и понять самостоятельно.
Движение препятствия в качестве реакции на действия пользователя
Модифицируем код таким образом, чтобы пользователь мог управлять положением препятствия при помощи клавиатуры.
Первым делом добавим методы MoveX и MoveY для препятствия:
Реализуем их:
Параметр inc показывает величину изменения положения.
Для обработки нажатий клавиш система передает приложению набор сообщений, одно из которых (WM_KEYDOWN) мы можем использовать для реализации движения.
Данное сообщение посылается при нажатии клавиши на клавиатуре. В случае, если клавиша не отпущена – сообщение генерируется с определенной периодичностью.
Добавим его обработчик и генерацию реакции на нажатие клавиш для препятствия:
Запустите приложение и попробуйте поуправлять препятствием при помощи клавиш управления курсором.
Следует заметить, что одновременное нажатие клавиш не обрабатывается, а также программа некорректно работает в случае наезда препятствием на шарик. Однако решение этих проблем представляет достаточную сложность, выходящую за рамки работы.
Подготовка отчета
Отчет к лабораторной работе должен включать:
1.Титульный лист.
2.Описание лабораторной работы.
3.Объяснение расчетов ограничений в методе CBall::Move.
4.Реализация индивидуального задания.
Индивидуальные задания
1.Реализуйте в классе CBall возможность задавать цвет шарика и модифицируйте приложение так, чтобы летало 2 шарика разных цветов и размеров.
2.Реализуйте возможность добавлять 2 горизонтальных препятствия, одно из которых подвижно.
3.Реализуйте возможность добавления вертикального подвижного препятствия. Модифицируйте приложение, чтобы было 1 подвижное вертикальное препятствие и неподвижное горизонтальное.
4.Модифицируйте класс CBall так, чтобы можно было управлять скоростью шарика. В обработчике клавиатурных сообщений добавьте реакцию на клавиши A и Q, уменьшающих и увеличивающих скорость шарика, соответственно.
5.Реализуйте препятствия в виде прямоугольников, имеющих толщину. Шарик может отражаться как от горизонтальных, так и от вертикальных граней.
6.Модифицируйте класс CBall и программу так, чтобы по нажатию клавиш можно было менять цвета летающих шариков. Шариков должно быть не менее 2.
7.Модифицируйте класс препятствия так, чтобы была возможность задавать и менять с клавиатуры цвет препятствия.
8.Модифицируйте классы и приложение так, чтобы при столкновении шарика с препятствием менялись цвета шарика и препятствия.
