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ě.