Tvorba her v DelphiX - 5.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:

Soutěž

Sponzorem soutěže je:

IDIF

 

Kde se koná výstava fotografií Luďka Vojtěchovského?

V dnešní soutěži hrajeme o:



Delphi

Tvorba her v DelphiX - 5.díl

delphix5

26. července 2001, 00.00 | Další pokračování seriálu o tvorbě her v DelphiX. Dnes si ukážeme, jak rozpohybovat raketu ve vesmíru a přidáme i střílení. Stáhněte si už hotový projekt, nebo jen hezké sprity rakety do vaší hry !

Po delší době se k vám opět dostává další díl seriálu o programování her v DelphiX. Dnes si ukážeme, jak naprogramovat raketku, která se bude pohybovat na formuláři podle fyzikálních zákonů (nebo spíš počítačových..). Tak se do toho dáme.

Začneme tedy raketkou. Ne každý programátor je zrovna rozený grafik (jinak by grafici neměli co dělat a celou hru by mohl udělat programátor), tak tady máte obrázek jednoho takového vesmírného plavidla. Nekreslil jsem jej já, ale Armand Niculescu (), zde máte již vyrenderovaný obrázek z Maxka:


Do naší hry by nám samozřejmě stačil i nějaký ten low polygon model, ale když je při ruce něco lepšího, proč to nepoužít. Takto vypadá raketa doopravdy:


Spusťte tedy delphi, vytvořte nový projekt, na formulář dejte komponenty DXDraw, DXTimer, DXImageList a do Items DXImageListu přidejte dva obrázky rakety. Pojmenujte je ship a shipburn, nezapomeňte nastavit Transparent na true. Aby raketa létala na všech počítačích přibližně stejnou rychlostí, nastavte si ještě Interval u DXTimeru na 16. Docílíme tím toho, že FPS bude přibližně 60.
Dále si definujeme pár proměnných naší raketky - Angle typu integer, kde bude uložen úhel ve stupních, XPos, YPos typu real, kde bude uložena pozice rakety a XVel,YVel typu real, kde bude rychlost rakety v x a y směru.

Nyní si ještě musíme vysvětlit, jak budeme ovládat pohyb rakety. (To, že k tomu budeme používat klávesnici je snad jasné :) Použijeme komponentu DXInput z palety DelphiX. Při každém vykonání procedury DXTimer.OnTimer obnovíme stav DXInputu, a poté přečteme stisknuté klávesy.
Vytvořte tedy proceduru DXTimer.OnTimer, a do ní přidejte následující řádky, které zajistí otočení rakety po nebo proti směru hodinových ručiček:


 DXInput1.Keyboard.Update;              // update DXInputu
 if isLeft in DXInput1.Keyboard.States  // otočit doleva
  then Dec(Angle,4);
 if isRight in DXInput1.Keyboard.States // otočit doprava
  then Inc(Angle,4);

 if Angle >= 360 then Angle:=0;
 if Angle <= -1 then Angle:=360;


Komentář snad netřeba. Problém je v tom, že při spuštení programu nic nevídíme. Proto je na čase začít raketu kreslit. Nejprve však musíme zjistit úhel otočení od 0 do 255, který si uložen do proměnné XAngle (takže si ji nesmíte zapomenou definovat). Dále si definujeme proměnnou Burn typu boolean, podle které poznáme, zda kreslit raketu normální, nebo s tryskami. Zde je kód pro převod úhlu a kreslení rakety:


 // XANgle ====================
 XAngle:=Trunc(255/360*Angle);

 // DRAW ==================================
 if Burn then DXIMageList1.Items.Find('shipburn').DrawRotate(
 DXDraw1.Surface,Trunc(XPos),Trunc(YPos),70,70,0,0.5,0.5,XAngle)
 else DXIMageList1.Items.Find('ship').DrawRotate(
 DXDraw1.Surface,Trunc(XPos),Trunc(YPos),70,70,0,0.5,0.5,XAngle);


Nyní, když program spustíte, zjistíte, že opravdu můžete s raketkou otáčet. Ale co pohyb ? Na ten se vrhneme nyní. K pohybu použijeme šipku nahoru, proto musíme otestovat, zda-li je zrovna stisknutá. Pokud ano, zvětšíme rychlost XVel a YVel podle otočení rakety. Poté tyto hodnoty přičteme k proměnným XPos a YPos. Pokud bychom to takto nechali, letěla by raketa stále dál, a její rychlost by se stále zvětšovala, až by byla opravdu velká. To nechceme, a proto budeme simulovat odpor tím, že proměnné XVel a YVel budeme zmenšovat. Také musíme ošetřit, pokud se raketa dostane ke kraji plochy - v tom případě ji přesuneme na opačnou stranu. Zde je již celý výsledný kód (doufám dostatečně okomentovaný):


 Burn:=false;
 if isUp in DXInput1.Keyboard.States    // zvýšit rychlost
  then
   begin
     // zvětšit rychlost ======================
     vx:=cos(DegToRad(Angle));
     vx:=vx * 0.08;

     vy:=sin(DegToRad(Angle));
     vy:=vy * 0.08;

     XVel:=vx+XVel;
     YVel:=vy+YVel;

     Burn:=true;

     //  VoX = cos alpha * Vo
     //  VoY = sin alpha * Vo
   end;

 // UPDATE SHIP =======================================
 XPos:=XPos+XVel;     // posuneme loď
 YPos:=YPos+YVel;

 XVel:=XVel/1.01;     // zmensime Velocity
 YVel:=YVel/1.01;
 if Abs(XVel) < 0.001 then XVel:=0;
 if Abs(YVel) < 0.001 then YVel:=0; 

 if XPos < 0 then XPos:=DXDraw1.SurfaceWidth   // není mimo plochu ???
 else if XPos > DXDraw1.SurfaceWidth then XPos:=0;

 if YPos < 0 then YPos:=DXDraw1.SurfaceHeight
 else if YPos > DXDraw1.SurfaceHeight then YPos:=0;
 // END UPDATE SHIP ==================================


