Animace spritu v Delphi - Builder.cz - Informacni server o programovani

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:



Delphi

Animace spritu v Delphi

18. července 2000, 00.00 | Jednoduchý návod, jak v Delphi udělat animaci založenou na spritech bez blikání...

Úvod

Ano, animace. Každý asi ví, co to je. Prostě se něco hýbe... A právě o tom je tento dokument - o tom, jak v Dephi rozhýbat sprite (nejedná se o nápoj, ale o pohyblivý obrázek). V naší ukázce půjde o to jak rozhýbat obrázek ufo na obrázku vesmíru. Samozřejmě jde, umístit dvě komponenty image nad sebe, a potom jedné (té s obrázkem ufo) měnit hodnoty left a top. Pokud jste ale tuto metodu již někdy zkoušeli, zjistili jste, že obrázky velice nepříjemně blikají... . Tudy cesta nevede...
Budeme tedy používat windows funkci BitBlt, pro kopírování, o tom ale až později...


>> zde si můžete stáhnout demo aplikaci se zdrojovým <<
>> kódem. Zip soubor - 452 KB <<

a takto to bude vypadat...

Nejprve příprava...

To nejdůležitější na začátek. Potřebujete hlavně nějaký počítač (ten ale tuším již máte), potom program Borland Delphi, nějaké ty obrázky (ti zručnější si je třeba můžou nakreslit :-), a hlavně trpělivost.
Začneme obrázky. Já jsem zvolil animaci ufa ve vesmíru. Ufo jsem si naskenoval z knihy Záhady neznáma, a poté trochu upravil. Pokud zrovna nic takového nemáte po ruce, můžete si třeba nějaké stáhnout z internetu, kde jich je požehnaně... Vesmíru na internetu moc není, zato je na jeho tvorbu specializovaný program Universe. Jeho shareware verzi si můžete stáhnout z internetu, kde je na adrese http://www.diardsoftware.com  . Od plné verze má omezení pouze to, že nemůžete do vesmíru vkládat prvky jako ze země, slunce a mars, jinak vše funguje. Tak si nějaký ten vesmír nakreslete...
A nyní příprava spritu. Obrázky totiž potřebujeme dva. Jeden normální, který uvidíme a druhý černobílý, který použijeme jako masku. To, co má být vidět nakreslíme černě, a to, co má být průhledné bíle... zde je náhled na normální obrázek a masku:

 

Trocha teorie

Aby obrázky při lítání ufa neblikaly, musíme vykreslovat sprite (ufo) vždy na nezobrazovanou bitmapu. K tomu potřebujeme na formuláři bitmapy s pozadím tři:

  1. zaprvé je tu bitmapa Backgnd1, na kterou se vůbec nekreslí a je v ní tedy neporušený obrázek pozadí, tedy vesmíru. Z této bitmapy se pouze čte.
  2. zadruhé je zde bitmapa, na kterou se vykresluje sprite, ale není zobrazená, protože BLIKÁ. Na tu se tedy sprite vykreslí, ale my to nevidíme (backGnd).
  3. a zatřetí je zde konečně bitmapa, kterou vidíme a která nebliká, jelikož pouze vždy překopíruje obsah bitmapy č.2. A to je to co potřebujeme.

Ale jak to všechno udělat ???
Zde jsou operace, které se provádějí s BackGnd2. Nejdříve se přes část, na které je sprite zkopíruje prázdná plocha z BackGnd1. Tím vlastně získáme původní obrázek vesmíru. Poté se vypočítá nová poloha spritu. Ta se počítá tak, že máme čtyři proměné: GoLeft, GoRight, GoUp, GoDown. Na začátku letí sprite doprava dolů, tedy GoRight a GoDown jsou nastaveny na true. Pokud narazí na to, že by byl pryč s pozadí vpravo, změní se GoRight na false a GoLeft na true, pokud by narazil dole, změní se GoDown na false a GoUp na true...
Když máme vypočítanou polohu, musíme zkopírovat sprite. Zde je na čase popsat si funkci BitBlt:

