Мультипликация
Как было показано выше, рисунок может быть сформирован из графических примитивов (линий, окружностей, луг, многоугольников и т. д.). Обеспечить перемещение рисунка довольно просто: надо сначала вывести рисунок на экран, затем через некоторое время стереть его и снова вывести этот же рисунок, но уже на некотором расстоянии от его первоначального положения. Подбором времени между выводом и удалением рисунка, а также расстояния между старым и новым положением рисунка (шага перемещения), можно добиться того, что у наблюдателя будет складываться впечатление, что рисунок равномерно движется по экрану. {replace on}
Следующая простая программа, текст которой приведен в листинге 10.8, а вид формы — на рис. 10.15, демонстрирует движение окружности от левой к правой границе окна программы.
Рис. 10.15. Форма программы Движущаяся окружность

Листинг 10.8. Движущаяся окружность
01.unit mcircle ;02.interface03.uses04.Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls;05.type06.TForml = class(TForra)07.Timer1: TTimer;08.procedure TimerlTimer(Sender: TObject);09.procedure FormActivatejSender: TObject);10.private11.{Private declarations }12.public13.{ Public declarations }14.end;15.implementation16.{$R *.DEW}17.var18.Form1; TForm;19.x,y: byte; // координаты центра окружности20.dx: byte; // приращение координаты х при движении окружности21.// стирает и рисует окружность на новом месте22.procedure Ris;23.begin24.// стереть окружность25.fоml.Canvas.Pen.Color:=forml.Color;26.forml.Canvas.Ellipse [x,y,x+10,y+10) ;27.x:=x+dx;28.// нарисовать окружность на новом месте29.forml.Canvas.Pen.Color:=c!Black;30.forml.Canvas.Ellipse(х,у,x+10,y+10);31.end;32.// сигнал or таймера33.procedure TForml.TimerlTiroer(Sender: TObject];34.begin35.Ris;36.end;37.procedure TForml.FormActivate(Sender: TObject);38.begin39.y:=10;40.dx:=5;41.tirnerl. Interval: =50; // период возникновения события OriTimer — 0.5 сек42.forml.canvas.brush.color:=forml.color;43.end;44.end.
Основную работу выполняет процедура RIS, которая стирает окружность и выводит ее на новом месте. Стирание окружности выполняется путем перерисовки окружности поверх нарисованной, но цветом фона.
Для обеспечения периодического вызова процедуры Ris в форму программы добавлен невизуальный компонент Timer (таймер), значок которого находится на вкладке System палитры компонентов (рис. 10.16). Свойства компонента Timer, перечислены в табл. 10.9.
Рис. 10.16. Значок компонента Timer

Добавляется компонент Timer к форме обычным образом, однако, поскольку компонент Timer является невизуальным, т. е. во время работы программы не отображается на форме, его значок можно поместить в любое место формы.
Таблица 10.9, Свойства компонента Timer

Компонент Timer генерирует событие OnTimer. Период возникновения события OnTimer измеряется в миллисекундах и определяется значением свойства interval. Следует обратить внимание на свойство Enabled. Оно дает возможность программе "запустить" или "остановить" таймер. Если значение свойства Enabled равно False, то событие OnTimer не возникает.
Метод базовой точки
При программировании сложных изображений, состоящих из множестваэлементов, используется метод, который называется методом базовой точки.
Суть этого метода заключается в следующем:
- Выбирается некоторая точка изображения, которая принимается за базовую.
- Координаты остальных точек отсчитываются от базовой точки.
- Если координаты точек изображения отсчитывать от базовой в относительных единицах, а не в пикселах, то обеспечивается возможность масштабирования изображения.
На рис. 10.17 приведено изображение кораблика. Базовой точкой является точка с координатами (x0, y0). Координаты остальных точек отсчитываются именно от этой точки.
Рис. 10.17. Определение координат изображения относительно базовой точки

