Tvorba her v DelphiX - 4. díl - 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

Tvorba her v DelphiX - 4. díl

delphi_delphix

31. května 2001, 00.00 | Nebaví vás kreslit v DelphiX pouze body a chtěli byste i jiné efekty ? Zkuste kreslit obrázky s částečnou průhledností, rotací, jako světlo nebo stín. Kompletní popis v tomto článku.



Jak jistě všichni víte, úspěšnost her nezávisí pouze na jejich hratelnosti, příběhu, propracovanosti atd., ale také především na grafice. Ve všech předchozích článcích jsme pouze kreslili body, čáry a čtverce na surface, když obrázky, tak pouze procedurou Draw. DirectX nám však nabízí další možnosti kreslení obrázků, jako například částečnou průhlednost, rotaci, světlo, stín atd. a na to se právě dnes podíváme.



Normální kreslení - Draw

I když jsem to napsal již tisíckrát, napíšu to raději ještě jednou. Pro kreslení obrázku, který máme uložen v DXImageListu, použijeme proceduru Draw. Parametry jsou tyto:

Draw(Dest: TDirectDrawSurface; X, Y, PatternIndex: Integer);
  • Dest - povrch, na který budeme kreslit
  • X,Y, - pozice, na kterou budeme kreslit
  • PatternIndex - kterou část obrázku chceme kreslit, blíže je toto popsáno v článku "Kreslení části obrázku v DelphiX"

Začneme tedy tím, že si vytvoříme nový projekt. Na plochu dáme komponenty DXDraw, DXTimer a DXImageList. Interval u DXTimeru nastavíme na 0, do Items ImageListu přidáme libovolný obrázek na pozadí (pojmenujeme jej pozadi) a ještě jeden, na kterém budeme demonstrovat kreslení (pojmenujeme delphix). Jelikož budeme kreslit všechny dále zmiňované efekty na jeden surface, musíme si říci, co vlastně chceme kreslit. Proto vytvoříme proměnnou CoKreslit, která bude nabývat pěti hodnot:


CoKreslit:(normal,rotate,pruhled,svetlo,stin);


Dále vytvoříme proceduru Form1.OnCreate, do které přidáme řádky pro nastavení proměnné CoKreslit na normal. Následně vytvoříme proceduru DXTimer1.OnTimer, ve které nejprve nakreslíme obrázek pozadí, FPS, to co chceme kreslit a vše ukončí Flip. Zde je výsledný kód:


procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer);
begin
 if not DXDraw1.CanDraw then Exit;

 DXImageList1.Items.Find('pozadi').Draw(DXDraw1.Surface,0,0,0); 

 with DXDraw1.Surface.Canvas do
  begin
   // FPS
   Brush.Color:=clWhite;
   Font.Name:='Tahoma';
   Font.Size:=8;
   Font.Color:=clBlack;
   TextOut(5,2,'FPS: '+IntTOStr(DXTimer1.FrameRate));

   release;
  end;

 // a co si to vlastně nakreslíme ???
 case CoKreslit of
  normal:XDrawNormal;
  rotate:XDrawRotate;
  pruhled:XDrawAlpha;
  svetlo:XDrawLens;
  stin:XDrawShadow;
 end;

 // flip :))
 DXDraw1.Flip;

end;


Ovšem žádné procedury XDrawNormal, XDrawRotate... neexistují. Ty si musíme sami jednu po druhé vytvořit. Teď se vrhneme na proceduru XDrawNormal, ostatní můžete zatím nechat prázdné (ovšem musíme je vytvořit!). V proceduře XDrawNormal tedy nejprve zjistíme střed, a už jen nakreslíme obrázek. Další vysvětlování není doufám nutné, program můžete rovnou spustit. Zde je kód procedury a screenshot aplikace:


procedure TForm1.XDrawNormal;
var centerx,centery:integer;
begin
 // kreslení obrázku normálně a vycentrovaně
 centerx:=DXDraw1.SurfaceWidth div 2-
 DXImageList1.Items.Find('delphix').Width div 2;
 centery:=DXDraw1.SurfaceHeight div 2-
 DXImageList1.Items.Find('delphix').Height div 2;

 DXImageList1.Items.Find('delphix').Draw
 (DXDraw1.Surface,centerx,centery,0);
end;






Kreslení s otočením - DrawRotate

Další věc, na kterou se podíváme, bude rotace. Ke kreslení libovoného obrázku otočeného pod stanoveným úhlem použijeme funkci DrawRotate. Zde jsou její parametry:

DrawRotate(Dest:TDirectDrawSurface; X,Y,Width,Height, PatternIndex:Integer; CenterX,CenterY:Double;Angle:Integer);

  • Dest - povrch
  • X,Y - souřadnice počátku kreslení
  • Width, Height - výška a šířka obrázku
  • PatternIndex - část obrázku
  • CenterX, CenterY - střed rotace
  • Angle - úhel

Prvních šest parametrů je jasných, co ostatní? CenterX a CenterY udávají, kde se bude obrázek otáčet, tedy přesně bod otáčení uvnitř obrázku. Můžou nabývat hodnot od 0 do 1, hodnota je v procentech. Pokud třeba nastavíme oba parametry na 0.5, bude obrázek přesně uprostřed. Poslední parametr Angle, který určuje úhel, může pro změnu nabývat hodnot 0 až 255.
Přidáme si ještě proměnnou Uhel typu integer, ve které bude úhel uložen a již známe vše potřebné k tomu, abychom mohli vytvořit proceduru XDrawRotate. Dobré je si ještě přidat na formulář několik RadioButonů, kterými můžete přepínat kreslení. Zde je opět kód procedury a screenshot aplikace:


procedure TForm1.XDrawRotate;
var centerx,centery,sirka,vyska:integer;
begin
 // kreslení obrázku s pootočením
 sirka:=DXImageList1.Items.Find('delphix').Width;
 vyska:=DXImageList1.Items.Find('delphix').Height;

 centerx:=(DXDraw1.SurfaceWidth div 2);
 centery:=(DXDraw1.SurfaceHeight div 2);

 DXImageList1.Items.Find('delphix').DrawRotate
 (DXDraw1.Surface,centerx,centery,sirka,vyska,0,0.5,0.5,Uhel);

 // zvětšení úhlu
 Inc(Uhel);
 if Uhel = 257 then Uhel:=0;

 // jaký je vlastně ten úhel ???
 with DXDraw1.Surface.Canvas do
  begin
   TextOut(5,15,'Uhel: '+IntTOStr(Uhel));
   release;
  end;
end;






Částečná průhlednost - DrawAlpha

Dalším hodně používaným efektem je kreslení částečně průhledného obrázku. Toho dosáhneme funkcí DrawAlpha, její parametry jsou zde:

DrawAlpha(Dest: TDirectDrawSurface; const DestRect: TRect; PatternIndex: Integer; Alpha: Integer);

  • Dest - povrch
  • DestRect - oblast, do které budeme kreslit
  • PatternIndex - část obrázku
  • Alpha - průhlednost

Tentokrát nekreslíme na pozici x,y s danou výškou a šířkou, ale oblast je určena proměnnou DestRect. Alpha může nabývat hodnot od 0 do 255. Čím menší číslo, tím je obrázek průhlednější. Při nule je průhledný úplně, při 255 vůbec. Průhlednost si uložíme do proměnné XAlpha typu integer, a v proceduře OnCreate nastavíme na nulu. Výpis procedury XDrawAlpha a screenshot aplikace je zde:


procedure TForm1.XDrawAlpha;
var centerx,centery,sirka,vyska:integer;
begin
 // kreslení obrázku s Alpha průhledností
 sirka:=DXImageList1.Items.Find('delphix').Width;
 vyska:=DXImageList1.Items.Find('delphix').Height;

 centerx:=(DXDraw1.SurfaceWidth div 2) - (sirka div 2);
 centery:=(DXDraw1.SurfaceHeight div 2) - (vyska div 2);

 DXImageList1.Items.Find('delphix').DrawAlpha
 (DXDraw1.Surface,Rect(centerx,centery,centerx+sirka,centery+vyska),
 0,XAlpha);

 // zvětšení úhlu
 Inc(XAlpha,3);
 if XAlpha > 257 then XAlpha:=0;

 with DXDraw1.Surface.Canvas do
  begin
   TextOut(5,15,'Alpha: '+IntTOStr(XAlpha));
   release;
  end;
