Von Schildern und Dialogen

Jaa ich klaue mal die Titelstruktur von Zombiepriester :wink:

Es geht um folgendes:

Ich will bei einem ganz normalen rpg schilder auf der karte verteilen, und beim “drĂŒberlaufen”
eine box mit einer hilfemeldung erscheinen lassen. zB schild “zum wald” und text “nicht empfehlenswert, waffe zu schwach” oder so was.
Nun, mir fĂ€llt nicht ein wie man das möglichst “proffesionell” machen könnte. Ich habe daran gedacht das ich bei jedem gameloop durchlauf
die spielerkoordinaten an die Klassse Sign ĂŒbergebe, die SignListener implementiert - sign listener hĂ€tte dann die methode “showSignFromCoords” oder so was.
aber wenn ich 50 schilder auf der map hÀtte, dann hÀtte ich ja 50 if abfragen ob der spieler im bereich jenes 1 bis 50.ten schildes ist


Also, hat einer idee wie man sowas “besser” lösen könnte? Oder sogar selber schon mal jemand gemacht und könnte ein wenig code posten?

Vielen Dank!

*** Edit ***

Mir fĂ€llt gerade folgendes ein: Man könnte ja ein array von rectangles anlegen die die schildcoordinaten enthalten, (natĂŒrlich automatisiert - also neues schild neues rectangle)
aber dann wĂŒrde ich ja immer noch in einer for loop alle diese rectangles durchlaufen und mit dem spieler rectangle vergleichen
 wĂ€re das vielleicht eine akzeptable lösung?

*** Edit 2.0***

ok mir ist noch was aufgefallen: Im prinzip muss ich ja einen eigenen listener schreiben, wie eben der mouseListener auch prĂŒfen kann ob ich “mit der maus ĂŒber ein objekt fahre”.
aber wie ist das da gelöst? Gibt es dazu code? (ich suche mal, aber vielleicht weiss es ja jemand) Im prinzip mĂŒsste ich ja sowas wie einen ObjectOverObject Listener schreiben


Wenn deine Map in Blocks aufgeteilt wÀre ginge es relativ einfach
if(block.hasSign() blabla

Aber da du da wahrscheinlich auch selbst drauf gekommen wÀrst denke ich dass du keine Blockstruktur hast.
Ich wĂŒrde es wahrscheinlich auch mit Rectangles oder mit Points machen.
Wobei das bei einer sehr großen Map mit (ĂŒbertieben) 5000 Schildern wahrscheinlich schon spĂŒrbar wĂ€re.
Dann mĂŒsste man vlt. immer nur einen Teil der Map laden und nur das berechnen, aber frag mich nicht wie du das machen sollst, nur so ein Gedanke. Bei nur 50 Schildern wĂ€re da wahrscheinlich auch der Aufwand zu groß.

Auch bei einem MouseListener lĂ€uft es auf eine einzelne ÜberprĂŒfung hinaus. SinngemĂ€ĂŸ (!) endet das auch bei sowas wie
for (Component c : allComponents) if (c.contains(mousePosition)) sendEventsToListeners();

Aber wirklich nur sinngemĂ€ĂŸ: Praktischerweise ist die Struktur eines GUIs genau das, was man im allgemeinen Fall als Beschleunigungsstrukur fĂŒr genau solche Abfragen einsetzt - nĂ€mlich eine Baum-Datenstruktur. Bei sowas wie

rootPanel.add(childPanel0);
rootPanel.add(childPanel1);

childPanel0.add(grandChildPanel00);
childPanel0.add(grandChildPanel01);

childPanel1.add(grandChildPanel10);
childPanel1.add(grandChildPanel11);

mĂŒssen am Ende ja nicht alle 4 grandChildPanels ĂŒberprĂŒft werden: Erst wird ĂŒberprĂŒft, ob die Maus im childPanel0 oder childPanel1 ist, und danach mĂŒssen ja nur noch dessen grandChildPanels ĂŒberprĂŒft werden.

Wenn man wirklich “viele” Punkte ĂŒberprĂŒfen muss, lohnt sich das, weil die ÜberprĂŒfung von n Punkten mit einer einfachen Schleife eben Laufzeit O(n) hat, aber wenn man dafĂŒr einmal so einen Baum berechnet, hat eine Abfrage nur noch Laufzeit O(logn).

FĂŒr diese BĂ€ume gibt es verschiedenste AusprĂ€gungen fĂŒr verschiedene FĂ€lle. Sowas wie http://en.wikipedia.org/wiki/Quadtree sollte recht leicht zu implementieren sein und grundsĂ€tzlich auf deinen Anwendungsfall passsen. (Zum GlĂŒck muss der ja nicht (oder selten) aktualisiert werden, weil die Schilder sich wohl nicht sooo oft Ă€ndern).

Aber
 selbst bei 50 oder auch 100 Schildern wĂŒrde ich mir da noch nicht sooo viele Gedanken machen. Eine Abfrage wie
for (Sign s : signs) if (s.contains(point)) tuWas();
dauert nur wenige Mikrosekunden. Selbst bei 1000 Schildern wĂŒrde ich noch vermuten, dass es zeitkritischere Dinge gibt. Aber im Idealfall kann man das ja ganz gut wegabstrahieren. Mit zwei Methoden


void addSign(Sign s) { ... }
Sign findSignAt(Point p) { ... }

hat man die nötige FunktionalitĂ€t soweit ich das sehe schon gekapselt. In der ersten Version werden die Schilder einfach mit einer Liste und einer for-Schleife behandelt. Falls es irgendwann mal um 10000 Schilder geht, und zu viel zeit frißt, kann man das ganze durch geeignete Implementierung dieser beiden Methoden auf einen Octree umstellen: Bei addSign wird das Schild in den Octree eingepflegt, und bei findSignAt wird der Octree traversiert.

Ich kenne mich jetzt nicht mit Spieleentwicklung aus, aber statt die Koordinaten immer zu einem festen Zeitpunkt zu schicken ( = jedem Gameloop-Durchlauf) wĂŒrde ich das mit einem Observer-Muster machen, wenn also die Berechnungen nur durchgefĂŒhrt werden, wenn sich der Spieler wirklich bewegt. Kann man natĂŒrlich auch mit dem Merken und Vergleichen von aktuellen und letzten Koordinaten machen.

Die Logik, was das Schild anzeigen soll, wĂŒrde ich dann vielleicht an das Rechteck binden. Folgender Pseudocode soll das mal darstellen:

Folgender Code sollte im Spielweltmanager oder Àhnlichem liegen.

public void update(final PlayerInfo info) {
   Box currentBox = BoxManager.getBoxByCoordinates(info.getCoordinates());
   currentBox.calculateSign(info);
}

Folgender Code liegt dann beispielsweise in einer Box:

public void calculateSign(final PlayerInfo info) {
   if (info.getCharLevel() < 50) {
      this.getSign().setText("Sorry, Level zu niedrig");
   }
}

Observee wĂ€re der Spieler, Observer wĂ€re die Spielwelt. Die Boxen sollten natĂŒrlich dann eine Vererbungshierarchie haben und das Literal im calculateSign() sollte natĂŒrlich irgendwo als Konstante hinterlegt werden :slight_smile: