|
||||||||||||||||||
|
Часть 9. Простой анимационный класс, обновление экрана, обработка ввода с клавиатуры Простой анимационный классЯ хочу создать анимацию с торами, отображая очередной кадр для создания впечатления вращения. Для того, чтобы сделать это как можно легче, я использую объектную ориентацию, добавляя простой анимационный класс. Этот класс хранит позицию спрайта, число кадров в его анимационной последовательности и скорость самой анимации. Это простой класс, но он вносит изменения в код, такие как добавление или удаление спрайтов. Листинг 22 представляет простой анимационный класс. Листинг 22 Простой анимационный класс, integer class integer type function GetCurrentFrame ( TickCount : integer integer constructor Create ( AFrameInterval integer property CurrentFrameC TickCount read GetCurrentFrame ; integer constructor TSimpleAnim. Create ( AFrameInterval : FFrameinterval := AFrameInterval ; integer function TSimpleAnim. GetCurrentFrame ( TickCount if TickCount - FLastTickCount >= FFrameinterval then begin if FCurrentFrame > FNumberOf Frames then FCurrentFrame := Result := FCurrentFrame ; integerКак видите, конструктор Create принимает параметры, определяющие спрайт, и хранит их в полях объекта. Свойство CurrentFrame сообщает нам, какой кадр спрайта должен быть отображен на экране с учетом текущего значения TickCount. CurrentFrame применяется функцией GetCurrentFrame. CurrentFrame использует грубый, но простой метод последовательного перехода на следующий кадр, если время в миллисекундах с момента появления последнего кадра больше, чем Вы добавляете этот код непосредственно в модуль главной формы. Это не компонент, поэтому нет необходимости добавлять его в палитру компонент. Экземпляры создаются в коде только в режиме выполнения. Это делается путем добавления TList, названного Animations, в определение формы. Данный список создается в FormShow, и вы добавляете в нее три анимационных объекта: Animations := TList .Create ; Animations.Add( TSimpleAnim.Create( 48, 60, 260, 120 ) ) ; Заметьте, что второй параметр Create - число кадров в анимационной последовательности - равен 60, Что это означает? Хорошо, если вы откроете ALL.BMP и произведете в нем прокрутку, вы увидите все анимационные кадры, размещенные под фоновым изображением. Их всего 60, и они размещены в шести рядах по 10 изображений в каждом ряду. Главное изображение имеет размер 640х480 пикселей, дабы соотиетстиоиать используемому разрешению экрана. Каждый кадр представляет собой 64-пиксельный квадрат, и десять таких кадров точно вписываются в одно полноэкранное пространство. Обновление экранаТеперь вы готовы написать код для обновления фонового буфера и осуществления быстрой смены кадров. Чтобы зделать это добавьте метод UpdateDisplay, как показано в листинге 23. Листинг 23 Обновление экрана с элементами анимации. procedure TFormI . UpdateDisplay ; // обновить и сменить поверхности - вначале перенести фон until MakeltSo( BackBuffer.BitFast( 0, 0, Image, ARect, DDBLTFAST_NOCOLORKEY ) ) ; for i :== 0 to Animations-Count - I do begin ( ACurrentFrame div 10) * 64+ 480, 64, 64 ) ; until MakeltSo( BackBuffer.BltFast( X, Y, Image, ARect, DDBLTFAST_SRCCOIiORKEY*) ) ; until MakeltSo( PrimarySurf ace. Flip ( NIL, DDFLIP_WAIT ) ) ; Первым делом эта процедура переносит фоновое изображение в фоновый буфер. Помните, что верхняя часть ALLBMP является фоном, ARect создается, чтобы определить прямоугольную область части растрового изображения и BItFast. Фун- Теперь проведите битовый перенос для каждой анимации. Получите значение TickCount и затем пройдите в цикле список Anirnations. Получите текущий анимационный кадр и затем подсчитайте позицию этого кадра в ALLBMP. Рассчитайте координату х с помощью операции вычисления остатка по модулю между текущим кадром и числом кадров в одном ряду. Это даст число до 10, что определит индекс кадра в ряду. Это значение умножается на ширину каждого кадра, то есть на 64. Координата у подсчитывается путем деления номера кадра на 10, что даст сначала номер кадра ц ряду; умножения номера кадра в ряду на высоту каждого ряда, которая равна 64, и добавления 480. Это место, где в ALLBMP начинаются кадры - Как только вся анимация будет нарисована, произойдет смена страницы. Тут есть существенный момент, о котором необходимо помнить: смена страницы не происходит, пока не закончится вертикальная развертка, поэтому приложение Изображение на экране компьютера создается с помощью луча электронов, который начинает падать на экран вверху слева, отражает горизонтальные линии картины одну под другой слева направо. пока не достигните нижнёго правого
Листинг 24 Метод Move передвигает аннимационный объект в пределах экрана. procedure TForinl.Move( dx, dy : integer ) ; if Assigned ( Animations ) then begin nTo : = Animations. Count - I ; for i := nFrom to nTo do begin Метод использует два параметра, которые представляют расстояние в пикселах для передвижения анимационного объекта относительно каждой из осей. Я добавил к форме еще одно поле, называемое MovedOption. MoveOption принимает положительное значение типа integer: 0 означает, что будут передвигаться все анимационные объекты, и любое другое число разрешает передвижение только определенного анимационного объекта. Определив диапазон использования анимационных объектов (либо все объекты вместе, либо один единственный объект), вы циклически проходите массив Animations, добавляя dx и dy в каждую анимационную позицию. Move также следит за тем, чтобы анимационные объекты не выходили за пределы экрана. Обработка ввода с клавиатурыЯ модифицировал обработчик OnKeyDown для обработки нажатий клавиш курсора, которые используются для передвижения анимационных объектов по экрану, как представлено в листинге 25. Листинг 25 Передвижение анимационных объектов с помощью клавиш курсора. procedure TForml.FormKeyDown (Sender: TObject; var Key: Word; Shift: TShiftState) ; Anoption : integer ; if ssShift in Shift then Speed := I ; VK_ESCAPE, VK_F12 : Close ; if Abs( XVelocity ) > I then XVelocity := XVelocity div 4 ; end ; by1:e( '0' )..byte( '9' ) : begin if Anoption <= Animations. Count then MoveOption : = Anoption Если удерживать клавишу Shift, анимационный объект будет передвигаться в четыре раза медленней, для этого необходимо определять значение локальной переменной Speed. Я добавил поля скоростей XVelocity и YVelocity, которые получают значение при нажатии какой-либо из клациш курсора. Клавиша Shift при нажатии снижает скорость, если она еще недостаточно медленная. Клавиши от 0 до 9 определяют значение MoveOption, которое указывает, каким объектам перемещаться. Заметьте, что наличие мониторинга нажатия определенной клавиши означает, что анимационный объект может по-разному реагировать на различные комбинации клавиш. В этом случае, вы можете передвигать спрайты по диагонали, если вы будете удерживать сразу две клавиши управления курсором. Теперь необходимо ввести обработчик ОпКеу1}рдля учета количества отжатия клавиши. Это представлено в листинге 26. Листинг 26 Отслеживание отжатых клавиш. procedure TForml.FormKeyUp (Sender: TObject; var Key: Word; begin case Key of VK_RIGHT : XVelocity := 0 ; VK_DOWN : YVelocity :== 0 ; Как вы видите, движение прекращается ь горизонтальном и вертикальном направлениях, если клавиша управления курсором отпущена, и скорость увеличивается в четыре раза, если отпускается клавиша Shift. Вхождение в цикл сообщенийТеперь, когда главный код у вас в сборе, вы должны найти место для вызова UpdateDisplay. Фактически, вы можете вызывать ее как можно чаще для того, чтобы получить максимально возможную скорость смены кадров. На языке С или даже Pascal, вам необходимо было войти в цикл сообщения и вызывать UpdateDisplay всякий раз при повторном прохождении цикла. Это можно сделать и в Delphi, но это несколько замысловато, ввиду того, что Delphi обладает своим собственным циклом Вместо этого можно добавить код в события Onidle и OnMessage переменной Application. Вы можете взглянуть на объявления обработчиков этих событий в диалоговой справке Delphi и добавить их в качестве методов в свою форму. Вот как procedure HandleMessage( var Msg : TMsg ; var Handled : boolean ) ; procedure ldleHandler( Sender : TObject ; Они, как и любой другой метод, добавляются в секцию private объявления формы. Применять их легко, главным образом нужно просто вызвать UpdateDisplay. Нужно только учесть один существенный момент - необходимо установить Done в False в IdleHandler, чтобы убедиться, что VCL не отдает управление в ожидании сообщения Windows, что приостановило бы обновление экрана. Это показано в листинге 27. Листинг 27 Обновление экрана с максимально возможной скоростью. procedure TForml.HandleMessage( var Msg : TMsg ; var Handled : boolean ) ; begin end ; begin В конечном итоге добавьте ь форму свойство FlippingEnabled, объявив его, как показано в листинге 28. Листинг 28 Добавление в форму свойства FlippingEnabled. type TFormI = class( TForm ) * * FFlippingEnabled : boolean ; property FlippingEnabied : boolean read FFlippingEnabled write SetFlippingEnabled ; |
|
Web дизайн: Бурлаков Михаил
Web программирование: Бурлаков Михаил