UWAGA! Promocja dla firm - MICROSOFT OFFICE 365  na 12 miesiecy ZA DARMO! Tylko na CentrumXP.pl!
Wielka promocja Office 365 na CentrumXP.pl!
Do góry Skomentuj

Tetris w C#

Tetris w C#

Autor: Marcin Hałaczkiewicz Opublikowano: 26 kwietnia 2007 Odsłon: 72 967

W tym artykule stworzymy jedną z najstarszych gier komputerowych - Tetrisa. Będziemy mówić o rysowaniu, napiszemy klasę, której właściwości będą dziedziczyć klasy pochodne. Dodatkowo zbudowany element bardzo nam się przyda w kolejnej części, w której napiszemy Snake'a - popularną gierkę spotykaną na komórkach. Pokażemy również jak dodać do formularza kontrolkę "ręcznie", czyli nie używając graficznego edytora Visual Studio.

Jak zwykle na początek tworzymy nowy projekt, nadajemy mu nazwę i wykonujemy pozostałe podstawowe czynności. Zmieniamy rozmiary naszej formy na 354x333, właściwość MaximizeBox ustawiamy na false, a AutoSizeMode na GrowAndShrink. Wszystko to po to, aby nie można było zmaksymalizować ani zmienić wymiarów formy. Dodajmy teraz nowy pusty plik do projektu, nazwijmy go Kratka. Umieścimy w nim klasę Kratka, która będzie reprezentować podstawowy obiekt w naszej grze - pojedynczy element klocka. Aby można było korzystać z funkcji do obsługi grafiki u góry pliku piszemy:

using System.Drawing;

Następnie wyposażamy klasę w następujące zmienne:

private Rectangle kwadrat;
private Color kolor;
private int x, y;
private bool zajeta;
public const int wymiar = 15;

x i y to położenie elementu klocka. Jest ono podawane w kratkach, a nie we współrzędnych (np. x = 2 i y = 3 oznacza trzecią kratkę od lewej i czwartą od góry, trzecia i czwarta bo liczymy od 0). kwadrat służy do przechowywania prostokąta, który reprezentuje element klocka, w kolor pamiętana jest barwa kratki. Zmienna zajeta mówi nam, czy kratka jest wypełniona, czy też wolna. Natomiast wymiar to stała oznaczająca wysokość i szerokość kratki w pikselach. Wyposażamy naszą klasę w zestaw trzech konstruktorów. Pierwszy to konstruktor domyślny nie przyjmujący żadnych argumentów. Tworzy on nowy prostokąt, ustawia współrzędne kratki na (0, 0) oraz nadaje kratce domyślny czarny kolor. Drugi robi to samo ale zmienia współrzędne zgodnie z naszym życzeniem, trzeci dodatkowo nadaje żądany kolor. Wyposażamy klasę również w funkcje do sprawdzenia stanu kratki (wolna/zajęta), do ustawienia jej koloru oraz do odczytania go. Oprócz tego kratka musi posiadać funkcje pozwalające na wyświetlenie elementu oraz ukrycie (czyli wypełnienie określonym kolorem, takim jak tło), więc tworzymy funkcje rysuj i kasuj. Możemy już zamknąć plik Kratka.cs, nie będziemy go więcej modyfikować.

Zajmiemy się teraz zaprogramowaniem figur do gry. Tworzymy nowy plik i nazywamy go figura. W nim piszemy klasę figura. Struktura ta będzie reprezentować klocek używany do gry w tetrisa. Będzie on miał swój kolor, współrzędne oraz kąt o jaki jest obrócony. W klasie będzie znajdować się jedynie konstruktor bezparametrowy oraz funkcja obracająca figurę o odpowiedni kąt. Konstruktor tworzy losowy element oraz nadaje jej losowy kolor. Poszczególne kratki figury przechowywane są w tablicy bool[4, 4]. W funkcji odwrocona zapisane są współrzędne wszystkich klocków w każdej pozycji, dzięki czemu gdy chcemy obrócić element wystarczy, że podamy w argumencie nowy kąt klocka spośród 0, 90, 180 i 270 stopni, a funkcja zwróci figurę ustawioną pod odpowiednim kątem.