BitBlt(
HDC hdcDest,     // handle objektu, na který budeme kopírovat 
int nXDest,         // pozice x obdélníku, do kterého budeme kopírovat
int nYDest,         // pozice y obdélníku, do kterého budeme kopírovat
int nWidth,         // šířka obdélníku, do kterého se bude kopírovat 
int nHeight,        // výška obdélníku, do kterého se bude kopírovat 
HDC hdcSrc,      // handle objektu, z kterého se bude kopírovat 
int nXSrc,          // pozice x obdélníku, který se bude kopírovat 
int nYSrc,           // pozice y obdélníku, který se bude kopírovat
DWORD dwRop    // rastrová operace

 Jako rastrovou operaci budeme používat  SRCCOPY a SRCAND. Pokud chcete vědět něco více o ostatních operacích, podívajte se do Delphi nápovědy.
A jdeme ke kopírování spritu. Nejdříve operace :

SRCCOPY  - slouží k normálnímu prostému kopírování, vezmeme kus obrázku a zkopírujeme ho do obrázku druhého. Nic víc, nic míň, asi nejpoužívanější operace.

SRCAND - slouží také pro kopírování, ale s operací AND. Používáme při kopírování masky. Zde jsou výsledjky operací: Nějaká barva (na obrázku vesmíru) AND černá (na obrázku masky) = černá. A ještě jeden příklad: Nějaká Barva (na obrázku vesmíru) AND bílá (na obrázku masky) = Nějaká barva. Proto tedy když zkopírujeme obrázek masky na obrázek vesmíru, vytvoří se zde černá díra.

SRCPAINT - také kopírování, a to poslední. Při kopírování se používá operce OR. Zde jsou výsledky operace OR s černou barvou, která obklopuje obrázek spritu, jak vidíme, na jejím místě se objeví původní barva: Nějaká barva (obrázek vesmíru) OR Černá (obklopující obrázek spritu) = Nějaká barva. 

A to je celé tajemství kopírování. Tak do toho...

A už to jen naprogramovat...

Ano, a je zde nejdůležitější krok - a to naprogramování. Potřebujete Borland Delphi alespoň verzi 3, a trochu té programátorské znalosti. Budu se snažit napsat to co nejsrozumitelněji...

  1. Tedy spustíme Delphi, a pomocí File/New Application vytvoříme nový projekt. Ten hned uložíme např pod názvem ufo a unit1 jako MainUnit (můžete samozřejmě ukládat pod libovolnými názvy, to je jen ze zvyku). 
  2. Form1 přejmenujeme na MainForm a caption dáme třeba na Ufo. Poté z palety Additional vložíme tři objekty Image. Následně změníme jejich názvy na BackGnd1, BackGnd2 a BackGnd3. U BackGnd1 a BakcGnd2 změníme Visible na false aby nebyly vidět. 
  3. Do BackGnd1 nahrajeme obrázek vesmíru, který je ve formátu bmp, v mém případě rozměrů 640x480 pixelů.
  4. Dále dáme na formulář ještě další dva prvky Image, které pojmenujeme SpriteImage a SpriteAndImage. Do SpriteImage nahrajeme obrázek Ufo a do druhého obrázek masky ufa. Autosize obou nastavíme na true a Visible na false.
  5. Nyní poklepeme na prázdné místo formuláře, čímž vytvoříme proceduru FormCreate, do které přidáme následující kód:
  6. // přiřazení obrázků do ostatních komponent
    BackGnd2.Picture.Assign(BackGnd1.Picture);
    BackGnd3.Picture.Assign(BackGnd1.picture);
    // BackGnd3 přes celý formulář
    // a vycentrování formu

    BackGnd3.AutoSize:=true;
    MainForm.AutoSize:=true;
    Mainform.Position:=poDesktopCenter;
  7. Dále přidáme proměnné GoLeft, GoUp, GoRight a GoDown typu boolean, a SpriteLeft a SpriteTop typu Integer.
  8. Na formulář přidáme komponentu Timer, kterou přejmenujeme na GoTimer, Interval nastavíme na ??? a Enabled na false.
  9. Do procedury FormCreate ještě přidámě následující kód, který zajistí pohyb spritu doprava dolů a pozici spritu 0,0:
  10. // pohyb spritu doprava dolů
    // z pozice 0,0 a spuštění timeru

    GoLeft:=false;
    GoUp:=false;
    GoRight:=true;
    GoDown:=true;
    SpriteLeft:=0;
    SpriteTop:=0;
    GoTimer.Enabled:=true;
  11. A nyní se pustíme do programování procedury GoTimerTimer. Nejdříve si musíme podle souřadnic a velikosti vesmíru vypočítat další pohyb spritu:
  12. nejprve definujeme pár proměnných:
  13. var VyskaVesmiru,
        SirkaVesmiru,
        VyskaSpritu,
        SirkaSpritu:integer;
  14. a poté je již vlastní výpočet:
  15. // nastavení promenných
    VyskaVesmiru:=BackGnd3.Height;
    SirkaVesmiru:=BackGnd3.Width;
    VyskaSpritu:=SpriteImage.Height;
    SirkaSpritu:=SpriteImage.Width;

    //Výpočet nové polohy spritu-----------

    if GoLeft then
     begin
      if SpriteLeft > 0 then
       SpriteLeft:=SpriteLeft-1
      else
       begin
        GoLeft:=false;
        GoRight:=true;
       end;
     end;

    if GoDown then
     begin
      if (VyskaSpritu+SpriteTop)<VyskaVesmiru then
       SpriteTop:=SpriteTop+1
      else
       begin
        GoDown:=false;
        GoUp:=true;
       end;
     end;

    if GoUp then
     begin
      if SpriteTop>0 then
       SpriteTop:=SpriteTop-1
      else
       begin
        GoUp:=false;
        GoDown:=true;
       end;
     end;

    if GoRight then
     begin
      if (SpriteLeft+SirkaSpritu)<SirkaVesmiru then
       SpriteLeft:=SpriteLeft+1
      else
       begin
        GoRight:=false;
        GoLeft:=true;
       end;
     end;
  16. A nyní kopírování spritu:
  17. // vymažeme původní kresbu spritu v BackGnd2
    // zkopírováním obdélníku z BackGnd1

    BitBlt(BackGnd2.canvas.handle,0,0,SirkaVesmiru,
    VyskaVesmiru,BackGnd1.canvas.handle,0,0,SrcCOPY);

    // nyní vykreslíme sprite na nezobrazovanou bitmapu
    // čímž zamezíme blikání... :-)


    // první vytvoříme černou díru na místě spritu tím
    // že do bitmapy zkopírujeme masku spritu pomocí
    // operace SrcAND

    BitBlt(BackGnd2.canvas.handle,SpriteLeft,SpriteTop,
    SirkaSpritu,VyskaSpritu,SpriteAndImage.canvas.handle,
    0, 0,SrcAnd);
    Backgnd2.Refresh;

    // a potom už zkopíprujeme sprite pomocí
    // SrcPaint

    BitBlt(BackGnd2.canvas.handle,SpriteLeft, SpriteTop,
    SirkaSpritu, VyskaSpritu, SpriteImage.canvas.handle,
    0,0,SrcPaint);

    // a nakonec to celé zkopírujeme
    // do výsledné BackGnd3

    BitBlt(BackGnd3.canvas.handle,0,0,SirkaVesmiru, VyskaVesmiru,
    BackGnd2.Canvas.Handle,0,0,SrcCopy);
    BackGnd3.Refresh;
  18. Nyní už jenom výsledný program přeložte a spusťte klávesou F9 a čekejte, co se stane. Ve vesmíru by Vám mělo létat ufo !!! Pokud tak je, blahopřeji, pokud ne, zkuste to znova projít, kde jste udělali chybu...

 

A konec...

Ano, a to je konec. Konec dokumentu, ve kterém jsem se snažil objasnit trochu problematiku animace spritu v delphi. Snažil jsem se to psát, jak jen nejlépe jsem uměl, ale nakonec je to asi pochopitelné pouze pro mě... No nic. Kdybyste měli jakýkoliv problém, směrujte ho buď na nápovědu Delphi, která je naštěstí dosti obsáhlá, nebo rovnou na mě, a to na e-mail   Budu se snažit odpovědět co nejrychleji... E-mailnout mi můžete i v případě, že problém nemáte, ale tento článek se Vám líbil, nebo se o problematiku zajímáte, a máte nějaké zkušenosti... Předem děkuji...

Tématické zařazení:

 » Rubriky  » Delphi  

 » Rubriky  » Windows  

 

 

 

Nejčtenější články
Nejlépe hodnocené články

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: