Сдам Сам

ПОЛЕЗНОЕ


КАТЕГОРИИ







Анимация на основе операции XOR





 

Первый способ основан на хитром свойстве логической операции XOR. Поместим на форму кнопку и объект Image1 с шириной, в два раза превышающей высоту. Сначала нарисуем небо – это мы уже умеем. Теперь надо нарисовать летающую тарелку. Их толком никто не видел, поэтому особой точности в деталях не требуется. Давайте вынесем команды рисования тарелки в отдельную процедуру, это заметно облегчит жизнь в дальнейшем.

 

PROCEDURE Ufo(x,y:INTEGER);

BEGIN

WITH Form1.Image1.Canvas DO

BEGIN

Pen.Color:=clBlue;

Pen.Width:=3;

Ellipse(x,y,x+20,y+10)

END

END;

 

Осталось организовать движение тарелки по экрану. Делается это в обработчике нажатия на кнопку примерно так:

 

Pen.Mode:=pmNOTXOR;

FOR i:=0 TO Image1.Width DO

BEGIN

Ufo(i, i DIV 2);

Application.ProcessMessages;

Sleep(10);

Ufo(i, i DIV 2)

END

END;

 

Самая важная строчка в этом фрагменте - Pen.Mode:=pmNOTXOR. Она устанавливает режим вывода графики "исключающее ИЛИ". При таком режиме вывод одной и той же картинки дважды в одно и то же место изображения приводит к автоматическому восстановлению фона под картинкой. Такой эффект основан на свойстве логической операции "исключающее ИЛИ": если a XOR b=c, то с XOR b=a. В цикле картинка выводится первый раз (вызов процедуры Ufo), затем выполняется команда Application.ProcessMessages, обеспечивающая немедленное отображение НЛО на экране и делается задержка на 10мс, чтобы мы успели увидеть, что получилось. Далее НЛО выводится в то же самое местоеще раз, при этом изображение тарелки пропадет, а под ней автоматически восстановится фон. Координаты тарелки меняются и по Х, и по Y, поэтому она поедет по экрану вправо вниз.

Запускаем… Красиво? Нет! Экран безобразно мерцает. Что делать? Спокойно, это просто еще один фокус Delphi. Чтобы динамическое изображение на форме не мерцало, в начало процедуры вывода анимации надо добавить строчку



 

Form1.DoubleBuffered:=TRUE;

 

Окончательный вариант обработчика имеет вид:

 

procedure TForm1.Button1Click(Sender: TObject);

 

var i:word;

 

begin

DoubleBuffered:=true;

with Image1.Canvas do

begin

Brush.Color:=clBlack;

FillRect(Image1.ClientRect);

for i:=1 to 500 do

Pixels[Random(Image1.Width),Random(Image1.Height)]

:=clWhite;

Pen.Mode:=pmNOTXOR;

FOR i:=0 TO Image1.Width DO

BEGIN

Ufo(i, i DIV 2);

Application.ProcessMessages;

Sleep(10);

Ufo(i, i DIV 2)

END

END

end;

 

Вот теперь наш мультик будет смотреться вполне неплохо, если бы не одна неприятность. Мы заказывали тарелку синего цвета (строчка Pen.Color:=clBlue), а получили желтого. Причина – в операции "исключающее ИЛИ". Она неизбежно искажает цвета выводимых на экран точек. Поэтому создать нормальную многоцветную анимацию таким способом затруднительно.

Буферизация фона

Воспользуемся способом №2, известным как "буферизация фона". Его идея даже проще – нужно перед отрисовкой каждого кадра запоминать фон под движущимся элементом картинки в отдельной переменной, а затем восстанавливать его. Наша летающая тарелка вписывается в прямоугольник с координатами (x,y) – (x+20,y+10). Чтобы запомнить такой фрагмент изображения, понадобится глобальная переменная типа TBitMap. Ее надо проинициализировать в начале работы программы (событие формы OnCreate) и удалить из памяти перед завершением работы (событие формы OnDestroy). Также введем константы UFOWidth и UFOHeight для хранения габаритных размеров перемещаемого фрагмента изображения и немного украсим нашу тарелку.

 

var Form1:TForm1;

mm:TBitMap;

 

const UFOWidth=20;

UFOHeight=10;

 

PROCEDURE Ufo(x,y:INTEGER);

 

begin

WITH Form1.Image1.Canvas DO

BEGIN

Pen.Color:=clBlue;

Brush.Color:=clWhite;

Pen.Width:=1;

Ellipse(x,y,x+UFOWidth,y+UFOHeight);

Pen.Color:=clRed;

MoveTo(x,y+UFOHeight DIV 2);

LineTo(x+UFOWidth,y+UFOHeight DIV 2)

