Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Новости ИТ Программы Книги Games   Обои   Экспорт RSS E-Books
 
Поиск по сайту

TOP-10 программ
Symantec Norton Ghost 9.0
Partition Magic 8.0.2 Pro
Xilisoft 3GP Video Converter v3.1.7.0616b
Norton AntiVirus 2005
Xilisoft 3GP Video Converter v2.1.52.831b
Антивирус Касперского Personal 5.0.303 beta 2
RAR Password Cracker 4.12
ABBYY PDF Transformer v1.00.820
MP3 To Ringtone Gold v3.02
Mobtime Cell Phone Manager v5.3.1
 
Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
 
 

   Программирование -> Delphi / Pascal -> Программирование анимации в Delphi


Программирование анимации в Delphi

В этом примере показано, как, объеденив классы Delphi 5 с функциями Win32 GDI, можно добиться анимации упрощенного избражения эльфа.

Исходные тексты можно взять здесь.

Запустить пример.

unit MainFrm;

interface

uses
   SysUtils, WinTypes, WinProcs, Messages, Classes,
   Graphics, Controls, Forms, Dialogs, Menus, Stdctrls;

{$R SPRITES.RES } {Привязка растровых изображений к 
                   исполняемому файлу.}

type
   TSprite = class
   private
   FWidth: integer;
   FHeight: integer;
   FLeft: integer;
   FTop: integer;
   FAndImage, FOrImage: TBitMap;
   public
   property Top: Integer read FTop write FTop;
   property Left: Integer read FLeft write FLeft;
   property Width: Integer read FWidth write FWidth;
   property Height: Integer read FHeight write FHeight;
   constructor Create;
   destructor Destroy; override;
 end;

TMainForm = class(TForm)
   procedure FormCreate(Sender: TObject);
   procedure FormPaint(Sender: TObject);
   procedure FormDestroy(Sender: TObject);
 private
   BackGnd1, BackGnd2: TBitMap;
   Sprite: TSprite;
   GoLeft, GoRight,GoUp,GoDown: boolean;
   procedure MyIdleEvent(Sender: TObject;
                         var Done: Boolean);
   procedure DrawSprite;
 end;

const

BackGround = 'BACK2.BMP';

var
   MainForm: TMainForm;

implementation

{$R *.DFM}

constructor TSprite.Create;
begin
   inherited Create;
{ Создание растров для хранения изображений эльфа,
     которые будут использованы при выполнении операции 
     AND/OR (И/ИЛИ) для содания анимации }
   FAndImage := TBitMap.Create;
   FAndImage.LoadFromResourceName(hInstance, 'AND');

   FOrImage := TBitMap.Create;
   FOrImage.LoadFromResourceName(hInstance, 'OR');

   Left := 0;
   Top := 0;
   Height := FAndImage.Height;
   Width := FAndImage.Width;
end;

destructor TSprite.Destroy;
begin
   FAndImage.Free;
   FOrImage.Free;
   inherited Destroy;
end;


procedure TMainForm.FormCreate(Sender: TObject);
begin
   // Создание исходного фонового изображения
   BackGnd1 := TBitMap.Create;
   with BackGnd1 do
   begin
     LoadFromResourceName(hInstance, 'BACK');
     Parent := nil;
     SetBounds(0, 0, Width, Height);
   end;

   // Создание копии фонового изображения
   BackGnd2 := TBitMap.Create;
   BackGnd2.Assign(BackGnd1);

   // Создание изображения эльфа
   Sprite := TSprite.Create;

   // Инициализация переменных направления
   GoRight := true;
   GoDown := true;
   GoLeft := false;
   GoUp := false;

   { Установка события приложения OnIdle равным значению
     MyIdleEvent, с которого начнется движение эльфа }
   Application.OnIdle := MyIdleEvent;
   // Установка высоты и ширины области клиента формы
   ClientWidth := BackGnd1.Width;
   ClientHeight := BackGnd1.Height;
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
   // Освобождение всех объектов, созданных в конструкторе
    формы FormCreate()
   BackGnd1.Free;
   BackGnd2.Free;
   Sprite.Free;