Teraz dodajemy do projektu kolejny plik i nazywamy go plansza. Tworzymy w nim klasę o nazwie Plansza, która jest wyprowadzona z System.Windows.Forms.Panel. Plansza posłuży nam do graficznej reprezentacji okna gry. W jej wnętrzu znajdzie się tablica kratek oraz podstawowe funkcje do jej obsługi. Będą to rysujkratke, które narysuje odpowiednią kratkę, gdy jest to możliwe. Kolejna to sprawdzwymiary, która informuje nas o tym czy podane współrzędne mieszczą się na planszy. target="_blank"odswiez i reset odpowiednio przerysują lub skasują wszystkie kratki. Plansza posiada także dwa konstruktory, które odpowiednio ją inicjują.

Następny plik w naszym projekcie nazywa się Plansza_Tetris. W jego wnętrzu umieścimy definicję klasy Plansza_Tetris, którą wyprowadzimy z klasy Plansza. Będzie ona właściwą planszą do tetrisa. Klasa Plansza_Tetris zawiera jedynie zmienne do przechowywania współrzędnych lewego górnego rogu figury, oraz samą figurę. Za to jest wyposażona w sporo funkcji. Pierwsza z nich rysujfigure służy do wyświetlenia wybranej figury w konkretnym miejscu planszy. Kolejne trzy: wdol, wlewo i wprawo pozwalają przesunąć klocek o jeden wiersz lub kolumnę w wybranym kierunku. Z kolei obroc_w_lewo i obroc_w_prawo służą do obrotu klocka o dziewięćdziesiąt stopni w określoną stronę. Funkcja wyczysclinie czyści (zmazuje) wskazany wiersz, a przesunlinie przesuwa linie o jeden wiersz w dół. Metoda linie sprawdza czy powstały jakieś pełne linie na planszy. Jeśli tak, to czyści je i odpowiednio przesuwa pozostałe. Będzie ona wywoływana, gdy klocek opadnie. Na koniec jeszcze funkcja getfigura, która zwraca aktualnie kontrolowany element.

Wyposażeni w takie klasy możemy zacząć projektować główny moduł. Otwieramy plik z formą (pełen kod - Form1.cs) i dodajemy do niej następujące zmienne:

private Plansza_Tetris Plansza_do_gry;
private Plansza_Tetris nastepny;

private Label Pkt, Poziom;
private Label lblPkt, lblPoziom;
private Label info;

public int level;
public int punkty;

private bool szybka;
private bool gra;
private bool pauza;

Plansza_do_gry będzie reprezentować główny ekran gry. nastepny posłuży do wyświetlania kolejnego klocka jaki się pojawi. Etykiety wyświetlą poziom gry oraz zdobyte punkty, które będą przechowywane odpowiednio w level i punkty. Etykieta info będzie pokazywać legendę gry. szybka powie nam czy spadający klocek jest przyspieszony (po naciśnięciu klawisza w dół), gra będzie informować nas o tym czy gra się odbywa, a pauza czy włączyliśmy pauzę. Przechodzimy do widoku graficznego i dodajemy kontrolkę Timer, nazywamy ją licznik i klikamy na niej 2 razy by utworzyć obsługę zdarzenia Tick. Wrócimy do niego później. Teraz dodajemy do formy funkcję Inicjuj. Umieszczony w niej kod zainicjuje wszystkie dodawane przez nas kontrolki odpowiednimi wartościami, określi ich szerokość, położenie, itp. Ponadto odpowiednio ustawi wcześniej utworzone zmienne. Dodajemy teraz kod obsługi zdarzenia Plansza_Paint, które ustawiliśmy dla Plansza_do_gry i nastepny. Będzie się ono wywoływać np. po zminimalizowaniu okna programu i przywróceniu mu poprzednich wymiarów. Jego zadaniem będzie przerysowanie plansz. Wracamy teraz do zdarzenia  Tick dla licznika. Będzie on je generował co pewien okres czasu zależny od poziomu. Po każdym tyknięciu kontrolowana figura musi opaść jeden wiersz w dół, a gdy to niemożliwe - musi pojawić się nowy klocek. Jeśli figura opadnie, procedura sprawdza się czy powstały jakieś linie i w razie potrzeby odpowiednio reaguje. Gdy nie będzie możliwości dodania do planszy nowego elementu (czyli gdy zabraknie już miejsca), gra się zakończy. Ponadto licznik aktualizuje planszę nastepny tak, aby pokazywała ona cały czas klocek, który pojawi się po aktualnym. Kontroluje także ilość zdobywanych punktów i poziom gry. Na koniec dodajemy jeszcze obsługę zdarzenia KeyDown dla naszej formy. Będzie ono przechwycać wciśnięcie klawisza oraz odpowiednio reagować w zależności od jego rodzaju. I tak np. po naciśnięciu Escape gra się zakończy, a gdy wciśniemy strzałkę w dół - klocek przyspieszy. Opis wszystkich używanych przycisków znajduje się w legendzie (etykieta info).

