|
via Udemy |
Go to Course: https://www.udemy.com/course/csharp-zbuduj-wlasnego-tetrisa-kompletny-przewodnik/
Chcesz nauczyć się programowania gier w C#? Zbuduj od podstaw kultowego Tetrisa i poznaj kluczowe koncepcje programowania! W tym kursie przeprowadzimy Cię przez cały proces - od minimalnej wersji gry (MVP) po bardziej zaawansowane mechaniki i optymalizację.Czego się nauczysz?Rozpoczniemy od implementacji z podziałem na warstwy i utrzymaniem najlepszych praktyk programowania. Zaczniemy od utworzenie projektu w Visual Studio z odpowiednimi warstwami:Tetris.Domain: Logika gry i modele.Tetris.Application: Zasady działania gry, logika aplikacji.Tetris.Infrastructure: Integracja z zewnętrznymi komponentami (jeśli będzie potrzebne).Tetris.Presentation: WPF - interfejs użytkownika.Krok 1. MVP naszej gry Tetris, skupiamy się na najbardziej podstawowych elementach gry, takich jak:Reprezentacja planszy jako siatki.Jeden prosty klocek.Mechanika opadania bloku w dół.Podstawowy interfejs (np. wyświetlanie planszy w WPF).Nie dodajemy od razu zaawansowanych funkcji, takich jak różne kształty klocków, poziomy trudności czy interakcje gracza, ponieważ najważniejsze jest przetestowanie podstawowej mechaniki. Gdy MVP działa poprawnie i spełnia oczekiwania, możemy zacząć rozwijać bardziej zaawansowane funkcjonalności.Następnie przeanalizujemy kod pod kątem zgodności z najlepszymi praktykami i zasadami:1. SOLID· Single Responsibility Principle (SRP):· Open/Closed Principle (OCP):· Liskov Substitution Principle (LSP):· Interface Segregation Principle (ISP):· Dependency Inversion Principle (DIP):2. Separation of Concerns (SoC)3. KISS (Keep It Simple, Stupid)4. DRY (Don't Repeat Yourself)5. YAGNI (You Aren't Gonna Need It)6. Cohesion i CouplingKrok 2. Dodamy testy jednostkowe zgodnie z podejściem TDD dla naszego kodu gry Tetris.Stworzymy testy dla głównych komponentów, zaczynając od podstawowych funkcjonalności.Testy naszej planszy do gry - klasy GameBoard:Sprawdzenie poprawnego tworzenia planszy czyli - Testy konstruktoraWeryfikacja, czy komórki są początkowo puste - Testy metody IsCellEmptyTestowanie umieszczania bloków na planszy - Testy metody PlaceBlockTesty warunków brzegowychTesty naszego serwisu - klasy GameService:Sprawdzenie poprawnego tworzenia nowych bloków - SpawnBlockTestowanie ruchu bloków w dół - MoveBlockDownWeryfikacja zachowania przy osiągnięciu dnaSprawdzenie poprawnego zbierania wszystkich bloków na planszy - GetBlocksTesty będą wykorzystywać:xUnit jako framework testowyMoq do mockowania zależnościFluentAssertions do czytelniejszych asercjiKrok 3 Dodanie różnych typów blokówDodanie różnych typów bloków w projekcie wymaga wprowadzenia odpowiednich modyfikacji w kodzie, które będą zgodne z zasadami projektowymi. W szczególności zastosujemy polimorfizm, co pozwoli na efektywne zarządzanie różnymi kształtami bloków. Dzięki temu nasz kod stanie się bardziej czytelny, elastyczny i zgodny z najlepszymi praktykami programowania.Krok 4 Zastosowanie wzorca Factory Method.Cel wzorca:Oddzielenie logiki tworzenia klocków od reszty kodu, co ułatwi zarządzanie i rozszerzanie aplikacji.Zamiast tworzyć obiekty GameBlock bezpośrednio w różnych miejscach kodu, będziemy korzystać z fabryki (GameBlockFactory), co poprawia czytelność i elastyczność kodu.Plan działań:Przeniesiemy IGameBoard do folderu Interfaces, aby lepiej uporządkować kod nasz kod.Dodamy GameBlockType (enum) - reprezentujący różne typy klocków (I, O, T, S, Z, J, L).Stworzymy interfejs IGameBlockFactory, który określi, jak powinna działać fabryka klocków.Zaimplementujemy GameBlockFactory, która będzie:Tworzyć klocek na podstawie zadanego typu (CreateGameBlock).Tworzyć losowy klocek (CreateRandomGameBlock).Dzięki temu jeśli w przyszłości dodamy nowe typy klocków, wystarczy zmodyfikować fabrykę, zamiast zmieniać kod w wielu miejscach!Krok 5 Dodanie obsługi obracania klocków za pomocą klawiatury.Aby poprawnie zaimplementować obrót klocków w grze, należy uwzględnić kolizje zarówno ze ścianami planszy, jak i innymi blokami. Jeśli obrót nie jest możliwy, kształt klocka powinien pozostać bez zmian.Plan Implementacji:1. Modyfikacja klasy GameBlock- Istniejąca metoda Rotate zostanie dostosowana tak, aby zwracała obrócony kształt klocka.2. Aktualizacja klasy GameService- Dodanie metody CanRotate, która sprawdzi, czy obrót jest możliwy.- Implementacja RotateCurrentBlock do obsługi rotacji klocka.- Dodanie metod MoveBlockLeft i MoveBlockRight w kontekście obrotów.3. Dodanie Strategi- Dodamy interfejs IRotationStrategy. - Dodamy implementację strategii standardowej rotacji klocka o 90 stopni w prawo.- Dodamy implementacja braku rotacji dla klocka.- Dodamy Rotacja o 180 stopni- Dodamy Obracanie klocek przeciwnie do ruchu wskazówek zegara- Dodamy Rotację Losową, wybiera jedną z dostępnych strategii rotacjiKrok 6 Dodanie logiki detekcji i usuwania pełnych linii i dodanie punktacjiDodamy logike detekcji i usuwania pełnych linii oraz punktację do naszej gry. Zacznijmy od stworzenia odpowiednich elementów w domenie.Implementacja zapewnia:- Prawidłowe wykrywanie pełnych linii - system skutecznie identyfikuje wiersze wypełnione klockami.- Usuwanie linii i przesuwanie klocków w dół - po usunięciu pełnych linii pozostałe klocki są automatycznie przesuwane w dół.- Naliczanie punktów według zadanej tabeli - wynik jest aktualizowany zgodnie z liczbą usuniętych linii i przyjętymi zasadami punktacji.- Wyświetlanie aktualnego wyniku - UI natychmiast odświeża wynik oraz licznik usuniętych linii po każdej zmianie.Zastosuj wzorzec Observer PatternObserver Pattern idealnie pasuje do powiadamiania UI o zmianach w grze. Observer Pattern pozwoli na oddzielenie logiki gry od interfejsu użytkownika. Dzięki temu UI będzie reagować na zmiany, takie jak:- Aktualizacja punktacji- Licznik usuniętych linii- Czy Możliwość dodania innych zmian (np. Informowanie o końcu gry co teraz też dodamy)Krok 7 Dodanie Zapisywania wyników i wyswietlania Top 5Dodamy funkcjonalność zapisywania wyników oraz ich wyświetlania w formie listy Top 5 najlepszych rezultatów. Dzięki temu gracze będą mogli śledzić swoje osiągnięcia oraz rywalizować o najwyższe miejsca w rankingu. Następnie Dodamy teraz wzorzec Memento, który pozwala na zapamiętanie stanu wyników graczy w danym momencie - HighScoreMementoDzięki temu można cofnąć się do wcześniejszego stanu listy wyników bez ryzyka ich przypadkowej zmiany.