Kod

Przykłady programowania obiektowego: przewodnik po programowaniu obiektowym, część 8

Przykłady programowania obiektowego: Przewodnik po programowaniu obiektowym, część 8

Kurs wprowadzający do Pythona: dla wszystkich poziomów umiejętności ➞ Cztery imponujące projekty do Twojego portfolio i możliwość zadawania pytań ekspertowi. Dowiedz się, jakie umiejętności możesz zdobyć na tym kursie.

Dowiedz się więcej

Gratulacje dla wszystkich, którzy przebrnęli przez wszystkie poprzednie materiały i dotarli do etapu zajęć praktycznych z programowania obiektowego w C#. Przed nami stworzymy prostą grę konsolową. Zastosujemy umiejętności programowania obiektowego, które już opanowaliśmy, a także nauczymy się kilku nowych technik.

  • Klasy i obiekty to podstawowe koncepcje programowania obiektowego. Klasę można traktować jako szablon lub model, który definiuje strukturę i zachowanie obiektów tworzonych na jej podstawie. Opisuje ona właściwości i metody, które będą dostępne dla instancji tej klasy.

    Obiekt z kolei reprezentuje konkretną instancję klasy. Posiada wszystkie cechy zdefiniowane w klasie i może oddziaływać z innymi obiektami. Każdy obiekt może mieć własne unikalne wartości atrybutów, co czyni go indywidualnym, pomimo faktu, że jest oparty na tej samej klasie.

    Zatem klasy służą jako podstawa do tworzenia obiektów, a obiekty pozwalają na implementację funkcjonalności zdefiniowanej przez klasę w praktycznych scenariuszach programistycznych.

  • Charakterystyka interakcji z obiektami.
  • Modyfikatory dostępu i hermetyzacja to ważne koncepcje programowania obiektowego. Modyfikatory dostępu określają poziom dostępu do klas i ich elementów, umożliwiając kontrolowanie, które elementy mogą być widoczne i dostępne z innych części programu. Istnieje kilka typów modyfikatorów, takich jak public, private i protected, z których każdy ma swoje własne cechy i zastosowania.

    Enkapsulacja z kolei polega na ukryciu wewnętrznej implementacji obiektu przed światem zewnętrznym. Osiąga się to poprzez ograniczenie dostępu do danych i metod, co pomaga chronić stan obiektu i zapobiega jego nieprawidłowemu użyciu. W ten sposób enkapsulacja przyczynia się do tworzenia bezpieczniejszych i łatwiejszych w zarządzaniu rozwiązań programistycznych, zapewniając integralność danych i upraszczając interakcję z obiektami.

  • Polimorfizm i przeciążanie metod.
  • Polimorfizm.
  • Dziedziczenie i kilka słów o polimorfizmie.
  • Klasy abstrakcyjne i interfejsy to ważne koncepcje w programowaniu obiektowym. Umożliwiają one programistom tworzenie elastycznych i rozszerzalnych struktur, zapewniając podstawę do dziedziczenia i implementacji funkcjonalności.

    Klasa abstrakcyjna to klasa, której nie można utworzyć samodzielnie. Zamiast tego służy jako fundament dla innych klas, które dziedziczą jego właściwości i metody. Klasy abstrakcyjne mogą zawierać zarówno metody abstrakcyjne, które nie mają implementacji, jak i metody zwykłe ze zdefiniowaną implementacją. Pozwala to na tworzenie współdzielonej funkcjonalności, którą klasy dziedziczące mogą nadpisywać lub używać domyślnie.

    Interfejsy z kolei definiują zestaw metod, które klasa musi implementować, ale nie zawierają ich implementacji. Zapewnia to większy stopień abstrakcji i pozwala klasom o różnych hierarchiach dziedziczenia implementować te same interfejsy. Korzystanie z interfejsów pomaga stworzyć bardziej odseparowaną i modułową architekturę, w której klasy mogą łatwo ze sobą współdziałać, przestrzegając wspólnych kontraktów.

    Ostatecznie zarówno klasy abstrakcyjne, jak i interfejsy odgrywają kluczową rolę w projektowaniu oprogramowania, umożliwiając programistom efektywniejszą organizację kodu i tworzenie rozwiązań, które są łatwiejsze w utrzymaniu i rozszerzaniu w przyszłości.

  • Praktyczne.

Jak będzie wyglądała gra

Gra będzie projektem konsolowym z symboliczną grafiką, w którym gracze będą mogli przemieszczać się po różnych lokacjach, walczyć z postaciami niezależnymi, a także otwierać ekwipunek i używać przedmiotów.

Gra będzie zorganizowana w następujący sposób:

  • Po uruchomieniu gry wywoływana jest metoda InitGame(), która odpowiada za tworzenie obiektów gry, przedmiotów i innych elementów.
  • Następnie wywoływana jest metoda Update(), która odpowiada za aktualizację bieżącego stanu gry.

Wewnątrz metody Update() należy zaimplementować pętlę, która wykona następujące operacje:

  • Utworzy wizualizację lokalizacji lub przedmiotów w ekwipunku.
  • Określi, który klawisz został naciśnięty przez gracza.
  • Przekaże naciśnięcie klawisza do kontrolera.
  • W zależności od naciśniętego klawisza kontroler zainicjuje wywołanie metod obiektów gry, takich jak Move() lub Use().

W procesie zarządzania rozgrywką używamy trzech statycznych klas, które działają jako kontrolery.

  • LocationController odpowiada za śledzenie działań gracza w lokacji.
  • InventoryController odpowiada za śledzenie interakcji gracza z ekwipunkiem.
  • GraphicsController odpowiada za kontrolowanie wyników graficznych.

Informacje o parametrach gry, w tym o rozmiarze lokacji i liście obiektów, są przechowywane w statycznej klasie Game. Poszczególne obiekty będą reprezentowane przez klasy GameObject (jako podstawową), Player i NPC. Pozycja i ruch w otoczeniu będą kontrolowane przez klasę Position.

System implementacji obiektów wykorzystuje klasę Item jako klasę bazową, a także jej pochodne: Potion i Meal. Jeśli przedmiot ma użyteczność, implementuje interfejs IUsable.

Projekt nie jest bardzo duży, ale jeśli spróbujesz przedstawić go w całości w artykule, zabraknie miejsca na tekst. Dlatego przedstawione zostaną tylko kluczowe punkty. Aby uzyskać pełny przegląd projektu, pobierz cały kod źródłowy z repozytorium na GitHubie.

Proces tworzenia elementów gry

Zacznijmy od zdefiniowania klasy GameObjects, która posłuży jako podstawa do tworzenia klas Player i NPC.

Zwróć uwagę na metodę Die(). Ta metoda jest uruchamiana, gdy zdrowie obiektu osiągnie zero. Usuwa ona obiekt z kolekcji Game.Objects, co pozwala na zwolnienie zajmowanej przez niego pamięci. Destruktory pełnią podobną funkcję; są aktywowane przed ostatecznym usunięciem obiektu z pamięci.

Klasa NPC będzie podstawą do rozwoju logiki sztucznej inteligencji gry. Klasa Player z kolei będzie zawierać metody zarządzania postacią gracza. Na przykład, w przyszłości dodamy w tej klasie możliwość korzystania z przedmiotów z ekwipunku.

Jak wspomniano wcześniej, utworzone obiekty będą przechowywane w kolekcji statycznej klasy Game. Poniżej przedstawiono implementację tego:

Możesz zauważyć typ danych GameMode — jest to wyliczenie, które ułatwia tworzenie list.

Jedną z opcji, która może zastąpić klasy wyliczeniowe, są liczby. Można to wyrazić w następujący sposób:

Może to jednak nie być do końca wygodne, ponieważ trzeba będzie stale śledzić, jaki numer został podany i w jakim celu.

Grafika

Aby zapewnić wyświetlanie obiektów i lokalizacji, utworzymy klasę GraphicsController.

Formowanie obiektów odbywa się za pomocą symboli, które różnią się w zależności od kierunku, w którym zorientowany jest obiekt.

Teraz musimy wprowadzić zmiany w klasie Program, aby utworzyć pierwsze instancje i wyświetlić je na ekranie konsoli.

Przepraszamy, ale Twoje żądanie nie zawiera tekstu do przepisania. Podaj tekst, który chcesz przepisać.

Sterowanie

Aby zapewnić ruch obiektu kontrolowanego przez gracza, konieczne jest wdrożenie systemu sterowania.

Ta klasa śledzi, który klawisz naciska gracz i przekazuje otrzymane polecenia. Na przykład współpracuje z klasą Position, która kontroluje ruch obiektów w przestrzeni gry.

Można przetestować proces ruchu.

Wraz z ruchem wprowadzono również system walki:

Ekwipunek

System ekwipunku opiera się na klasie Przedmiot:

Klasy Mikstura i Posiłek mają praktycznie taką samą strukturę, różnią się jedynie wyświetlanymi komunikatami tekstowymi. Dlatego w tym przypadku zostanie zaprezentowany kod tylko jednej z tych klas:

Należy zauważyć, że ta klasa implementuje interfejs IUsable:

Aby użytkownik mógł przeglądać przedmioty w swoim ekwipunku, należy zaimplementować nową metodę w GraphicsController:

Ponadto w klasie Program należy uzupełnić instrukcję switch o nową opcję dla trybów:

Sterowanie będzie realizowane poprzez InventoryController:

Teraz przejdźmy do obiektu Player.

Tutaj przedstawiono dwa nowe słowa kluczowe:

  • is — sprawdza obecność określonego interfejsu w danym obiekcie.
  • as — zapewnia implementację interfejsu.

Przepraszam, ale nie widzę tekstu, który chcesz przepisać. Proszę o dostarczenie tekstu, a ja chętnie pomogę w jego poprawieniu.