Kurs
Delphi - cześć 2
Pierwszy projekt, pierwsza gra
Na poprzedniej lekcji dowiedziałeś się jak sprawnie posługiwać
się środowiskiem Delphi, nawet napisałeś mini aplikację, ale dziś
zajmiemy się dużo ciekawszymi rzeczami - mianowicie napiszemy grę ! Pewnie
teraz przeklinasz, że chciałeś nauczyć się pisać programy a nie gry. Nie
obawiaj się, będzie to gra okienkowa, na niej łatwo będzie pokazać zasadzę
działania instrukcji warunkowej IF. A więc do działa:
Gra będzie działać następująco:
1. Wciskamy przycisk start
2. Aplikacja generuje liczbę losową z podanego zakresu
3. Aplikacja zadaje nam pytanie o liczbę
4. Wyświetlenie odpowiedniego komunikatu
5.1 Jeśli to jest za dużo lub za mało to skok do punktu 3
5.2 Jeśli zgadliśmy to gratulacje.
Najpierw stwórzmy projekt:
Na formularzu umieść przycisk START, dwa pola tekstowe (textbox) oraz jedną
etykietę (label). Powinno to wyglądać mniej więcej tak:

Mam nadzieję, ze jeszcze pamiętasz jak zmienia się
etykietki oraz nazwy elementów. Przystąpmy do tej czynności - przycisk
nazwij cmdstart i nadaj mu etykietę START, pierwsze pole tekstowe nazwij
txtmin drugie txtmax. Może Cię teraz zdziwić fakt, że pole tekstowe nie
zawiera właściwości Caption. Fakt, bo zamiast tego pole tekstowe posiada właściwość
text - polu txtmin nadaj wartość 1 a polu txtmax 9999. Ostatnią czynnością
jest zmienienie nazwy etykiety Label na lblwynik i także skasowanie zawartości
pola caption. Teraz nie pozostało nam nic innego jak dodanie do przycisku
START kodu. Ciekaw jestem czy pamiętasz jak to się robiło...
A więc zaznacz przycisk, teraz w inspektorze obiektów przejdź do zakładki
"Events" :