end;

procedure TMainForm.MyIdleEvent(Sender: TObject;
                                var Done: Boolean);
begin
   DrawSprite;
   { Разрешение вызова события OnIdle даже при отсутствии
     сообщений в очереди сообщений приложения }
   Done := False;
end;

procedure TMainForm.DrawSprite;
var
  OldBounds: TRect;
begin

  // Сохранение границ эльфа в объекте OldBounds
  with OldBounds do
  begin
    Left := Sprite.Left;
    Top := Sprite.Top;
    Right := Sprite.Width;
    Bottom := Sprite.Height;
  end;

  { Теперь изменяем границы эльфа, чтобы он двигался в одном
    направлении, или изменяем направление при
    соприкосновении с границами формы }
  with Sprite do
  begin
    if GoLeft then
      if Left > 0 then
         Left := Left - 1
      else begin
        GoLeft := false;
        GoRight := true;
      end;

    if GoDown then
      if (Top + Height) < self.ClientHeight then
         Top := Top + 1
      else begin
         GoDown := false;
         GoUp := true;
      end;

     if GoUp then
       if Top > 0 then
          Top := Top - 1
       else begin
          GoUp := false;
          GoDown := true;
       end;
	   
     if GoRight then
        if (Left + Width) < self.ClientWidth then
           Left := Left + 1
        else begin
           GoRight := false;
           GoLeft := true;
        end;
     end;
   { Стираем исходное изображение эльфа на фоне BackGnd2
     путем копирования прямоугольника из фона BackGnd1 }
   with OldBounds do
    BitBlt(BackGnd2.Canvas.Handle, Left, Top, Right, Bottom,
           BackGnd1.Canvas.Handle, Left, Top, SrcCopy);
    { Теперь рисуем эльфа на "внеэкранном" растре, тем самым
      избавлясь от мерцания }
   with Sprite do
   begin
   { Создадим черное пятно с силуэтом эльфа с помощью
     операции логического И, выполненной над растрами
     FAndImage и BackGnd2 }
   BitBlt(BackGnd2.Canvas.Handle, Left, Top, Width, Height,
          FAndImage.Canvas.Handle, 0, 0, SrcAnd);
   // Выполним заливку черного пятна исходными цветами эльфа 
   BitBlt(BackGnd2.Canvas.Handle, Left, Top, Width, Height,
          FOrImage.Canvas.Handle, 0, 0, SrcPaint);
   end;
    { Копируем эльфа в его новой позиции на канву формы.
      При этом используется прямоугольник, который немного
      больше, чем нужно для фигуры эльфа. Тем самым мы
      добиваемся эффективного стирания эльфа путем его
      перезаписи, после чего рисуем нового эльфа в новой
      позиции с помощью доного вызова функции BitBlt } 
   with OldBounds do
   BitBlt(Canvas.Handle, Left-2, Top-2, Right+2, Bottom+2,
          BackGnd2.Canvas.Handle, Left-2, Top-2, SrcCopy);
end;
procedure TMainForm.FormPaint(Sender: TObject);
begin
   // Рисуем фоновой изображение при закрашивании формы 
   BitBlt(Canvas.Handle, 0, 0, ClientWidth, ClientHeight,
          BackGnd1.Canvas.Handle, 0, 0, SrcCopy);
end;

end.

Как это работает. Анимационный проект состоит из фонового изображения и нарисованного на нем эльфа в виде летающего блюдца, которое перемещается в пределах области клиента фона. Фон представлен растровым изображением разбросанных по небу звезд (рис 1).


Рис 1.

