× Aktuálně z oboru

Vychází Game Ready ovladače pro Far Cry 5 [ clanek/2018040603-vychazi-game-ready-ovladace-pro-far-cry-5/ ]
Celá zprávička [ clanek/2018040603-vychazi-game-ready-ovladace-pro-far-cry-5/ ]

Delphi v příkladech - 2. díl: Bludiště

[ http://programujte.com/profil/2893-petr-lepcio/ ]Google [ ?rel=author ]       [ http://programujte.com/profil/20356-josef-vitu/ ]Google [ ?rel=author ]       30. 4. 2007       32 389×

Dnes si ukážeme, jak vytvořit jednoduché bludiště.

Výsledné bludiště bude tvořeno dvojrozměrným polem labelů, které budou mít červenou nebo zelenou barvu. Jeden z nich bude mít caption nastaven na X (cíl), ostatní budou mít caption prázdný. V programu bude ještě jeden label, který bude mít zelenou barvu, caption nastaven na O a bude se pohybovat v závislosti na mačkání šipek, ale jen po zelených políčkách. Úkolem uživatele (hráče) bude přemístit tento label nad pole s křížkem. Abychom si ušetřili práci, budou labely v poli vytvářeny za běhu programu a trasa bude generována náhodně.

Políčko

Začneme s políčkem, které bude označovat aktuální pozici. Vložíme do nového projektu objekt Label a nastavíme mu (v Object inspectoru) tyto vlastnosti:

  • Alignment na taCenter (vyrovnání textu na střed labelu v horizontálním směru)
  • Autosize na false (nechceme, aby se automaticky měnila jeho velikost)
  • Caption na O
  • Color na clGreen
  • Font.Color na clWhite
  • Font.Size na 11
  • Font.Style na [fsBold] (písmo bude mít tučný řez)
  • Height na 20
  • Width na 20

Reakci na událost onKeyDown ošetříme později, až budeme mít připravené bludiště. Protože objekt Label nemá tuto událost (nemůže být aktivní, mít focus), použijeme tuto událost u formuláře.

Hrací pole

Jak jsem se již zmínil, bude hrací pole tvořeno dvojrozměrným polem labelů. V části type si připravíme datový typ pole_labelu:


type
  pole_labelu = array [0..14,0..24] of TLabel;

Dávejte si pozor, protože v novém projektu nejsou deklarovány datové typy TLabel, TButton, TImage, atd. Delphi si je samo vytvoří až při přidání takového objektu. Pokud tedy chcete vytvářet objekty dynamicky (za běhu programu), nejjednodušší způsob, jak tyto typy vytvořit, je přidat do projektu objekt tohoto typu, projekt zkompilovat, a následně tento pomocný objekt podle potřeby vymazat. Nás se teď tento problém netýká, protože již máme v projektu objekt Label1.

Dále vytvoříme globální proměnné pole typu pole_labelu a cil typu boolean (zamezí pohybu políčka po dosažení cíle):


public
  pole:pole_labelu;
  cil:boolean;

Objekty v poli vytvoříme v metodě onCreate formuláře. Nesmíme zapomenout nastavit všechny honoty podle našich potřeb.


procedure TForm1.FormCreate(Sender: TObject);
var a,i,j,zaplneno:byte;  //a,i,j jsou pomocné proměnné, v zaplneno bude počet přebarvených  políček 
begin
  randomize;                  //nastavení generátoru náhodných čísel, stačí vždy jednou v programu, a to na začátku
                              //bez tohoto příkazu by byla náhodná čísla při každém zapnutí programu stejná
                              //budeme potřebovat pro generování náhodné trasy
  for i := 0 to 14 do         //protože se jedná o dvojrozměrné pole, vytvoříme jej 2 vnořenými for cykly
    for j := 0 to 24 do
      begin
        pole[i,j] := TLabel.Create(Form1);  //vlastní vytvoření objektu (funkce Typ.Create(Vlastnik) )
        pole[i,j].Parent := self;           //nastavení rodiče - nadřazeného objektu
        pole[i,j].Width := 20;
        pole[i,j].Height := 20;             //nastavení rozměrů
        pole[i,j].Top := 20 + 20*i;
        pole[i,j].Left := 20 + 20*j;        //nastavení pozice tak, aby labely vytvořily souvislou plochu
        pole[i,j].Visible := true;          //nastavení viditelnosti
        pole[i,j].Color := clRed;           //nastavení barvy na červenou, později ji u některých změníme
                                            //na zelenou, aby vytvořily trasu
        pole[i,j].AutoSize := false;        //chceme, aby všechny měly pevné rozměry a neměnily je
      end;
  Label1.BringToFront;  (*nově vytvořené objekty překryjí starší objekt Label1, který ale chceme mít navrchu - aby on
                         překrýval ostatní objekty, proto jej musíme přenést dopředu*)
end;

Způsob, který použiji pro vytváření trasy, je možná příliš komplikovaný, ale vznikají při něm zajímavé trasy. Trochu si jej popíšeme: Vybere se náhodně jedno políčko, ve kterém se bude začínat, a přemístí se Label1 nad tuto pozici. Poté se vybere náhodně jeden ze 4 směrů a délka (3-7) a všechny tyto labely se obarví zeleně (pokud nenarazíme na okraj, tady si musíme dávat pozor na rozsah pole, aby program nemohl skončit chybou), a to se bude znovu opakovat v políčku, ve kterém skončíme. Až počet zelených labelů přesáhne určitou hodnotu (175), změní se caption posledního změněného políčka na X (a kvůli vzhledu bude mít stejné písmo jako Label1).

Nejdříve vytvoříme proceduru, která, pokud bude políčko zadaných parametrů červené, jej přebarví a přičte k počtu zelených políček (třetí parametr). Aby se tato změna projevila i v proceduře, kde bude volána, musí být třetí parametr tzv. parametr nahrazovaný odkazem. Takový parametr má před sebou ještě var a parametrem při volání musí být proměnná. V ní se také projeví změny vykonané s parametrem ve volané proceduře.


//deklarace
  TForm1 = class(TForm)
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure zmena_barvy (i,j:byte;var policek:byte);
...
procedure TForm1.zmena_barvy(i,j:byte;var policek:byte);
begin
  if pole[i,j].Color <> clGreen then
    begin
      pole[i,j].Color := clGreen;
      policek := policek + 1;
    end;
end;

Generování trasy

Generování trasy připíšeme na konec procedury FormCreate:


  ...
  Label1.BringToFront;
  i := random(15);
  j := random(25);              //vybrání náhodných počátečních souřadnic
  pole[i,j].Color := clgreen;
  Label1.Left := 20 + 20*j;
  Label1.Top := 20 + 20*i;      //přesuneme Label1 na pozici vybraného labelu
  zaplneno := 1;
  repeat
    case random(4) of           //vybere náhodný směr
      0:                        //nahoru
         for a := 1 to random(5)+3 do    //vybere náhodnou délku 3-7
           begin
             if (i - 1 >= 0) then        //kontrola rozsahu pole
               begin
                 i := i - 1;             //posunutí souřadnic aktuálního políčka
                 zmena_barvy(i,j,zaplneno);  (*přebarvení, v proměnné zaplneno
se projeví změny vykonané se třetím parametrem během procedury*)
               end;
           end;
         //podobně budeme pokračovat pro ostatní 3 směry (s úpravou posunu souřadnic)
      1:                        //dolů
         for a := 1 to random(5)+3 do
           begin
             if (i + 1 <= 14) then
               begin
                 i := i + 1;
                 zmena_barvy(i,j,zaplneno);
               end;
           end;
      2:                        //doleva
         for a := 1 to random(5)+3 do
           begin
             if (j - 1 >= 0) then
               begin
                 j := j - 1;
                 zmena_barvy(i,j,zaplneno);
               end;
           end;
      3:                        //doprava
         for a := 1 to random(5)+3 do
           begin
             if (j + 1 <= 24) then
               begin
                 j := j + 1;
                 zmena_barvy(i,j,zaplneno);
               end;
           end;
    end;
  until zaplneno >= 175;    //generování se skončí, pokud je zelených políček 175 nebo více
  if (pole[i,j].Left <> Label1.Left) or (pole[i,j].Top <> Label1.Top)
    //kontrola, aby cíl nebyl na stejné pozici jako start
    then pole[i,j].Caption := 'X' //cíl
    else
      begin
        repeat //výběr náhradního cíle
           i := random(15);
           j := random(25);
        until (pole[i,j].Color = clGreen) and ((pole[i,j].left <> Label1.left) or (pole[i,j].top <> Label1.Top));
        pole[i,j].Caption := 'X' //náhradní cíl
      end;
  pole[i,j].Font := Label1.Font;   //zkopírujeme font Labelu1
  pole[i,j].Alignment := taCenter; //zarovná Caption na střed
  cil := false; //pro nás výchozí situace - nejme v cíli

Ošetření události zmáčknutí šipky

Nejdříve nastavíme vlastnost KeyPreview formuláře na true. To způsobí, že každá zmáčknutá klávesa vyvolá událost OnKeyDown formuláře bez ohledu na to, který objekt je aktivní. Sice bychom to v tomto programu nepotřebovali, protože zde není žádný další objekt, který může být aktivní (mít focus), ale kdybychom jej později chtěli přidat, mohla by vzniknout chyba.

Nyní vytvoříme obslužnou proceduru pro událost OnKeyDown u formuláře (dvojklikem v ObjectInspectoru):


procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var i,j:byte;
begin
  if not cil then  //pokud nejsme v cíli
    begin
      i := (label1.Top - 20) div 20;   //zjištění aktuálních souřadnic, zjednodušší
      j := (label1.Left - 20) div 20;  //a zpřehlední zápis
      case key of  //rozlišení zmáčknuté klávesy
        vk_down:   //konstanta pro šipku dolů (platí v OnKeyDown a dalších procedurách, kde je parametr Key typu word)
          begin
            if i in [0..13] then  //i se nemůže nacházet v posledním řádku, protože by se už nemělo kam posunout
              if pole[i+1,j].Color = clgreen then //je-li políčko o řádek níž zelené
                label1.Top := label1.Top + 20;    //vlastní posun
          end;
             //s drobnými modifikacemi použijeme i pro ostatní šipky
        vk_up:     //konstanta pro šipku nahoru
          begin
            if i in [1..14] then
              if pole[i-1,j].Color = clgreen then
                label1.Top := label1.Top - 20;
          end;
        vk_left:   //konstatnta pro šipku doleva
          begin
            if j in [1..24] then
              if pole[i,j-1].Color = clgreen then
                label1.left := label1.left - 20;
          end;
        vk_right:  //konstanta pro šipku doprava
          begin
            if j in [0..23] then
              if pole[i,j+1].Color = clgreen then
                label1.left := label1.left + 20;
          end;
      end;
      i := (label1.Top - 20) div 20;
      j := (label1.Left - 20) div 20;  //nové souřadnice
      if pole[i,j].Caption = 'X' then  //jsme-li nad cílovým políčkem
        begin
          cil := true;          //konec hry, s políčkem nepůjde dále pohybovat
          Showmessage('Dorazili jste do cíle!'); //zobrazí jednoduchou zprávu
        end;
    end;
end;

Závěrečné úpravy

Program už nám funguje, ale ještě nám chybí doladit drobnosti:

  • Nastavit správnou velikost formuláře (ClientWidth na 540 a ClientHeight na 340)
  • Změnit Caption formuláře
  • Nastavit ikony (malá ikona na horní liště formuláře je vlastnost Icon formuláře, velká ikona viditelná ve Windows se změní v nastavení projektu – Project → Options… → Application → Load Icon

    (Je dobré vytvořit si vlastní ikony, k tomu můžete použít ImageEditor, který je u Delphi).

Nyní je už celý program hotový, přesto má ale vážné nedostatky (např. po dosažení cíle nelze spustit novou hru a musíme program ukončit), kterými se budeme zabývat někdy příště.


Článek stažen z webu Programujte.com [ http://programujte.com/clanek/2007033103-delphi-v-prikladech-2-dil-bludiste/ ].