Właśnie ukończyliśmy tetrisa. Jak się okazało wcale nie było to takie trudne. Najważniejsze są klasy Plansza oraz Plansza_Tetris. To one przechowują informacje o grze oraz potrafią zachować się jak na tetrisa przystało (kasowanie lini, itp.). Drugi ważny element - odliczanie -  zrealizowany jest w liczniku i to on sprawia, że klocki opadają w dół. Serdecznie zapraszam do bicia rekordów :)

Zobacz również

Komentarze

hmmm..mam dokladnie tak samo ale nie reaguje na klawisze
aigi, 18 czerwca 2007, 19:17
Aby reagowalo na klawisze trzeba kliknac akcje Key Down formy w jej oknie Events i wkleic kod. Wtedy dziala.
blah, 28 czerwca 2007, 15:01
tak tez zrobilam,to byla pierwsza moja mysl,ale tak i tak nie dziala...
aigi, 19 lipca 2007, 15:46
chyba robie blad w dodawaniu pliku,powilnnam dodac klase czy codefile?
aigi, 19 lipca 2007, 17:02
Ja dodałem klase - i działa :)
m, 5 sierpnia 2007, 19:49
aigi pewnie pewnie juz jest za pozno z tym moim komentarzem ale napisze, moze komus innemu sie przyda - jezeli macie taki problem sprobujcie zamienic wlasciwosc KeyPreview dla formy na true - byc moze to pomoze
mardock, 26 listopada 2007, 18:16
Witam. Po zrobieniu wszystkiego wg instrukcji pojawia mi sie blad: The name "licznik" does not exist in the current context . Co mam zrobic? Pomozcie!!!
marcin, 13 stycznia 2008, 18:59
wszystko spoko dziala thx
k4, 22 stycznia 2008, 22:04
Przede wszystkim stosuj się do instrukcji.... Jest napisane przecież: Przechodzimy do widoku graficznego i dodajemy kontrolkę Timer, nazywamy ją licznik i klikamy na niej 2 razy by utworzyć obsługę zdarzenia Tick. Jak to zrobisz będzie działało bez problemu
Shl, 22 stycznia 2008, 23:47
cienko opisane metody, co robia? itp wiem, ze jest pomoc w C# i jest wszystko napisane ale jak ktos pisze jakis kurs to powinien tlumaczyc od deski do deski.
dok, 15 kwietnia 2008, 14:30
@dok: Czego konkretnie brakuje Ci w artykule?
Daniel K., 16 kwietnia 2008, 00:44
Czemu nie ma gotowego pliku do pobrania? :( bo wyskakuje mi kilka błędów i nie wiem co robić a takto bym sobie sprawdził z gotowym plikiem. Może ktoś dać linka do gotowego pliku? Proszę!
Juziogim3, 2 lipca 2008, 15:18
 KIEPSKIE ŻE NIEMOGE!!!

Ziom, 25 października 2008, 15:26
u mine wyskakuje błąd :
 
Error 1 Program "C:\Users\Jakub\Documents\Visual Studio 2008\Projects\Tetrissss\Tetrissss\obj\Debug\Tetrissss.exe" does not contain a static "Main" method suitable for an entry point Tetrissss<br /><br />może jakieś rady ??

dziadjihad, 19 listopada 2008, 00:29
bez statycznej metody Main nie zadziała

xxx, 2 grudnia 2008, 21:57
Witam. Mam również problem z obsługą klawiatury.. Zrobiłam wszystko wg instrukcji i Waszych podpowiedzi i niestety nadal nic.. Program uruchamia się, ale nie reaguje na zdarzenia.. Ustawiłam również grę na "true" , jednak to również nie dało rezultatu.. :( Proszę o pomoc i z góry dziękuję :)
Meg, 28 grudnia 2008, 20:11
Dobry poradnik, wszystko ładnie opisane na prawie wszystko ale poprzednicy to uzupełnili.
 
P.S.
A Ci co piszą że kiepski itp. To chyba o programowaniu niemają zielonego pjęcia. I chcą odrazu poważniejsze rzeczy pisać. A pozatym ~70% czasu przy projektowaniu jakiejs aplikacji to jest poprawa błędów(takie śą fakty).

voidrek, 26 stycznia 2009, 09:28
cześć mógłby ktoś podesłać mi program na mejla? kamil_lacki@o2.pl
z góry pięknie dziękuje :)

