Uwaga: nie chcę tutaj pomocy w kodowaniu, jestem włączony Programmers
z jakiegoś powodu. Chcę poprawić swoje umiejętności planowania / pisania programów, a nie (tylko) rozumienie języka Java .
Próbuję wymyślić, jak stworzyć drzewo, które ma dowolny system kategorii, w oparciu o umiejętności wymienione w tej grze LARP tutaj . Moja poprzednia próba polegała na tym, że umiejętność była również kategorią. Próba kodowania tego była nieporządna. Rysując moje drzewo zauważyłem, że tylko moje „liście” były umiejętnościami, a pozostałe oznaczyłem jako kategorie.
To, co szukam, to sposób na utworzenie drzewa, które będzie próbowało oddzielić Model i Widok, i pozwolić na dodanie dowolnego typu węzła potomnego (z osobnym sposobem edycji / renderowania) do dowolnego rodzica.
Uwaga: Wszystko tutaj jest kupowane jako umiejętność, nawet jeśli wydaje się być własnością. Użytkownicy końcowi uznają to za umiejętności kupowania (co robią na bankomacie w formie papierowej), dlatego należy je przedstawić jako takie, wszystkie na tej samej stronie.
Wyjaśnienie drzewa: Drzewo „rodzi się” z zestawem kategorii zakodowanych na najwyższym poziomie ( broń, fizyczne i psychiczne, medyczne itd.). Na tej podstawie użytkownik musi mieć możliwość dodania umiejętności. Ostatecznie chcą na przykład dodać umiejętność Specjalizacja miecza jednoręcznego ( nie przedmiot). Aby to zrobić, najlepiej kliknij „dodaj” z Weapons
zaznaczonym, a następnie wybierz One-handed
z węzła combobox, który pojawia się na tym dziecku, a następnie kliknij ponownie dodaj i wprowadź nazwę w polu tekstowym na tym węźle potomnym, który się pojawi. Następnie kliknij przycisk Dodaj ponownie, aby dodać / określić „poziom” lub „poziom” dla tego liścia; najpierw biegłość, potem specjalizacja (na przykład).
Oczywiście, jeśli chcesz kupić inną umiejętność, jest to zupełnie inna droga do liścia. Możesz nie potrzebować pola kombi na tym samym poziomie w dół drzewa, co na przykład z bronią, i potrzebujesz też innej logiki. Właśnie z tego powodu nie mogę się skupić na programowaniu; jak utworzyć zestaw klas i nie określać kolejności, w jakiej należy je ze sobą połączyć, ale nadal mają wszystkie pasujące.
Jaki jest dobry system do opisywania tego rodzaju drzewa w kodzie? Wszystkie inne przykłady JTree, które widziałem, mają pewien przewidywalny wzór, a mój nie . Nie chcę kodować tego wszystkiego w „literałach”, z długimi listami tego, jaki typ (pole kombi, pole tekstowe itp.) Węzła potomnego powinien być dozwolony na jakim rodzicu. Czy powinienem używać klas abstrakcyjnych? Interfejsy?
Jak mogę sprawić, by ten rodzaj obiektów był rozszerzalny, gdy dodam inne umiejętności niewymienione powyżej, które zachowują się inaczej?
Jeśli istnieje nie system dobry do użycia, czy istnieje dobry sposób na wypracowanie jak robić tego typu rzeczy?
Koła zębate w mojej głowie obracają się:
Zawsze muszę:
- Sprawdź rodzica
- Podaj opcje w zależności od rodzica
Zaczynam myśleć ze względu na tę skill
powszechność. Potrzebuję czegoś w rodzaju klasy abstrakcyjnej / interfejsu, która definiuje / określa powszechne metody umiejętności i kategorii. Mogę (mam nadzieję) umieścić zasady i opcje w bazie danych i czytać stamtąd. Pytanie brzmi, jak myślę teraz, między metodą abstrakcyjną lub metodą interfejsu a tym, jak ją zaimplementować.
źródło
Odpowiedzi:
Prosty przykład mutable JTree
Kod (zgodny i przetestowany z Javą 7, aby zrobić powyższy obraz):
Specjalne podziękowania dla tego samouczka JTree
Aktualizacja: omówienie możliwych rozwiązań
Istnieje samouczek dotyczący tworzenia dynamicznego drzewa za pomocą przycisków u dołu ramki, aby dodać / usunąć / wyczyścić węzły.
W przypadku pól kombi i tym podobnych, chcesz wziąć obiekty odpowiedniej klasy swing i sprawić, by były czymś w rodzaju JComboBox, który implementuje java.swing.tree.MutableTreeNode. Samouczek Java Swing zawiera listę elementów sterujących .
Nadal musisz utworzyć element interfejsu użytkownika, aby umożliwić użytkownikom wybór rodzaju węzła, który chcą dodać, i edytować węzeł. Jeśli dodadzą pole kombi, będą musieli móc określić, jakie opcje będzie dostępne.
Potrzebujesz podstawowego modelu danych, aby zapisać swoje dane. Możesz użyć domyślnego schematu serializacji wbudowanego we wszystkie obiekty Java, ale służy on tylko do prototypowania - zepsuje się, jeśli kiedykolwiek zmienisz kod programu. Będziesz musiał użyć bazy danych z JDBC lub JPA albo będziesz musiał napisać własne procedury serializacji (lub użyć biblioteki, która obsługuje serializację), używając czegoś takiego jak JSON lub XML jako format przechowywania.
Aktualizacja: Proponowane rozwiązanie z przeglądem projektu
Najprostszym rozwiązaniem może być zapomnienie o bazach danych i wymyślenie najpierw wyrażenia XML danych, a następnie edycja pliku XML i wyświetlenie wyników jako JTree bez specjalnych pól kombi lub czegokolwiek. Myślę, że właśnie to sugerował Chibueze Opata swoją odpowiedzią. Częściowa reprezentacja XML tego drzewa może wyglądać następująco:
Oto kilka potencjalnych kamieni milowych dla Ciebie:
Pamiętaj, aby zapisać kopię zapasową programu za każdym razem, gdy działa on na końcu każdego kamienia milowego. System kontroli źródła zainstalowany na innym komputerze jest do tego idealny. Możesz użyć github, sourceforge lub innej publicznej kontroli źródła, jeśli nie masz nic przeciwko udostępnianiu kodu i nie chcesz konfigurować serwera z kontrolą źródła.
Każde z tych rozwiązań jest pracochłonne i zdecydowanie większe niż projekt dla początkujących. Oznacza to, że poświęcisz znacznie więcej czasu na naukę Java Swing i XML lub JSON niż granie na LARP, dlatego po raz pierwszy zbadałem opcje wykorzystania istniejących narzędzi. Ale najlepszym sposobem na naukę czegokolwiek jest najbardziej zmotywowany do nauki. To może być dla Ciebie idealny projekt.
Mam nadzieję że to pomogło.
źródło
Nie sądzę, aby JTree stanowiło właściwą reprezentację problemu, który próbujesz rozwiązać. Spojrzałem na twoją stronę internetową i widzę listy rzeczy. To świetny początek, ale myślę, że istnieje podstawowy projekt danych, który możesz mieć, ale nie widzę.
Życie i siła wyglądają jak atrybuty postaci. Podwójne, Potrójne i Czteroosobowe wyglądają jak wartości dla atrybutu Siła. Potem widzę umiejętności podzielone na broń i medycynę. Uważam broń za posiadanie (które można kupić, znaleźć lub upuścić) i zakładam, że ta umiejętność pozwala ci być skutecznym z daną bronią. Ale sposób, w jaki na to patrzę, broń i medycyna nie mają umiejętności, bohater ma. W rzeczywistości podejrzewam, że Postać jest centralną postacią w twoim projekcie danych.
Oto trzy obiekty danych, które do tej pory wyróżniały się na tle mojego projektu:
Teraz postać może mieć broń i umiejętności, ale do naprawdę dobrego ataku potrzebują umiejętności specyficznej dla używanej broni. W każdym razie istnieją tutaj relacje jeden do wielu (jedna postać może mieć wiele umiejętności). Ale jeszcze nie widzę drzew.
Weź bloczek papieru i na pierwszej stronie umieść postać na środku strony i wypisz 5–10 najważniejszych obiektów świata gry. Dowiedz się, jakie dane są jedynie atrybutem innego obiektu (np. Życie i Siła są nieodłącznymi częściami postaci) i jakie są najważniejsze relacje między obiektami, bez myślenia o drzewach, polach tekstowych lub polach kombi. Narysuj linie między obiektami, aby przedstawić relacje. Następnie dowiedz się, które relacje to 1: 1, a które są 1: wiele, a które są liczne: wiele, i oznacz je etykietami. Mogą istnieć „has-a” i „is-a” oraz inne rodzaje relacji.
Możesz zdecydować, że potrzebujesz osobnych reprezentacji dla WeaponSkill vs. HealingSkill vs. ManufactureSkill. Możesz też zdecydować, że są tak podobne, że należą do jednej tabeli umiejętności (w moim przykładzie powyżej) z polem określającym, jaki to rodzaj umiejętności.
To dobry znak, że nie jesteś zadowolony ze swoich dotychczasowych prób - oznacza to, że przed wybraniem jednej z nich chcesz rozważyć wiele możliwości. Im więcej szkiców bierzesz pod uwagę, tym lepszy będzie twój ostateczny projekt. W końcu najlepszym stanie się diagram danych. Gdy jest to dość dobrze rozwiązane, możesz wrócić do myślenia o „polach kombi” lub „polach tekstowych”, ale decyzje dotyczące interfejsu użytkownika pozostawię do końca.
Zamiast patrzeć na JTrees, sugerowałbym zapoznanie się z tematami Struktur danych, Projektowanie baz danych, a może modelowania danych. EDYCJA-> Lub jeszcze lepsze diagramy mapowania relacji między bytami, jak sugerował David Kaczyński! <-EDYCJA Jeśli poprawnie opracujesz projekt danych, Java i interfejs użytkownika będą z niego płynąć w sposób oczywisty i naturalny. Ale jeśli pomylisz się, to żadna ilość Java-kung-fu lub UI-beauty to nie naprawi.
Powodzenia!
źródło
Skupię się na modelu obiektowym.
Myślę, że ze względu na elastyczność, którą chcesz, prawdopodobnie chcesz podzielić swoje klasy na warstwę wiedzy (być może „definicja” jest lepszym słowem w tym przypadku) i warstwę transakcji. Przez „warstwę” naprawdę rozumiem tylko logiczne rozdzielenie ich w głowie. Warstwa wiedzy zawiera definicję rozłożenia drzewa, a dane w nim pochodzą od projektanta gry, a warstwa danych przechowuje określone wybory dla konkretnej postaci.
Twój poziom wiedzy będzie co najmniej nieco niechlujny, ponieważ starasz się stworzyć fajną grę, a nie matematycznie czysty model.
Próbuję uporządkować to, co do tej pory masz, myślę, że masz klasę SkillDefinition, a także właściwość Parent typu SkillDefinition. Masz również podklasy SkillDefinition (które mogą stać się pozycjami w tabeli DEF_SkillType w bazie danych), aby objąć kilka przypadków.
Wydaje się, że „broń”, „fizyczna i psychiczna” oraz „medycyna” mają tylko tytuł (i umiejętności dziecka).
Wydaje się, że „One Handed”, „Strength” i „Bind Wounds” mają powiązane pole kombi (co oznacza coś w rodzaju tabeli DEF_SkillChoice w bazie danych z kluczem obcym do DEF_Skill). Miecz i łuk wydają się ciągiem zdefiniowanym przez użytkownika (więc nie ma powiązanej tabeli na poziomie wiedzy, ale dane będą przechowywane w warstwie transakcji).
Wydaje się, że z „życiem” jest związana liczba całkowita. Może nie być w stanie współużytkować tej klasy z żadnymi przyszłymi cechami, które wykorzystują liczbę całkowitą, ponieważ istnieje domniemane zachowanie dotyczące sposobu zwiększania liczby całkowitej. W każdym razie obecnie potrzebuje własnej klasy.
„Sword”, „Bow”, „Strength” i „Bind Wounds” wydają się mieć powiązane z nimi poziomy umiejętności progresywnych poniżej drzewa. W przypadku „Sword” i „Bow” poziomy te są naprawdę powiązane z ich umiejętnościami rodzica. Myślę, że potrzebujesz klasy ProgressiveSkillDefinition z uporządkowaną kolekcją wartości prawnych (tabela DEF_SkillLevel z kluczem obcym do DEF_Skill. Na poziomie wiedzy nie jest do końca jasne, jakie reguły modelujesz. Jeśli „biegłość” i „specjalizacja” są zawsze dostępne dla wszystkich broni możesz mieć tabelę DEF_SkillLevel z rekordami „biegłości” i „specjalizacji” posiadającymi obce klucze do rekordu „Broń”.
Obejmuje to, co wiesz na poziomie wiedzy. Poziom transakcji (być może „poziom postaci” byłby lepszą nazwą?) Wskazuje tylko na odpowiedni poziom wiedzy. Tak więc w twoim przykładzie miałbyś obiekt postaci z obiektem umiejętności, który ma kolekcję umiejętności - tylko te, które faktycznie posiada.
Tak więc postać miałaby umiejętność „Biegłość”, której rodzicem jest umiejętność „miecz”, a jej typ to Skill_Level. W bazie danych rekord TRANS_SkillDefinition zawiera klucz obcy do transakcyjnego rekordu umiejętności „miecz” i rekordu DEF_SkillLevel poziomu wiedzy o nazwie „Proficiency”.
Umiejętność biegłości miałaby obiekt nadrzędny umiejętności „miecza” typu Skill_UserNamed. W bazie danych nie miałby to klucza obcego do poziomu wiedzy, ponieważ dla słowa „miecz” nie ma nic specjalnego (to nazwa użytkownika). Ma jednak również klucz obcy do nadrzędnego rekordu transakcji, dzięki czemu można uzyskać więcej informacji za jego pośrednictwem.
Obiekt umiejętności „miecz” ma obiekt nadrzędny „jednoręczny”, ponieważ użytkownik postanowił umieścić „miecz” w kategorii „jednoręcznej”. Jest to obiekt typu SkillCategory. W bazie danych ma obcy klucz do tabeli DEF_SkillChoice dla rekordu „jedną ręką” i brak transakcyjnego elementu nadrzędnego, ponieważ wszystkie dodatkowe dane dotyczące tej umiejętności są przechowywane na poziomie wiedzy.
Podczas konstruowania drzewa początkowego dla nowej postaci należy zapytać tylko o poziom wiedzy. Aby wypełnić wybory dokonane dla postaci, wymagany jest poziom transakcyjny.
Będziesz potrzebował kodu, aby przetłumaczyć model obiektowy na drzewo iz powrotem. Mam nadzieję, że powinno być jasne, co należy zrobić - każdy typ w warstwie wiedzy będzie miał powiązany zestaw elementów sterujących w drzewie, który pobierze dane odpowiednie dla tego typu.
Później możesz chcieć klas dla każdego wyboru w rekordach SkillCategory (jeśli „Specjalizacja” ma z tym związane zachowanie, kod musi gdzieś iść), ale nie potrzebujesz tego jeszcze dla tego drzewa, a ten projekt będzie kompatybilny z tym. Musisz tylko mieć fabrykę, która wykorzystuje informacje o poziomie wiedzy do zbudowania odpowiedniego obiektu.
źródło
W końcu zawsze kończymy na zarządzaniu strukturami hierarchicznymi - czy to hierarchią klas programu, czy samym programem zbudowanym z różnych modułów łączących cię z „wewnętrznym światem” (GUI, połączenie DB, logika biznesowa związana z danymi itp.) . Ale to jest filozofia, jak powinna działać w twoim przypadku?
W tym drzewie masz węzły, każdy element jest „instancją obiektu”; podczas gdy ich zachowanie (gdzie można je umieścić, listę dozwolonych węzłów potomnych itp.) jest wspólne dla niektórych zestawów, takich jak „klasy”. Tak, to jest jak kod programu. Jeśli znasz wystarczająco odbicie Java, możesz nawet użyć klas POJO i hierarchii dziedziczenia, aby zbudować ten komponent z kontenerem IoC lub mechanizmem fabrycznym do zbudowania rzeczywistych instancji. Ale myślę, że tego nie chcesz, ponieważ jest to hakowanie ciężkiego języka, więc ...
Najpierw utwórz obiekt „klasy”, który będzie opisywał zachowanie elementów. Zawiera identyfikator klasy, nazwy „pola” oraz dozwolone typy i liczbę przedmiotów itp. Przykład: klasa „root” to „Właściwości gracza”, mają pola „Fizyczne / umysłowe”, „Medyczne”, „Broń”. Ten typ jest „ostateczny”: w tej chwili nie chcesz mieć różnych typów graczy. Wskazówka: później możesz to zrobić, używając tych samych narzędzi do obsługi „potworów innych niż ludzie” ... :-)
Pole „Medycyna” to
Wręcz przeciwnie: Członek broni nie jest wymagany, należy go utworzyć, gdy do gracza zostanie dodana pierwsza broń. Oznacza to: kiedy „edytujesz” swój „obiekt” (obecnie odtwarzacz) i chcesz zezwolić na dodanie do niego nowego elementu, nie powinieneś ograniczać wyboru rzeczywistymi właściwościami instancji (która teraz nie zawiera „broni” ”), ale pokaż wszystkie pola definicji klasy i leniwie utwórz nowe pole (węzeł potomny) przy pierwszym użyciu. Stworzy to rozszerzalne środowisko. Później możesz dodać pole „Znajomi” z wieloma graczami ... eee ... referencjami (patrz później).
Postępuj zgodnie z procesem z rzeczywistymi „klasami”. Pomoże ci dopracować swoje pomysły, na przykład: wydaje się, że lepiej jest rozdzielić typy broni (miecze, sztylety, łuki, ...), jakoś radzić sobie z amunicją (wiedząc, że być może gracz NIE ma łuku, ale może zbierać strzały, ale używając niektóre bronie wymagają amunicji i dekrementacji, niektóre z nich można znaleźć, inne zostały zgubione ...) w klasie „Broń”: łatwiej jest przeprowadzić ankietę, a także pokazać, czy gracz niesie tylko ten przedmiot, czy też może go użyć ( ma umiejętności). Z drugiej strony: z pewnością zmienisz tę strukturę w miarę rozwoju gry.
Utwórz globalnie dostępny „sklep klasowy”, który zainicjujesz, gdy rozpocznie się gra, i podaj definicje klas, gdy ktoś odwoła się do ich nazwy. W tym przypadku obiekty klasy def muszą być niezmienne.
„Obiekty” są łatwiejsze: można je uzyskać z tej samej klasy głównej, która zawiera odwołanie do definicji klasy oraz ogólny dostęp do pól. Być może użyj HashMap, aby zatrzymać te dzieci, identyfikowane przez nazwę pola. Pamiętaj: niektóre z tych pól zawierają pojedynczy obiekt, inne zestaw obiektów. Te przypadki są oczywiście zmienne.
Teraz interfejs. Najpierw powinieneś sprawdzić samouczek JTree ... i teraz powinno być oczywiste. Każdy „obiekt” może być reprezentowany przez DefaultMutableTreeNode, „userObject” węzła powinien być twoim obiektem (myślę, że toString () tego węzła jest wyświetlana jako etykieta węzła, ale możesz utworzyć niestandardowy formatator komórek). Ilekroć otwierasz węzeł, przeglądasz pola obiektu i tworzysz węzły potomne pod rodzicem (jeśli chcesz to zrobić dynamicznie) - lub przeglądasz całe drzewo i budujesz strukturę TreeNode, gdy wyświetlasz JTree (wskazówka: tam to konstruktor JTree z parametrem TreeNode).
Po wybraniu węzła w drzewie masz instancję Object. Według jego klasy, możesz wyświetlić odpowiedni panel edytora lub ogólny panel generowany przez definicję klasy (np .: panele kart z polami, edytory pola rzeczywistego według deklaracji pola: przycisk, który tworzy dziecko odpowiedniego typu of pozwala wybrać jedną z dostępnych klas oraz pola edytora dla tego wystąpienia, takie jak właściwości broni). Po zmodyfikowaniu struktury musisz odświeżyć samo drzewo - TreeModel i jego ogień ... funkcje zmiany są Twoimi przyjaciółmi.
Wygląda dobrze? Czy zbyt skomplikowany? To niewielki ułamek historii. Nie rozmawiałem o tym
W każdym razie mam nadzieję, że możesz skorzystać z tej sesji rozgrzewki.
źródło
Nie dam ci długiej odpowiedzi, ale już wcześniej spotkałem się z taką sytuacją i szczerze mówiąc, zrezygnowałem z prób wykorzystania dowolnej istniejącej struktury danych. Po prostu stworzyłem własny obiekt, który mógłby akceptować nowych rodziców i dzieci, podobnie jak Węzeł XML.
Jednak w twoim przypadku myślę, że użycie klasy Xml pomoże. Następnie możesz mieć właściwości dla każdego węzła, które informują cię, czy dana klasa jest umiejętnością, i możesz łatwo uzyskać rodziców i dzieci z dowolnego węzła, którego chcesz użyć w polu kombi lub w inny sposób.
Ponadto chciałbym dodać, że nie powinieneś uciekać od myśli o dużej ilości tekstów / ciągów. Gry zwykle wymagają sztucznej inteligencji, a sztuczna inteligencja zwykle wymaga dużej ilości tekstów.
źródło