В листинге 10.9 приведен текст программы, которая выводит на экран изображение перемешающегося кораблика.
Листинг 10.9. Кораблик
01.unit ship_;02.interface03. 04.uses05.Windows, Messages, SysOtils, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls, ExtCtrls;06.type07.TForml = class(TForra)08.Timer!: TTiraer;09.procedure TimerlTimer(Sender: TObject];10.procedure FormActivate(Sender: TObject);11.private12.{ Private declarations }13.public14.{ Public declarations }15.end;16.var17.Form1: TForm1;18.x,y: integer; // координаты корабля (базовой точки)19.implementation20.{SR *.DFM}21.// вычерчивает кораблик22.procedure Titanik(x,y: integer; // координаты базовой точки23.color: TColor]; // цвет корабля24.const25.dx - 5;26.dy = 5;27.var28.buf: TColor;29.begin30.with forml.canvas do31.begin32.buf:=pen.Color; // сохраним текущий цвет33.pen.Color:=color; // установим нужный цвет34.// рисуем . . .35.// корпус36.MoveTo(x,y] ;37. 38.LineTo(к,y-2*dy);39.LineTo(x+10*dx,y-2*dy);40.LineTo(x+ll*dx,y-3*dy) ;41.LineTo(x+17*dx,y~3*dy);42.LineTo (x+1-4*dx,y);43.LineTo(x,y);44.// надстройке45.MoveTo(x+3*dx,y-2*dy);46. 47.LineTo(x+4*dx,y-3*dy) ;48.LineTo (x+4*dx, y-4dy);49.LineTo(x+13*dx,y-4*dy);50.LineTo(x+13*dx,y-3*dy);51.MoveTo (x-f5*dx, y-3*dy) ;52.LineTo (x+9*dx,y-3*dy);53.// капитанский мостик54. 55.Rectangle(x+8*dx,y-4*dy,x+ll*dx,y-5*dy|;56.// труба57.Rectangle(x+7*dx,y-4*dy,x+8*dx,y-7*dy);58.// иллюминаторы59.Ellipse(x+ll*dx,y-2*dy,x+12*dx,y-l'dy);60.Ellipse (x+13*dx,y-2*dy,x-t-14*dx,y-l*dy) ;61.// мачта62.MoveTo(x+10*dx,y-5'dy);63.LineTo (x-HO*dx,y-10*dyi ;64.// оснастка65.MoveTo(x+17*dx,y-3*dy);66.LineTo(x+10*dx,y-10*dy| ;67.LineTo(x,y-2*dy);68.pen.Color:=buf; // восстановим старый цвет карандаша69.end;70.end;71.// обработка сигнала таймера72. 73.procedure TForml.TimerlTiiner(Sender: TObject];74.begin75.Titanik{x,y,forml.color); // стереть рисунок76.if x < Form1.ClientWidth then x := x+5 else begin // новый рейс77.x := О;78.у := Random(50] + 100;79.end;80.Titanik(x,y,clffliite); // нарисовать в новой точке81.end;82.procedure TForml.FormActivatelSender: TObject);83.begin84.x:=0;85.y:=100;86.Forml.Color:=clNavy;87.Timer1.Interval := 50; // сигнал таймера каждые 50 миллисекунд88.end;89.end.
Отрисовку и стирание изображения кораблика выполняет процедура Titanik, которая получает в качестве параметров координаты базовой точки и цвет, которым надо вычертить изображение кораблика. Если при вызове процедуры цвет отличается от цвета фона формы, то процедура рисует кораблик, а если совпадает— то "стирает". В процедуре Titanik объявлены константы dx и dy, определяющие шаг (в пикселах), используемый при вычислении координат точек изображения. Меняя значения этих констант, можно проводить масштабирование изображения.
Использование битовых образов
В предыдущем примере изображение формировалось из графических примитивов. Теперь рассмотрим, как можно реализовать перемещение одногосложного изображения на фоне другого, например перемещение самолета на фоне городского пейзажа.
Эффект перемещения картинки может быть создан путем периодической перерисовки картинки с некоторым смещением относительно ее прежнегоположения. При этом предполагается, что перед выводом картинки в новой точке сначала удаляется предыдущее изображение. Удаление картинки может быть выполнено путем перерисовки всей фоновой картинки или только той ее части, которая перекрыта битовым образом движущегося объекта.
В рассматриваемой программе используется второй подход. Картинка выводится применением метода Draw к свойству canvasкомпонента image, a стирается путем копирования (метод CopyRect) нужной части фона из буфера на поверхность компонентаimage.
Форма программы приведена на рис. 10.18, а текст — в листинге ШЛО.
Компонент image используется для вывода фона, а компонент Timer — для организации задержки между циклами удаления и вывода на новом месте изображения самолета.
Листинг 10.10. Летящий самолет
01.unit anim_;02.interface03.uses04.Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,05.Dialogs, ExtCtrls, StdCtrls, Buttons;06.type07.TForml = class(TForm)08.Timerl: TTimer;09.Irnagel: TImage;10.procedure ForraActivate(Senderr TObject);11.procedure TimerlTimer(Sender: TObject);12.procedure FormClose(Sender: TObject; var Action: TCloseAction);13.private14.{ Private declarations }15.public16.{ Public declarations}17.end;18.var19.Forml: TForm;20.implementation21.{$R*.DFM}22.var23.Back, bitmap, Buf : TBitMap; // фон, картинка, буфер24.BackRct : TRect; // область фона, которая должна быть25.// восстановлена из буфера26.BufRct: Ttect; // область буфере, которая используется для27.// восстановления фона28.х,у:integer; // текущее положение картинки29.W,H: integer; // размеры картинки30.procedure TForml.FormActivatefSender: TObject);31.begin32.// создать три объекта — битовых образа33.Back := TBitmap.Create; // фон34.bitmap := TBitmap.Create; // картинка35.Buf := TBitmap.Create; // буфер36.// загрузить и вывести фон37.Back.LoadFromFilei'factory.bmp'J;38.Forml.Imagel.canvas.Draw(0,0,Back);39.// загрузить картинку, которая будет двигаться40.bitmap.LoadFromFile('aplane.bmp');41.// определим "прозрачный" цвет42.bitmap.Transparent := True;43.bitmap.TransParentColor := bitmap.canvas.pixels[1,1];44.// создать буфер длл сохранения копии области фона,45.// на которую накладывается картинка46.W:= bitmap.Width;47.Н:= bitmap.Height;48.Buf.Width;= W;49.Buf.Height:=H;50.Buf.Palette:=Back.Palette; // Чтобы обеспечить соответствие палитр ! !51.Buf.Canvas.CopyMode:=cmSrcCopy;52.// определим обласгь буфера, которая будет использоваться53.// для восстановления фона54.BufRet:^Bounds(0,0,W,H);55.// начальное положение картинки56.к := -W;57.у := 20;58.// определим сохраняемую область фона59.BackRct:=Bounds(x,у,W,H);60.// и сохраним ее61.Buf.Canvas.CopyRect(BufRct,Back.Canvas,BackRct);62.end;63.// обработка сигнала таймера64.procedure TForml.TimerlTimer(Sender: TObject);65.begin66.// восстановлением фона (из буфера) удалим рисунок67.Forml.imagel.canvas.Draw(x,у,Buf);68.x:=x+2;69.if x>forml.Imagel.Width than x:=-W;70.// определим сохраняемую область фона71.BackRct:=Bounds(x,у,W,H);72.// сохраним ее копию73.Buf.Canvas.CopyRect(BufRet,Back.Canvas,BackRct];74.// выведем рисунок75.Forml.imagel.canvas.Draw(x,у,bitmap);76.end;77.// завершение работы программы78.procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);79.begin80.// освободим память, выделенную81.// для хранения, битовых образов82.Back.Free;83.bitmap. Free;84.Buf.Free;85.end;86.end.
Рис. 10.18. Форма программы Самолет
Для хранения битовых образов (картинок) фона и самол