Эльф составлен из двух растров размером 64x32. О них речь пойдет ниже, а пока рассмотрим, что происходит в программе. В приведенном модуле определяется класс TSprite, который содержит поля, предназначенные для хранения позиций эльфа на изображении фона, и два объекта типа TBitmap для хранения растровых изображений эльфа. Конструктор TSprite.Create создает оба экземпляра класса TBitmap и загружает их реальными растрами. Оба растровых изображения эльфа и фоновый растр содержатся в файле ресурсов, который привязывается к проекту путем включения в основной модуль следующей инструкции: { $R SPRITES.RES }.

После загрузки растра устанавливаются границы изображения эльфа. Деструктор TSprite.Destroy освобождает оба экземпляра растра. Главная форма содержит два объекта типа TBitmap, объект TSprite и индикаторы напрвлений, задающие линию движения эльфа. Кроме того, в главной форме определены два метода: MyIdleEvent(), служащий обработчиком событий Application.OnIdle, и DrawSprite(), предназначенный для рисования изображения эльфа.

Обработчик событий FormCreate() создает оба экземпляра класса TBitmap и загружает каждый одним и тем же растровым изображением (зачем - разберемся чуть ниже). Затем создается экземпляр класса TSprite, устанавливаются значения индикаторов направлений и обработчику событий Application.OnIdle назначается метод MyIdleEvent(). Наконец, обработчик событий формы FormCreate() изменяет размеры формы в соответствии с размерами фонового изображения.

Метод FormPaint() выполняет рисование на канве фона BackGnd1.

Метод FormDestroy() освобождает экземпляры классов TBitmap и TSprite.

Метод MyIdleEvent() вызывает метод DrawSprite(), который перемещает и рисует эльфа на существующем фоне.

Метод MyIdleEvent() вызывается, когда приложение находится в состоянии ожидания, т.е. когда пользователь не выполняет никаких действий, на которые приложению следовало бы отреагировать.

Метод DrawSprite() изменяет расположение эльфа на изображении фона. Для этого требуется выполнить немало инструкций - ведь сначала нужно стереть старое изображение эльфа, а затем нарисовать его на новом месте, сохраняя цвет фона вокруг реального изображения эльфа. Кроме того, метод DrawSprite() должен выполнить эти действия без мерцания. Для достижения поставленных целей процесс рисования выполняется на "внеэкранном" растре BackGnd2. Растры BackGnd2 и BackGnd1 являются точными копиями фонового изображения, однако BackGnd1 никогда не модифицируется (поэтому его можно назвать чистой копией фона). По завершении рисования модифицированная область растра BackGnd2 копируется на канву формы. Это позволяет за одно обращение к функции BitBlt() выполнить как стирание на канве формы, так и рисование эльфа в новой позиции. Какие же опреции выполняются с растром BackGnd2?

Во-первых, из BackGnd1 в BackGnd2 копируется прямоугольный участок, превышающий по размерам область, занимаемую самим эльфом. Тем самым гарантируется стирание изображения эльфа с растра BackGnd2. После этого растр FAndImage копируется в BackGnd2 на его новой позиции с помощью поразрядной опреции AND (логическое И). Это приводит к созданию черного пятна с силуэтом эльфа, но с сохранением цветов в области растра BackGnd2, окружающей черный силуэт. Растр FAndImage показан на (рис 2).

Рис 2.

На рис 2 эльф представлен черными пикселами, а изображение вокруг эльфа состоит из белых пикселей. Черный цвет имеет значение, равное 0, а белый - 1. В табл. 1 и 2 приведены результаты выполнения опреции AND с белым и черным цветами.

Табл. 1 "Опреция AND с черным цветом"

Фон
Значение
Цвет
BackGnd2
1001 Некоторый цвет
FAndImage 0000 Черный
Результат
0000
Черный

Табл. 2 "Операция AND с белым цветом"

Фон
Значение
Цвет
BackGnd2
1001 Некоторый цвет
FAndImage 1111 Белый
Результат
1001
Некоторый цвет

