Živě.cz o počítačích a internetu

Tipy a triky v Delphi, díl 123. - jednoduchá animace

Jan Šindelář - 14.1.2004

Hned na začátku si řekněme na rovinu, že uvedeným způsobem žádnou hru nebo něco podobného nevytvoříte. Na to jsou zcela jiné postupy a techniky. Nám bude stačit velmi jednoduchá animace, kdy na zvoleném pozadí, které bude tvořit obrázek, rozpohybujeme jiný obrázek. Takto vytvořená animace se pak může hodit například do dialogu "O aplikaci..." nebo jiné podobné nenáročné účely.

Co budeme potřebovat? V první řadě si musíme připravit několik obrázků. Prvním z nich bude samotné pozadí animace. Tím může být zcela libovolný obrázek, fotografie, zkrátka cokoliv. Velikost (rozměry) tohoto obrázku pak určují rozměry finálního animovaného obrázku. Dále potřebujeme obrázek, kterým budeme na zvoleném pozadí pohybovat. Bude zpravidla menší (v našem příkladu - viz. dále - jím bude ikona Delphi) a navíc jej potřebujeme ve dvou podobách. V prvním případě se bude jednat o náš obrázek na černém pozadí. Druhá verze, tzv. maska, pak bude černá silueta našeho obrázku na bílém pozadí. Všechno bude myslím jasné z přiloženého příkladu.

Tolik tedy příprava a nyní již k samotnému zdrojovému kódu. Na prázdný formulář si připravíme čtyři komponenty Image. První tři budou obsahovat naše pomocné obrázky, takže ve finální aplikaci jim nastavíme vlastnost Invisible. V našem příkladu jsou však pro názornost vidět. Čtvrtá komponenta Image pak bude naše finální animace. Celou akci spustíme jako obvykle tlačítkem.

Vlastní efekt, tedy pohyb jednoho obrázku přes druhý, pak bude proveden pomocí Timeru. Právě jeho interval v kombinaci s proměnnou, určující o kolik bodů se obrázek v každém kroku posune, pak určuje rychlost pohybu. Překreslování je pak provedeno postupným kopírováním obrázku v kombinaci s jeho maskou s využitím metod komponenty Image. Hodně nám pomůže hlavně vlastnost CopyMode, ve které určíme způsob, jak budou obrázky vzájemně zkombinovány. Pohledem do nápovědy Delphi zjistíte, že variant je poměrně hodně. Nás bude zajímat jednak „obyčejné“ kopírování cmSrcCopy, dále sloučení obrázků operátorem AND pomocí cmSrcAnd a konečně sloučení operátorem OR přes cmSrcPaint.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Imagesprite: TImage;
    Imagemask: TImage;
    Imagebackground: TImage;
    Button1: TButton;
    Timer1: TTimer;
    Image1: TImage;
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  x, y, xvel, yvel, xold, yold: integer;


implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  ARect: TRect;
begin
  x := 0;
  y := 0;
  xvel := 2;
  yvel := 0;
  xold := 0;
  yold := 0;
  ARect := Rect(0, 0, ImageBackground.Width, ImageBackground.Height);
  with Image1.Canvas do
  begin
    CopyMode := cmSrcCopy;
    CopyRect(ARect, ImageBackground.Canvas, ARect);
  end;
  Timer1.Enabled := True;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  Dest, Sour: TRect;
begin
  Sour := Rect(xold, yold, xold + ImageMask.Width, yold + ImageMask.Height);
  with Image1.Canvas do
  begin
    CopyMode := cmSrcCopy;
    CopyRect(Sour, ImageBackground.Canvas, Sour);
  end;
  Sour := Rect(0, 0, ImageMask.Width, ImageMask.Height);
  Dest := Rect(x, y, x + ImageMask.Width, y + ImageMask.Height);
  with Image1.Canvas do
  begin
    CopyMode := cmSrcAnd;
    CopyRect(Dest, ImageMask.Canvas, Sour);
    CopyMode := cmSrcPaint;
    CopyRect(Dest, ImageSprite.Canvas, Sour);
  end;
  xold := x;
  yold := y;
  Inc(x, xvel);
  Inc(y, yvel);
  if x >= ImageBackground.Width then x := -ImageMask.Width;
  if y >= ImageBackground.Height then y := -ImageMask.Height;
end;

end.

Nejprve je v události OnClick zkopírováno pozadí do výsledného obrázku animace, jsou zinicializovány globální proměnné, určující souřadnice pohybovaného obrázku a jeho rychlost (krok) a poté je aktivován Timer. V Timeru pak probíhá opakovaně zmiňované kopírování (překreslování) obrázku na jiné souřadnice, čímž vzniká dojem pohybu. Jak vidíte, obrázek se pohybuje pro jednoduchost pouze po horizontální ose (rychlostí 2 body za jeden krok) a po opuštění plochy skočí zpět na začátek. Samozřejmě si můžete vymyslet jinou „trasu“, kterou můžete popsat třeba nějakou složitější funkcí a měnit obě souřadnice i rychlost.

Budete-li chtít použít v animaci více „spritů“ (tedy pohyblivých obrázků) najednou, vždy je nejprve při překreslování v události OnTimer všechny vymažte a poté všechny opět vykreslete. Nedělejte překreslování a mazání postupně zvlášť pro každý obrázek.

Jelikož je dnešní příklad poněkud složitější na přípravu s ohledem na nutnost vytvořit obrázky, rozhodl jsem se pro tentokrát kromě obvyklého zdrojového kódu uvést i odkaz na stažení kompletního projektu. Můžete si tak velmi rychle vyzkoušet, oč se vlastně jedná. K příkladu jsou přiloženy všechny potřebné obrázky v BMP formátu a projekt je vytvořen v Delphi 7.