Szukam rozwiązania problemu „Opcje kliknięcia prawym przyciskiem”.
Zasadniczo każdy element w grze, po kliknięciu prawym przyciskiem myszy, może wyświetlić zestaw opcji w zależności od tego, czym jest obiekt.
Przykłady kliknięcia prawym przyciskiem myszy dla różnych scenariuszy :
Inventory: Helmet pokazuje opcje (Equip, Use, Drop, Description)
Bank: Hełm pokazuje opcje (Weź 1, Weź X, Weź wszystko, Opis)
Piętro: kask pokazuje opcje (Take, Walk Here, Description)
Oczywiście każda opcja w jakiś sposób wskazuje na pewną metodę, która robi to, co mówi. Jest to część problemu, który próbuję rozwiązać. Przy tak wielu opcjach poprawiania pojedynczego przedmiotu, jak miałbym tak zaprojektować moje zajęcia, aby nie były wyjątkowo niechlujne?
- Myślałem o dziedziczeniu, ale mogło to być naprawdę długie i łańcuch może być ogromny.
- Myślałem o użyciu interfejsów, ale prawdopodobnie ograniczyłoby to mnie trochę, ponieważ nie byłbym w stanie załadować danych elementu z pliku Xml i umieścić go w ogólnej klasie „Element”.
Opieram pożądany wynik końcowy na grze o nazwie Runescape. Każdy obiekt można kliknąć prawym przyciskiem myszy w grze i w zależności od tego, co to jest i gdzie to jest (ekwipunek, piętro, bank itp.) Wyświetla inny zestaw opcji dostępnych dla gracza do interakcji.
Jak miałbym to osiągnąć? Jakie podejście powinienem zastosować przede wszystkim, zdecydować, które POWINNY zostać wyświetlone, a po kliknięciu, jak wywołać odpowiednią metodę.
Używam C # i Unity3D, ale wszelkie podane przykłady nie muszą być powiązane z żadnym z nich, ponieważ szukam wzorca w przeciwieństwie do rzeczywistego kodu.
Jakakolwiek pomoc jest mile widziana, a jeśli nie wyraziłem się jasno w swoim pytaniu lub oczekiwanych wynikach, proszę o komentarz, a ja postaram się jak najszybciej.
Oto, co dotychczas próbowałem:
- W rzeczywistości udało mi się zaimplementować ogólną klasę „Przedmiot”, która przechowuje wszystkie wartości dla różnych rodzajów przedmiotów (dodatkowy atak, dodatkowa obrona, koszt itp.). Te zmienne są zapełniane danymi z pliku Xml.
- Myślałem o umieszczeniu każdej możliwej metody interakcji w klasie przedmiotów, ale myślę, że jest to niewiarygodnie niechlujna i zła forma. Prawdopodobnie podjąłem niewłaściwe podejście do wdrażania tego rodzaju systemu, używając tylko jednej klasy, a nie podklasowania do różnych elementów, ale jest to jedyny sposób, w jaki mogę załadować dane z Xml i zapisać je w klasie.
- Powodem, dla którego zdecydowałem się załadować wszystkie moje elementy z pliku Xml, jest to, że ta gra ma możliwość ponad 40 000 przedmiotów. Jeśli moja matematyka jest poprawna, klasa dla każdego przedmiotu to wiele klas.
źródło
Odpowiedzi:
Podobnie jak w przypadku wszystkich elementów związanych z tworzeniem oprogramowania, nie ma idealnego rozwiązania. Tylko rozwiązanie idealne dla Ciebie i Twojego projektu. Oto niektóre, których możesz użyć.
Opcja 1: model proceduralny
Starożytnyprzestarzałametoda starej szkoły.Wszystkie elementy są głupimi, zwykłymi, starymi typami danych bez żadnych metod, ale wiele publicznych atrybutów, które reprezentują wszystkie właściwości, które może mieć element, w tym niektóre flagi boolowskie
isEdible
,isEquipable
itp., Które określają, jakie pozycje menu kontekstowego są dla niego dostępne (być może możesz również obejść się bez tych flag, jeśli można je wywnioskować z wartości innych atrybutów). Mają pewne metody, takie jakEat
,Equip
itd. W klasie gracza, który zajmuje pozycję i który posiada wszystkie logiki przetwarzać zgodnie z wartościami atrybutów.Opcja 2: model obiektowy
Jest to bardziej rozwiązanie OOP-by-the-book oparte na dziedziczeniu i polimorfizmie.
Mają bazową klasy
Item
, z której inne przedmioty, takie jakEdibleItem
,EquipableItem
itd dziedziczenia. Klasa bazowa powinna mieć metodę publicznąGetContextMenuEntriesForBank
,GetContextMenuEntriesForFloor
itp, które zwróci listęContextMenuEntry
. Każda dziedzicząca klasa zastąpiłaby te metody, aby zwrócić pozycje menu kontekstowego odpowiednie dla tego typu elementu. Może również wywołać tę samą metodę klasy podstawowej, aby uzyskać domyślne wpisy, które można zastosować do dowolnego typu elementu.ContextMenuEntry
Byłaby klasa z metodąPerform
, która następnie wywołuje odpowiednią metodę z elementu, który ją stworzył (można użyć delegata do tego).Jeśli chodzi o problemy z implementacją tego wzorca podczas odczytywania danych z pliku XML: Najpierw sprawdź węzeł XML dla każdego elementu, aby określić typ elementu, a następnie użyj specjalnego kodu dla każdego typu, aby utworzyć instancję odpowiedniej podklasy.
Opcja 3: model oparty na komponentach
Ten wzór wykorzystuje kompozycję zamiast dziedziczenia i jest bliższy temu, jak działa reszta Jedności. W zależności od tego, jak ustrukturyzujesz swoją grę, może być możliwe / korzystne użycie systemu komponentów Unity do tego ... lub nie, twój przebieg może się różnić.
Każdy obiekt klasy
Item
musiałaby listę składników jakEquipable
,Edible
,Sellable
,Drinkable
, itd. Element może mieć jeden lub żaden z każdego komponentu (na przykład kask wykonany z czekolady byłoby zarównoEquipable
aEdible
, a gdy nie jest to działka o znaczeniu krytycznym przedmiot zadania równieżSellable
). Logika programowania specyficzna dla komponentu jest zaimplementowana w tym komponencie. Gdy użytkownik kliknie element prawym przyciskiem myszy, elementy elementu są iterowane i dla każdego istniejącego elementu dodawane są pozycje menu kontekstowego. Gdy użytkownik wybierze jeden z tych wpisów, składnik, który dodał ten wpis, przetwarza opcję.Możesz to przedstawić w pliku XML, mając podwęzeł dla każdego komponentu. Przykład:
źródło
Mike Hunt, twoje pytanie mnie tak zainteresowało, postanowiłem wdrożyć pełne rozwiązanie. Po trzech godzinach próbowania różnych rzeczy, skończyłem z tym krok po kroku:
(Należy pamiętać, że NIE JEST to bardzo dobry kod, więc zaakceptuję wszelkie zmiany)
Tworzenie panelu zawartości
(Ten panel będzie pojemnikiem na nasze przyciski menu kontekstowego)
UI Panel
anchor
w lewym dolnym roguwidth
na 300 (jak chcesz)Vertical Layout Group
i ustawChild Alignment
na górną środkową,Child Force Expand
na szerokość (nie wysokość)Content Size Fitter
i ustawVertical Fit
na Min. Rozmiar(W tym momencie nasz Panel zmniejszy się do linii. To normalne. Ten panel akceptuje przyciski jako dzieci, wyrównuje je w pionie i rozciąga do wysokości zawartości podsumowania)
Tworzenie przycisku próbki
(Ten przycisk zostanie utworzony i dostosowany, aby wyświetlać elementy menu kontekstowego)
anchor
w lewym górnym roguLayout Element
, ustawionyMin Height
na 30,Preferred Height
na 30Tworzenie skryptu ContextMenu.cs
(Ten skrypt ma metodę, która tworzy i pokazuje menu kontekstowe)
ContentPanel
prefabrykat do odpowiedniego gniazda i przeciągnij płótno do gniazdaCanvas
.Tworzenie skryptu ItemController.cs
Cube
), Umieść go tak, aby był widoczny dla kamery i dołącz do niego ten skrypt. Przeciągnij i upuśćsampleButton
prefabrykat do odpowiedniego gniazda.Teraz spróbuj go uruchomić. Po kliknięciu obiektu prawym przyciskiem myszy powinno pojawić się menu kontekstowe z zapełnioną przez nas listą. Naciśnięcie przycisków spowoduje wydrukowanie tekstu na konsoli, a menu kontekstowe zostanie zniszczone.
Możliwe ulepszenia:
Przykładowy projekt (Unity Personal 5.2.0, wtyczka VisualStudio): https://drive.google.com/file/d/0B7iGjyVbWvFwUnRQRVVaOGdDc2M/view?usp=sharing
źródło