Эти таблицы показывают, как выполнение операции логического И приводит к зачернению области, занимаемой эльфом на растре BackGnd2. В табл. 1 столбец "Значение" представляет цвет пискселя. Если пиксель на растре BackGnd2 содержит некоторый произвольный цвет, то объединение этого цвета с черным при использовании оператора AND заставит этот пиксель полностью почернеть. Аналогичная операция, выполненная над тем же цветом и абсолютно белым "коллегой" никак не отразится наисходном цвете, как видно в табл. 2. А поскольку цвет фона, на котором находится эльф в растре FAndImage, был белым, то пиксели на растре BackGnd2 копируются без изменения своих цветов. После копирования растра FAndImage в объект BackGnd2 растр FOrImage должен быть скопирован в то же самое место растра BackGnd2, чтобы заполнить черное пятно, созданное объединением растра FAndImage с реальными цветами эльфа. Растр FOrImage таже имеет прямоугольник, окружающий реальное изображение эльфа. И вновь мы сталкиваемся с задачей получения цветов эльфа для растра BackGnd2 и одновременным сохранением цветов этого растра в области, окружающей эльфа. Это достигается объединением растров FOrImage и BackGnd2 с использованием оператора OR (лигическое ИЛИ). Растр FOrImage показан на (рис 3).

   	    					       Рис 3.

Обратите внимание на то, что область, окружающая изображение эльфа, окрашена в черный цвет. В табл. 3 показаны результаты выполнения операции ИЛИ с растрами FOrImage и BackGnd2. Из табл. 3 следует, что если растр BackGnd2 содержит произвольный цвет, то после операции лигического сложения с черным цветом останется тот же цвет растра BackGnd2.

Табл. 3 "Операция OR с черным цветом"

Фон
Значение
Цвет
BackGnd2
1001 Некоторый цвет
FOrImage 0000 Черный
Результат
1001
Некоторый цвет

Напомним, что все рисование выполняется на "внеэкранном" растре. По завершении рисования достаточно только одного обращения к функции BitBlt(), чтобы стереть и скопировать изображение эльфа. В описанном способе создания анимации нет ничего необычного. Вы можете сами расширить функциональные возможности класса, связанные с перемещением и рисованием на родительской канве.



 
Популярные книги

Технология программирования на C++. Начальный курс

Подробнее

Photoshop CS2. Настоящий самоучитель

Подробнее

SQL для "чайников", 5-е издание

Подробнее

 

 
Новости ИТ
01.12.2008  Buffalo выпустил миниатюрные USB-накопители
01.12.2008  VENTO TA-U1 - стильный корпус представлен Asus
01.12.2008  Fujitsu-Siemens выпускает в продажу внешний ускоритель для ноутбуков
01.12.2008  Оригинальные чехлы для ноутбуков от Choiix
01.12.2008  Опубликован код драйвера для беспроводных карт Atheros
01.12.2008  Лучший блог 2008
01.12.2008  Linux запустили на Apple iPhone
01.12.2008  LG KC780
01.12.2008  MSI дополнит линейку Wind-нетбуков двумя моделями
01.12.2008  Nikon D3X - 24,5 млн пикселей для профессионалов
01.12.2008  Киловаттник HIPER M1000 с КПД выше 85%
01.12.2008  AMD впервые снизила цены линейки Radeon HD 4800
01.12.2008  Чистильщики: Wise Registry Cleaner v.3.8.2
01.12.2008  Антивирусы: RemoveIT Pro v4 SE (30.11.2008)
01.12.2008  Корпус ASUS Vento TA-U1 можно поставить вместо новогодней ёлки
01.12.2008  Диагностика: PC Wizard 2008 v.1.871
01.12.2008  Диагностика: NextSensor v.2.7.6.0 Build 1130
01.12.2008  Тестовые приложения: PassMark BurnInTest v.6.0 Build 1000 Beta 15
01.12.2008  Неофициальные драйверы для модемов Motorola
01.12.2008  Драйверы и утилиты для сетевых хранилищ D-Link
 
Полезно

 
Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.
 
Rambler's Top100