Ich suche nach einer Lösung für das Verhalten "Rechtsklickoptionen".
Grundsätzlich kann jeder Gegenstand in einem Spiel, wenn mit der rechten Maustaste darauf geklickt wird, eine Reihe von Optionen basierend auf dem Objekt anzeigen.
Rechtsklick-Beispiele für verschiedene Szenarien :
Inventar: Helm zeigt Optionen (Ausrüsten, Benutzen, Ablegen, Beschreibung)
Bank: Helm zeigt Optionen (Take 1, Take X, Take All, Beschreibung)
Etage: Helm zeigt Optionen (Take, Walk Here, Description)
Offensichtlich verweist jede Option irgendwie auf eine bestimmte Methode, die das tut, was gesagt wird. Dies ist ein Teil des Problems, das ich herauszufinden versuche. Wie würde ich bei so vielen Potenzierungsoptionen für einen einzelnen Gegenstand meine Klassen so gestalten, dass sie nicht extrem chaotisch sind?
- Ich habe über Vererbung nachgedacht, aber das könnte sehr langwierig sein und die Kette könnte riesig sein.
- Ich habe über die Verwendung von Schnittstellen nachgedacht, aber dies würde mich wahrscheinlich ein wenig einschränken, da ich keine Artikeldaten aus einer XML-Datei laden und in eine generische "Item" -Klasse einfügen könnte.
Ich stütze mein gewünschtes Endergebnis auf ein Spiel namens Runescape. Jedes Objekt kann im Spiel mit der rechten Maustaste angeklickt werden. Abhängig davon, was es ist und wo es sich befindet (Inventar, Etage, Bank usw.), werden dem Spieler verschiedene Optionen zur Interaktion angeboten.
Wie würde ich das erreichen? Wie gehe ich vor? Entscheide, welche Optionen angezeigt werden SOLLTEN und wie die entsprechende Methode aufgerufen werden soll.
Ich verwende C # und Unity3D, aber die bereitgestellten Beispiele müssen sich nicht auf eines von beiden beziehen, da ich nach einem Muster im Gegensatz zum tatsächlichen Code arbeite.
Jede Hilfe wird sehr geschätzt und wenn ich in meiner Frage oder den gewünschten Ergebnissen nicht klar war, schreibe bitte einen Kommentar und ich werde mich so schnell wie möglich darum kümmern.
Folgendes habe ich bisher versucht:
- Ich habe es tatsächlich geschafft, eine generische "Item" -Klasse zu implementieren, die alle Werte für verschiedene Arten von Gegenständen enthält (zusätzlicher Angriff, zusätzliche Verteidigung, Kosten usw.). Diese Variablen werden mit Daten aus einer XML-Datei gefüllt.
- Ich habe darüber nachgedacht, jede einzelne mögliche Interaktionsmethode in die Item-Klasse aufzunehmen, aber ich denke, das ist eine unglaublich chaotische und schlechte Form. Ich habe wahrscheinlich den falschen Ansatz gewählt, um diese Art von System zu implementieren, indem ich nur eine Klasse verwendet habe und keine Unterklassen für verschiedene Elemente erstellt habe. Es ist jedoch die einzige Möglichkeit, die Daten aus einer XML-Datei zu laden und in der Klasse zu speichern.
- Der Grund, warum ich mich dazu entschlossen habe, alle meine Artikel aus einer XML-Datei zu laden, ist, dass dieses Spiel die Möglichkeit hat, mehr als 40.000 Artikel zu speichern. Wenn meine Mathematik stimmt, besteht eine Klasse für jeden Gegenstand aus vielen Klassen.
quelle
Antworten:
Wie bei allem in der Softwareentwicklung gibt es keine ideale Lösung. Nur die Lösung, die für Sie und Ihr Projekt optimal ist. Hier sind einige, die Sie verwenden könnten.
Option 1: Das Vorgehensmodell
Die
alteveralteteOld-School-Methode.Alle Einzelteile sind stumm plain-old-Datentypen ohne Methoden , aber viele öffentliche Attribute , die alle Eigenschaften ein Element darstellen könnte, darunter auch einige boolean Flags wie haben
isEdible
,isEquipable
usw. , die bestimmen , welche Kontextmenüeinträge für sie verfügbar sind (vielleicht könnten Sie auch Verzichten Sie auf diese Flags, wenn Sie sie aus den Werten anderer Attribute ableiten können. Habe einige Methoden wieEat
,Equip
usw. in Ihrer Player - Klasse , die ein Element nimmt und die alle die Logik es zu verarbeiten hat die Attributwerte nach.Option 2: Das objektorientierte Modell
Dies ist eher eine OOP-by-the-Book-Lösung, die auf Vererbung und Polymorphismus basiert.
Haben Sie eine Basisklasse ,
Item
von denen andere Einzelteile mögenEdibleItem
,EquipableItem
usw. erben. Die Basisklasse sollte über eine öffentliche Methode usw. verfügenGetContextMenuEntriesForBank
,GetContextMenuEntriesForFloor
die eine Liste von zurückgibtContextMenuEntry
. Jede übernehmende Klasse würde diese Methoden überschreiben, um die Kontextmenüeinträge zurückzugeben, die für diesen Elementtyp geeignet sind. Es könnte auch dieselbe Methode der Basisklasse aufrufen, um einige Standardeinträge abzurufen, die für jeden Elementtyp gelten. DasContextMenuEntry
wäre eine Klasse mit einer Methode,Perform
die dann die entsprechende Methode aus dem Item aufruft, das sie erstellt hat (Sie könnten dafür einen Delegaten verwenden ).Bezüglich Ihrer Probleme bei der Implementierung dieses Musters beim Lesen von Daten aus der XML-Datei: Untersuchen Sie zunächst den XML-Knoten für jedes Element, um den Elementtyp zu bestimmen, und verwenden Sie dann für jeden Typ speziellen Code, um eine Instanz der entsprechenden Unterklasse zu erstellen.
Option 3: Das komponentenbasierte Modell
Dieses Muster verwendet Komposition anstelle von Vererbung und entspricht eher der Funktionsweise von Unity. Abhängig davon, wie Sie Ihr Spiel strukturieren, kann es möglich / vorteilhaft sein, das Unity-Komponentensystem für diese Aufgabe zu verwenden.
Jedes Objekt der Klasse
Item
eine Liste der Komponenten haben würde wieEquipable
,Edible
,Sellable
,Drinkable
usw. Ein Element eine oder keines der einzelnen Komponenten (zum Beispiel haben kann, ein Helm aus Schokolade wäre sowohlEquipable
undEdible
, und , wenn es nicht ein grafische Darstellung kritische Questgegenstand auchSellable
). Die für die Komponente spezifische Programmierlogik ist in dieser Komponente implementiert. Wenn der Benutzer mit der rechten Maustaste auf ein Element klickt, werden die Komponenten des Elements iteriert und Kontextmenüeinträge für jede vorhandene Komponente hinzugefügt. Wenn der Benutzer einen dieser Einträge auswählt, verarbeitet die Komponente, die diesen Eintrag hinzugefügt hat, die Option.Sie könnten dies in Ihrer XML-Datei darstellen, indem Sie für jede Komponente einen Unterknoten haben. Beispiel:
quelle
Also, Mike Hunt, Ihre Frage hat mich so interessiert, dass ich beschlossen habe, eine vollständige Lösung zu implementieren. Nachdem ich drei Stunden lang verschiedene Dinge ausprobiert hatte, endete ich mit dieser schrittweisen Lösung:
(Bitte beachten Sie, dass dies KEIN sehr guter Code ist, so dass ich alle Änderungen akzeptieren werde.)
Inhaltsbereich erstellen
(Dieser Bereich ist ein Container für unsere Kontextmenü-Schaltflächen.)
UI Panel
anchor
nach unten-linkswidth
auf 300 ein (wie Sie wünschen)Vertical Layout Group
und Festlegen der Breite (nicht der Höhe)Child Alignment
in der oberen MitteChild Force Expand
Content Size Fitter
und setzen Sie sieVertical Fit
auf Min. Größe(An diesem Punkt wird unser Bedienfeld auf eine Linie verkleinert. Es ist normal. In diesem Bedienfeld werden Schaltflächen als untergeordnete Elemente akzeptiert, vertikal ausgerichtet und auf die Höhe des Zusammenfassungsinhalts gedehnt.)
Beispielschaltfläche erstellen
(Diese Schaltfläche wird instanziiert und angepasst, um Kontextmenüelemente anzuzeigen.)
anchor
nach oben linksLayout Element
, dieMin Height
auf 30 undPreferred Height
30 gesetzt istErstellen eines ContextMenu.cs-Skripts
(Dieses Skript verfügt über eine Methode zum Erstellen und Anzeigen des Kontextmenüs.)
ContentPanel
Prefab per Drag & Drop auf den entsprechenden Steckplatz und ziehen Sie den Canvas-Bereich auf den SteckplatzCanvas
.Script ItemController.cs erstellen
Cube
), platzieren Sie es so, dass es für die Kamera sichtbar ist, und hängen Sie dieses Skript daran an.sampleButton
Fertighaus per Drag & Drop in den entsprechenden Steckplatz ziehen.Versuchen Sie nun, es auszuführen. Wenn Sie mit der rechten Maustaste auf das Objekt klicken, sollte das Kontextmenü mit der von uns erstellten Liste angezeigt werden. Durch Drücken der Tasten wird Text in die Konsole gedruckt und das Kontextmenü wird zerstört.
Mögliche Verbesserungen:
Beispielprojekt (Unity Personal 5.2.0, VisualStudio Plugin): https://drive.google.com/file/d/0B7iGjyVbWvFwUnRQRVVaOGdDc2M/view?usp=sharing
quelle