hihot, 28 stycznia 2009, 23:59
Problem z dzialaniem strzalek na klawiaturze, dziala wszystko inne a, s, d, w itd. ale nie dzialaja strzalki. Oczywiscie KeyPreview dla formy na true. Zalezy mi na strzalkach bo pisze troszke bardziej zaawnsowany programik i obsluge bajerow ustawiem na czesci ASCII, a do poruszania sie potrzebne mi strzalki. Prosze o jakies solucje :)

blacky, 23 marca 2009, 12:02
Cóż mogę powiedzieć, mi wszystko działa, wystarczyło do głównej formy dodać obsługę zdarzenia KeyDown
 
this.KeyDown += new KeyEventHandler(Form1_KeyDown);
Inicjuj(); // tak dla orientacji w kodzie dla zupełnie zielonych;)
 
ktoś miał problem z licznikiem, upewnij się czy dodałeś do głównej formy Timer"a i zmieniłeś właściwość "Name" na "licznik"

aniol, 5 maja 2009, 19:50
prosze, niech ktos przepchnie na maila. tezcatlipoca_one@o2.pl

gość, 7 maja 2009, 08:21
Moze ktos mi przeslac na maila ten projekt bede bardzo wdzieczny:)
Grzes89iek@gmail.com

Grzesiek, 12 maja 2009, 13:17
Wszystkie jest opisane w tych postach co trzeba zrobić żeby działało innej opcji nie ma - patrz koment "aniol". Ja powiem tyle, że o ile faktycznie to wszystko działa to tłumaczenie jest jedną, wielką, fatalną, żenującą porażką. Ktoś kto już programuje łatwo się w tym znajdzie i zauważy co się czym zajmuje, ale przecież ten art nie jest dla tych co się znają. Więc przydatność dla początkujących marna.

Bobov, 9 czerwca 2009, 00:02
Kurs jest fajny, ale ktoś powinien go zdebugować - przecież nie ma zamieszczonego przykładowego działającego projektu, a pliki, które są zawierają błędy. Też oczywiście miałem problem z obsługą klawiszy - trzeba przecież dodać obsługę klawiczy w Inicjuj(). Mi po wykonaniu tych wszystkich instrukcji nie wiem czemu nie działa opadanie klocków. Dopiero się uczę i naprawdę nie wiem w czym jest problem. Może ktoś wie i się podzieli rozwiązaniem?
Tomek, 9 czerwca 2009, 09:52
wszystko działa, instrukcja jest przejrzyście napisana. Najłatwiej zrobić caly projekt tak, że dodajemy klasy pokolei i wklejamy gotowce, które są tu na stronie. Program może sie wysypać w jednym miejscu: jak dodajemy obsługę zdarzenia "Tick" to moze nam napisac Tick_1 w kodzie zamiast Tick (mi tak robiło). Autor zapomniał o bardzo ważnej rzeczy, którą napisał juz wczesniej kolega anioł:
 