Projekt můžete spustit a hle - s raketou můžete hezky létat po celé ploše zatáčet, otáčet... Není to přesně to, co jste chtěli ?
Aby nebylo pozadí tak černé, můžete přidat nějaký ten obrázek, třeba tento:


Stačí obrázek přidat do Items DXImageListu, nastavit Transparent na false, Name na pozadi, a do procedury DXTimer.OnTimer přidat před všechno tento řádek:


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


Zde je konečně i screenshot aplikace:



A to ještě pořád není vše ! Přidáme si totiž ještě střílení. Pro střílení budou dvě možnosti - buď budeme co nejrychleji stlačovat šipku dolů, nebo ji prostě necháme stisknutou, a raketa bude střílet také. V druhém případě však budou mezi jednotlivými střelami znatelně větší prodlevy.
Pro střely si musíme vytvořit konstantu MaxStrel, která bude určovat, kolik je možno vystřelit střel najednou a také typ Strela, z kterého si potom uděláme pole Missile. Dále si vytvoříme proměnné FireCount a MisCount typu integer. Proměnná FireCount se nám postará o to, aby se při stisknuté klávese šipka dolů nestřílelo neustále, ale pouze po x-té. Při každém volání procedury DXTimer.OnTimer se totiž proměnná FireCount zvětší, a střela se vystřelí, pouze pokud bude FireCount deset (náhodně zvolené číslo, můžete samozřejmě použít i jiné). V proměnné MisCount bude uloženo číslo aktuální střely, kterou můžeme použít. Zde je všechno hezky popořadě:


const MaxStrel = 25;

type Strela = record
     XPos,YPos,       // pozice
     XVel,YVel:real;  // rychlost
     visible:boolean; // viditelná ?
     Angle:integer;   // úhel
     end;

...

Missile:array [0..MaxStrel] of Strela;
MisCount,
FireCount:integer;


Dále si v proceduře DXTimer.OnTimer definujeme dvě pomocné proměnné mx a my typu real. To by nám snad stačilo, zde je již celý kód, který se stará o vystřelení, update a nakreslení střely. Úplně bych zapomněl - samozřejmě musíte nejdříve nějaký ten obrázek střely nareslit, vložit do DXImageListu a pojmenovat strela. Druhou možností je použít tento - . Zde je již slibovaný kód:


 // STŘELA ======================================
 if isDown in DXInput1.Keyboard.States // vystřelit střelu !!!!!!
  then
   begin
    // až na x-té vystřelit, ať sou ňáký pauzy...
    FireCount:=FireCount+1;
    if FireCount = 10 then
     begin
      mx:=cos(DegToRad(Angle));
      mx:=mx * 30;    // rychlost střely - 30

      my:=sin(DegToRad(Angle));
      my:=my * 30;

      Missile[MisCount].XVel:=mx/10;    // MISCOUNT
      Missile[MisCount].YVel:=my/10;

      Missile[MisCount].XPos:=XPos+mx;  // pozice střely
      Missile[MisCount].YPos:=YPos+my;

      Missile[MisCount].Angle:=XAngle;
      Missile[MisCount].Visible:=true;

      MisCount:=MisCount+1;        // další střela...nebo první ?
      if MisCount > MaxStrel then MisCount:=0;

      FireCount:=0;
     end;
   end
  else if not (isDown in DXInput1.Keyboard.States) then
   begin
    // když nedrží šipku dulů, tak vynulujem FireCOunt, ať to
    // příště vystřelí...
    FireCount:=9;
   end;

 // update pozice střely
 for i:=0 to MaxStrel do
  begin
   if Missile[i].visible then
    begin
     Missile[i].XPos:=Missile[i].XPos+Missile[i].XVel;
     Missile[i].YPos:=Missile[i].YPos+Missile[i].YVel;

     // a nakreslit střelu
     DXImageList1.Items.Find('strela').DrawRotateAdd(DXDraw1.surface,
     Trunc(Missile[i].XPos),Trunc(Missile[i].YPos),8,8,0,0.5,0.5,
     Missile[i].Angle,255);

     // a není už náhodou mimo plochu ???????
     if (Trunc(Missile[i].XPos) < 0) or
     (Trunc(Missile[i].XPos) > DXDraw1.SurfaceWidth) or
     (Trunc(Missile[i].YPos) < 0) or
     (Trunc(Missile[i].YPos) > DXDraw1.SurfaceHeight) then
      begin
       Missile[i].visible:=false;
      end;
    end;
  end; 


Projekt přeložte, spusťte a pokud je vše v pořádku, měla by vaše raketka po stisknutí šipky dolů začít střílet. Třeba jako zde na obrázku:


A to je pro dnešek již doopravdy vše, pro veškeré další nápady,připomínky a dotazy je místo dole v diskuzi.

Download
ZDE si můžete stáhnout dnes vytvořený program a jeho zdrojáky (670 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: