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í...
ÚvodAno, 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:
- 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.
- 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).
- 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...
- 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).
- 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.
- Do BackGnd1 nahrajeme obrázek vesmíru, který je ve formátu bmp, v mém případě rozměrů 640x480 pixelů.
- 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.
- Nyní poklepeme na prázdné místo formuláře, čímž vytvoříme proceduru FormCreate, do které přidáme následující kód:
// 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;- Dále přidáme proměnné GoLeft, GoUp, GoRight a GoDown typu boolean, a SpriteLeft a SpriteTop typu Integer.
- Na formulář přidáme komponentu Timer, kterou přejmenujeme na GoTimer, Interval nastavíme na ??? a Enabled na false.
- Do procedury FormCreate ještě přidámě následující kód, který zajistí pohyb spritu doprava dolů a pozici spritu 0,0:
// 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;- 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:
- nejprve definujeme pár proměnných:
var VyskaVesmiru,
SirkaVesmiru,
VyskaSpritu,
SirkaSpritu:integer;- a poté je již vlastní výpočet:
// 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;- A nyní kopírování spritu:
// 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;- 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...
Diskuse k článku
-
25. listopadu 2012
-
30. srpna 2002
-
10. října 2002
-
4. listopadu 2002
-
12. září 2002
-
25. listopadu 2012
-
28. července 1998
-
31. července 1998
-
28. srpna 1998
-
6. prosince 2000
-
27. prosince 2007
-
4. května 2007