END

END;

 

procedure TForm1.FormCreate(Sender: TObject);

begin

mm:=TBitMap.Create;

// задаем размеры буфера, равные размерам НЛО

mm.Width:=UFOWidth;

mm.Height:=UFOHeight

end;

 

procedure TForm1.FormDestroy(Sender: TObject);

begin

mm.Free

end;

 

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

 

procedure TForm1.Button1Click(Sender: TObject);

 

var i:word;

 

begin

DoubleBuffered:=true;

with Image1.Canvas do

begin

Brush.Color:=clBlack;

FillRect(Image1.ClientRect);

// вывод звездного неба

for i:=1 to 1500 do

Pixels[Random(Image1.Width),Random(Image1.Height)]:=

clWhite;

FOR i:=0 TO Image1.Width DO

BEGIN

// Запоминаем фрагмент в буфере

mm.Canvas.CopyRect(Rect(0,0,mm.Width,mm.Height),

Image1.Canvas,Rect(i,i DIV 2,i+UFOWidth,I DIV 2

+ UFOHEight));

// Рисуем НЛО

Ufo(i, i DIV 2);

// Ждем

Application.ProcessMessages;

Sleep(30);

// Восстанавливаем фон

Image1.Canvas.Draw(i,i DIV 2,mm);

END

END

end;

 

Метод C1.CopyRect(R1,C2,R2) копирует изображение, содержащееся в прямоугольнике R2 на холсте С2, в прямоугольник R1 на холсте С1. Разумеется, прямоугольники должны быть одинакового размера, хотя и могут находиться в разных частях холстов.

Метод C1.Draw(x,y,m) выводит изображение, хранящееся в переменной m типа TBitMap, на холст C1 в точке x,y.

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

 

Работа с таймером

 

Интересная возможность Delphi – создание процедур, автоматически выполняющихся через заданные промежутки времени. Для этого используется специальный объект Timer ( ), находящийся на закладке System. Этот объект – невизуальный, он не отображается на форме во время работы программы и его можно разместить в любом ее месте.

Главное свойство объекта Timer называется Interval и задает время в миллисекундах, по истечении которого таймер вызывает процедуру, присоединенную к его событию OnTimer. Свойство Enabled включает и выключает таймер. Когда таймер включен, он постоянно и незаметно для пользователя отсчитывает время и, как только пройдет заданный интервал, выполняет заданную процедуру, затем снова начинает отсчитывать время и т.д.

Простейший пример работы таймера – вывод в заголовке формы текущего времени. Настроим таймер так, чтобы он вызывал процедуру каждую секунду. Для этого свойство Interval нужно установить в 1000, а свойство Enabled – в True. Обработчик события OnTimer имеет вид:

 

procedure TForm1.Timer1Timer(Sender: TObject);

 

begin

Form1.Caption:=TimeToStr(Now)

end;

Заставим наше НЛО мигать – менять цвет при движении – при помощи таймера. Настроим таймер так, чтобы он срабатывал каждые 100мс. Для управления цветом заливки НЛО придется ввести глобальную переменную clr, задав ей начальное значение clGreen

 

var clr:TColor=clGreen;

 

Обратите внимание на интересную особенность Delphi – глобальным переменным можно задавать начальные значения. В нашем случае в переменную clr с самого начала будет занесено значение clGreen (код зеленого цвета). TColor – это системный тип данных, предназначенный для хранения кодов цветов.

В процедуре таймера мы должны циклично менять значение переменной clr. Делается это так:

 

procedure TForm1.Timer1Timer(Sender: TObject);

begin

if clr=clGreen then

clr:=clRed

else

clr:=clGreen

end;

 

Здесь в переменную clr будут циклически заноситься то значение clGreen, то clRed.

Изменим процедуру Ufo, чтобы в ней использовалась переменная clr. Для этого заменим всего одну строчку на Brush.Color:=clr. Все! При запуске программы НЛО будет не только лететь по экрану, но и мигать то красным, то зеленым.

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

 

Лекция 17









Что делает отдел по эксплуатации и сопровождению ИС? Отвечает за сохранность данных (расписания копирования, копирование и пр.)...

Что вызывает тренды на фондовых и товарных рынках Объяснение теории грузового поезда Первые 17 лет моих рыночных исследований сводились к попыткам вычис­лить, когда этот...

Что будет с Землей, если ось ее сместится на 6666 км? Что будет с Землей? - задался я вопросом...

Что делать, если нет взаимности? А теперь спустимся с небес на землю. Приземлились? Продолжаем разговор...





Не нашли то, что искали? Воспользуйтесь поиском гугл на сайте:


©2015- 2021 zdamsam.ru Размещенные материалы защищены законодательством РФ.