Zaznacz zdarzenie OnClick bo o takie nam chodzi i kliknij
dwukrotnie na białym polu - powinniśmy zobaczyć cos takiego:
procedure TForm1.cmdstartClick(Sender: TObject);
begin
end;
end.
Fajnie, ale co teraz ? Będą nam potrzebne cztery zmienne -
jedna będzie przechowywać wylosowaną liczbę w pamięci, druga podaną
przez nas liczbę, trzecia sprawdzać czy podana została prawidłowa odpowiedź
a czwarta który to już raz odpowiadamy. Musze tu wspomnieć, że będą to
dwie różne zmienne, jedna będzie przechowywać liczby całkowite (bo takie
będą losowane) a druga będzie przetrzymywać jedną z dwóch opcji - prawda
lub fałsz. Uwaga - wszystkie zmienne deklarujemy jeszcze przed rozpoczeciem
się danej procedury - czyli między liniami: procedure
TForm1.FormClick(Sender: TObject); a begin.
Do deklaracji zmiennych używamy słowa var - czyli nasz kod
powinien wyglądać teraz tak:
procedure TForm1.cmdstartClick(Sender: TObject);
var
liczba, kolej:integer;
prop:string;
zgadnieto:bool;
begin
end;
Jak widzisz najpierw piszemy słowo var, potem pod spodem nazwę
zmiennej, kolejno dwukropek i typ. Każdą prostą instrukcję kończymy średnikiem
! Prosta instrukcja to taka, która wykonuje się jakby sama, np. instrukcją
prostą jest komunikat MessageBox, ale np. pętle składają się już z kilku
linii i są to instrukcje złożone.
Fajnie, mamy już zmienne, teraz musimy pomyśleć jak to ma
działać. Samą aplikacje można zrobić na kilka sposobów, możemy poradzić
sobie nawet bez użycia pętli, ale my jedną zastosujemy. Pętla jest
instrukcją złożoną i decyduje ona o tym czy jej wnętrze ma się wykonać
czy też nie. Nasza pętla będzie się wykonywać dopóty dopóki ni podamy
prawidłowej odpowiedzi o czym będzie świadczyła zmienna "zgadnieto".
A więc szkielecik pętli winien wyglądać tak:
procedure TForm1.cmdstartClick(Sender: TObject);
var
liczba, kolej:integer;
prop:string;
zgadnieto:bool;
begin
while (zgadnieto=false) do
begin
end;
end;
Kod staje się pomału zagmatwany - ale dojdziemy do wszystkiego - najbardziej
mylące mogą być te begin i end. Mamy już dwie pary - z tym, że jedna
rozpoczyna i kończy zdarzenie, a druga jest ciałem pętli. W kodzie pojawiła
się nowa instrukcja:
while (zgadnieto=false) do
begin
instrukcje;
end;
While to angielskie dopóki - czyli jeśli zostanie spełniony
warunek w nawiasie (w naszym przypadku jeśli w zmiennej zgadnięto będzie
wyrażenie false) to wykonają się instrukcje zawarte między słowami begin
i end. Ale mało tego, jeśli się wykonają to aplikacja powtórnie rozpatrzy
wyrażenie - na tym polega pętla. Jeśli zdarzyło by się tak, że zmienna
zgadnięto nigdy nie przyjmie wartości true to pętla będzie nieskończona i
spowoduje to zawieszenie aplikacji !
Mamy już pętlę, teraz wypada wylosować jakąś liczbę z
podanego przedziału. Tylko gdzie taki kawałek kodu wsadzić - do pętli czy
przed pętle, czy może jeszcze za nią ? Za pętlą ? Wykluczone, w pętli ?
Hmmmm, zastanówmy się - czy chcemy po każdej złej odpowiedzi losować nową
liczbę ? Chyba nie, no wiec jedynie możemy zrobić to przed pętlą. Do
generacji liczb losowych służy funkcja:
jakas_liczba = x + random(y);
Gdzie x jest wartością minimalną, a y maksymalną. Muszę
wspomnieć o kolejnej rzeczy - w Delphim nie jest możliwe łączenie dwóch
zmiennych różnych typów w sposób bezpośredni. O co chodzi - my w pole
tekstowe będziemy wpisywać liczby, ale tak naprawdę zostaną one zwrócone
jako łańcuch znaków a nie jako liczba.
Aby do łańcucha przeładować np. zawartość pola
tekstowego to wpierw trzeba utworzyć zmienną typu string (nazwa:string), a
następnie użyć instrukcji przekazania:
zmienna := poletekstowe.text;
Czy cos Ci to przypomina ? Ostatni człon to nic innego jak
nazwa kontrolki i po kropce jedna z jej właściwości. Jak się okaże w
przyszłości możemy tym sposobem zmieniać wszystkie właściwości. Np. chcąc
zmienić etykietkę przycisku cmdstar możemy napisać:
cmdstart.caption := 'Nowa etykieta;'
I poznałeś znów kolejną rzecz - wszystkie łańcuchy
tekstowe przetrzymujemy w znaczku apostrofa. Operatorem przypisania nie jest
samo = jak w innych językach lecz := trzeba o tym pamiętać !
A więc zabierzmy się za generację liczby losowej - do kodu
dopisz:
procedure TForm1.cmdstartClick(Sender: TObject);
var
liczba, kolej:integer;
prop:string;
zgadnieto:bool;
begin
zgadnieto := false;
randomize;
liczba := strtoint(txtmin.text) +
random(strtoint(txtmax.text));
while (zgadnieto=false) do
begin
end;
end;
Wygląda to bardzo groźnie - aby lepiej zrozumieć pokażę
to porównawczo:
liczba := liczba_minimalna + random(liczba_maksymalna);
liczba := strtoint(txtmin.text) +
random(strtoint(txtmax.text));
Wcześniej pisałem, że nie można sumować dwóch stringów,
a więc zaraz po pobraniu danych z pól tekstowych należało je przerobić na
liczby za pomocą instrukcji strtoint(jakisstring). Pod koniec tej lekcji będziemy
zamieniać odwrotnie - liczby na stringa - wtedy lepiej to zrozumiesz.
A więc mamy wygenerowaną liczbę losową, jeszcze wspomnę o
instrukcji randomize. Gdyby jej nie było, za każdym uruchomieniem aplikacji
losowana była by ta sama liczba. Jeszcze wcześniej przyjąłem założenie,
że w zmiennej zgadnięto od razu będzie false, czyli fałsz.
Teraz zadamy pierwsze pytanie - umieścimy go także przed pętlą
za pomocą instrukcji:
InputBox('Tytuł','Treść','domyslnie');
Wartość zwraca stringa wpisanego do wyświetlonego pola. Jeśli
w okienku naciśniemy cancel to zwrócona zostaje domyślna odpowiedź.
Do kodu więc dopiszmy:
procedure TForm1.cmdstartClick(Sender: TObject);
var
liczba, kolej:integer;
prop:string;
zgadnieto:bool;
begin
zgadnieto := false;
randomize;
liczba := strtoint(txtmin.text) + random(strtoint(txtmax.text));
prop := InputBox('Zgadula','Podaj liczbę','');
if (prop = '') then exit
while (zgadnieto=false) do
begin
end;
end;
Pierwsza niebieska linijka to wyświetlenie komunikatu, druga
linijka to sprawdzenie czy naciśnięto cancel. Instrukcja warunkowa IF jest
bardzo powszechnie stosowana IF z angielskiego to Jeśli, a więc jeśli w
zmiennej prop będzie pusto to wtedy wykona się instrukcja exit czyli zakończenie
działania procedury i tym samym przerwanie gry.
Możesz spróbować uruchomić swój projekt - zobaczysz
przynajmniej okienko. Jak na razie ani OK ani CANCEL specjalnie nie działa,
zmieńmy to więc.
Teraz musimy sprawdzić czy wpisana liczba do okienka była
mniejsza, większa czy może równa liczbie wylosowanej. I znów posłużymy
się instrukcja IF, ale teraz bardziej ją rozbudujemy - tzn na kilka linii.
procedure TForm1.cmdstartClick(Sender: TObject);
var
liczba, kolej:integer;
prop:string;
zgadnieto:bool;
label ponownie;
begin
zgadnieto := false;
kolej:= 1;
randomize;
liczba := strtoint(txtmin.text) + random(strtoint(txtmax.text));
prop := InputBox('Zgadula','Podaj liczbę','');
if (prop = '') then exit;
while (zgadnieto=false) do
begin
if (strtoint(prop) = liczba) then
begin
messagebox(0,'Gratulacje','Zgadula',MB_OK) ;
zgadnieto := true;
end;
if (strtoint(prop) < liczba) then
begin
prop := InputBox('Zgadula','Za mało !','');
kolej := kolej + 1;
if (prop = '') then exit;
goto ponownie;
end;
if (strtoint(prop) > liczba) then
begin
prop := InputBox('Zgadula','Za dużo !','');
kolej := kolej + 1;
if (prop = '') then exit;
goto ponownie;
end;
ponownie:
end;
lblwynik.caption := 'Zgadłeś za ' + inttostr(kolej) +
' razem';
end;
Tym razem
Wszystko tutaj powinno być jasne, ale nowością jest label i
goto. Label służy do deklaracji etykiety w kodzie a goto to nic innego jak
przeskocz do podanej etykiety. Na końcu znów pokazane jest łączenie stringów
i niezbędna konwersja z integer na string. Aplikacja gotowa - możemy już w
nią grac :)
Dla bardziej wtajemniczonych - wiem, że dało się program
napisać prościej, ale chciałem użyć większej liczby nowych instrukcji !
Aha - obiecałem na poprzedniej lekcji że dziś zajmiemy się
inspektorem obiektów oraz poznamy dokładniej własciwości kontrolek. Pomyślałem
jednak, że skoro miesiąc temu zajmowaliśmy się wyłącznie graficznym środowiskiem
to dziś na odmianę napiszemy coś - lekcja o właściwościach za miesiąc...
Życzę udanej kompilacji
Slash
slash83@wp.pl
|