this.KeyDown += new KeyEventHandler(Form1_KeyDown);
<br /> Inicjuj(); // tak dla orientacji w kodzie

 
chodzi o tą pierwszą linijkę. Trzeba ją dodać do pliku Form1.cs (druga linijka tylko pokazuje gdzie powinniśmy dodac tą pierwszą).
Po tym wszystko już śmiga, fajnie sie gra, ja juz do 10lvl dobiłem ;D
Acha i jeszcze jedno bardzo ważne: zeby to zrozumiec trzeba conajmniej raz przeczytać całą ta instukcje od poczatku do konca, bo bez tego to raczej trudno.
pzdr

mr.zbro, 9 czerwca 2009, 14:14
Czy tos moze zamiescic kod 2 konstrutorow z pliku Plansza.cs bo strona jest nieosiąglna http://www.centrumxp.pl/dotNet/Podstrony/Plansza.htm#public_Plansza() lub wyslac mi na maila a bardzo chce uruchomic gre pozdrawiam
adasko, 7 października 2009, 12:20
Oki juz poradzilem sobie z moim probleme
adasko, 7 października 2009, 13:02
sam kurs jest ok, ale wydaje mi sie ze troche jest tu niescislosci jesli chodzi o nazewnictwo. chyba ze autor od razu zalozyl ze ten kurs czytaja programisci, a nie poczatkujacy. ja sie tu gubie niestety...
czolg, 13 grudnia 2009, 19:28
Mógłby ktoś dać już całął paczkę wraz z kodem źródłowym ?
igorw6, 28 grudnia 2009, 23:22
czy ktoś może mi wyjaśnić dlaczego visualstudio wywala mi błąd: Error    1    No overload for method "Kratka" takes "2" arguments    C:\C#\TETRIS\tetris\tetris\plansza.cs    24    28    tetris przy kodzie: public  Plansza_Tetris (int a, int b): base(a, b)     {         x_figury = y_figury = 0;     } ?? będe wdzięczny za pomoc
coldblue, 2 lutego 2010, 17:07
moze ktos mi powiedziec dlaczego te klocki mi nie opadają???
jama, 28 grudnia 2010, 12:48
pytanie - co zrobić by zmieinć wymiary planszy ? tzn żeby powiększyło się pole do gry.. np szerkość na 20 kratek..
tomiii, 10 stycznia 2011, 13:32
Co dokladnie robi this.Size = new System.Drawing.Size(sz_ekranu * kratka.wymiar + 4, wys_ekranu * kratka.wymiar + 4); Tworzy jakis tam rozmiar??
itachi, 12 stycznia 2011, 13:06
podeślijcie mi proszę projekt na maila: mark.trait@gmail.com ;)
mark.trait, 3 kwietnia 2011, 18:17
"Dodajmy teraz nowy pusty plik do projektu, nazwijmy go Kratka." jakiego typu ma być ten plik png, txt czy co ?? proszę o odpowiedź. z góry dziękuje.
greg19, 23 października 2011, 18:00
Pojawia mi sie blad "The type or namespace name "Form1" could not be found (are you missing a using directive or an assembly reference?)" moglby ktos pomoc ? :)
Marcin, 13 listopada 2011, 21:34
Tworzymy pusty plik kratka a w nim klasę, czyli tworzymy ten plik .cs The namespace ... być może Twoja forma nie jest widoczna
Pozny typ, 23 kwietnia 2012, 18:44

Dodaj swój komentarz

Zasady publikacji komentarzyZasady publikacji komentarzy

Redakcja CentrumXP.pl nie odpowiada za treść komentarzy publikowanych na stronach Portalu
i zastrzega sobie prawo do usuwania wypowiedzi, które:

  • zawierają słowa wulgarne, obraźliwe, prowokujące i inne naruszające dobre obyczaje;
  • są jedynie próbami reklamowania stron internetowych (spamowanie poprzez umieszczanie linków);
  • przyczyniają się do złamania prawa bądź warunków licencyjnych oprogramowania (cracki, seriale, torrenty itp.);
  • zawierają dane osobowe, teleadresowe, adresy mailowe lub numery GG;
  • merytorycznie nie wnoszą nic do dyskusji lub nie mają związku z tematem komentowanego newsa, artykułu bądź pliku.

Autor:

Komentarz:

Dodaj komentarz