end;





Kreslení světla - DrawAdd

Jedním z nejnáročnějších efektů na čas je bezesporu kreslení světla. K tomu nám slouží DrawAdd a zde jsou již její parametry:

DrawAdd(Dest: TDirectDrawSurface; const DestRect: TRect; PatternIndex: Integer; Alpha: Integer=255);

  • Dest - povrch
  • DestRect - oblast, do které budeme kreslit
  • PatternIndex - část obrázku
  • Alpha - svítivost :)

Nejdůležitějším parametrem je Alpha, která určuje, jak hodně bude kreslený obrázek "svítit". Maximální hodnota je 255. Pro vytvoření hezkého světla však potřebujeme i hezký obrázek. Jeden takový je právě zde. Čím světlejší barva, tím bude pixel víc svítit, černá barva tedy svítit vůbec nebude a bude tak průhledná. Tento obrázek si přidejte do DXImageListu a pojmenujte jej lens:


A následuje jako obvykle zdrojový kód procedury XDrawLens a screenshot aplikace při kreslení onoho hezkého světla:


procedure TForm1.XDrawLens;
var pos:TPoint;
begin
 // kreslíme světlo na pozici kurzoru
 GetCursorPos(Pos);
 Pos:=DXDraw1.ScreenToClient(pos);

 // vycentrujeme čočku
 Dec(Pos.x,150 div 2);
 Dec(Pos.y,150 div 2);

 DXImageList1.Items.Find('lens').DrawAdd(DXDraw1.Surface,
 Rect(Pos.x,Pos.y,Pos.x+150,Pos.y+150),0,255);

end;





Kreslení stínu - DrawSub

Nakonec si nakreslíme pravý opak světla - stín. Kreslení je velice podobné, pouze použijeme DrawSub s těmito parametry:

DrawSub(Dest: TDirectDrawSurface; const DestRect: TRect; PatternIndex: Integer; Alpha: Integer=255);

  • Dest - povrch
  • DestRect - oblast, do které budeme kreslit
  • PatternIndex - část obrázku
  • Alpha - tmavost

Pro nás nejduležitější je parametr Alpha, který určuje, jak hodně bude pozadí ztmaveno, opět s možností od 0 do 255. Důležitý je také obrázek, který použijeme - nejlépe pouze v odstínech šedi. V takovémto obrázku bude pozadí v místech nejsvětlejších barev ztmaveno nejvíce, v tmavším méně. Pokud nemáte zrovna žádný takový obrázek při ruce, můžete použít tento. Přidejte jej do DXImageListu a pojmenujte shadow:


Sami si jej zhotovíte také velice jednoduše. Stačí nejprve převést obrázek na stupně šedi (např. v IrfanView - Image/Convert to greyscale), rozostřit (Image/Effect/Blur) a Invertovat barvy (Image/Negative). Opravdu to není nijak těžké. Nakonec ještě přikládám zdrojový kód procedury XDrawShadow a screenshot při kreslení stínu:


procedure TForm1.XDrawShadow;
var pos:TPoint;
begin
 // kreslíme stín na pozici kurzoru
 GetCursorPos(Pos);
 Pos:=DXDraw1.ScreenToClient(pos);

 // vycentrujeme stín
 Dec(Pos.x,96 div 2);
 Dec(Pos.y,101 div 2);

 DXImageList1.Items.Find('shadow').DrawSub(DXDraw1.Surface,
 Rect(Pos.x,Pos.y,Pos.x+96,Pos.y+101),0,255);
end;





Co se sem nevešlo...

Pokud pořádně projdete nápovědu k DelphiX, zjistíte, že existují ještě další procedury pro kreslení. Většinou se jedná o modifikace, nebo sloučení více věcí dohromady (kreslení alpha průhlednosti + rotace). Existuje také ještě kreslení zvlněného obrázku procedurou DrawWaveX, bohužel bez vyhlazení, takže vypadá dost bídně, a proto ani neukazuji příklad. Ostatně, vše je popsáno v nápovědě, na kterou vás právě teď směruji a končím tím i tento článek.

Download
ZDE si můžete stáhnout dnes vytvořený program a jeho zdrojáky (706 kB)

Obsah seriálu (více o seriálu):

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: