Kurze Version
Gibt es ein Entwurfsmuster für die Verteilung von Fahrzeugetiketten in nicht überlappender Weise, um sie so nah wie möglich an dem Fahrzeug zu platzieren, auf das sie sich beziehen? Wenn nicht, ist eine der von mir vorgeschlagenen Methoden praktikabel? Wie würden Sie das selbst umsetzen?
Erweiterte Version
In dem Spiel, das ich schreibe, habe ich eine Vogelperspektive meiner Luftfahrzeuge. Ich habe auch neben jedem der Fahrzeuge ein kleines Etikett mit Schlüsseldaten über das Fahrzeug. Dies ist ein Screenshot:
Da die Fahrzeuge nun in unterschiedlichen Höhen fliegen könnten, könnten sich ihre Symbole überlappen. Ich möchte jedoch nicht, dass sich die Beschriftungen überschneiden (oder dass sich die Beschriftungen von Fahrzeug 'A' mit dem Symbol von Fahrzeug 'B' überschneiden).
Gegenwärtig kann ich Kollisionen zwischen Sprites erkennen und schiebe das anstößige Etikett einfach entgegen der Richtung des ansonsten überlappenden Sprites weg . Dies funktioniert in den meisten Situationen, aber wenn der Luftraum überfüllt ist, kann das Etikett sehr weit vom Fahrzeug weggeschoben werden, selbst wenn es eine alternative "intelligentere" Alternative gibt. Zum Beispiel bekomme ich:
B - label
A -----------label
C - label
Wo wäre es besser (= Etikett näher am Fahrzeug) zu bekommen:
B - label
label - A
C - label
EDIT: Es muss auch berücksichtigt werden, dass es neben dem Fall überlappender Fahrzeuge auch andere Konfigurationen geben kann, in denen sich die Fahrzeugkennzeichnungen überlappen können (die ASCII-Kunstbeispiele zeigen zum Beispiel drei sehr nahe Fahrzeuge, in denen das Etikett von A
das Symbol von überlappen würde B
und C
).
Ich habe zwei Ideen, wie ich die gegenwärtige Situation verbessern kann, aber bevor ich Zeit damit verbringe, sie umzusetzen, habe ich mir überlegt, mich an die Community zu wenden, um Rat zu holen (schließlich scheint es ein "häufig genug auftretendes Problem" zu sein, dass ein Entwurfsmuster dafür existieren könnte).
Für das, was es wert ist, sind hier die zwei Ideen, an die ich gedacht habe:
Slot-isierung des Label-Space
In diesem Szenario würde ich den gesamten Bildschirm in "Slots" für die Etiketten unterteilen. In diesem Fall wird für jedes Fahrzeug immer das Etikett in das nächstgelegene Leerzeichen gesetzt (leer = keine anderen Sprites an dieser Stelle).
Spiralige Suche
Ab der Position des Fahrzeugs auf dem Bildschirm würde ich versuchen, das Etikett in zunehmenden Winkeln und dann in zunehmenden Radien zu platzieren, bis eine nicht überlappende Position gefunden wird. Etwas auf der ganzen Linie von:
try 0°, 10px
try 10°, 10px
try 20°, 10px
...
try 350°, 10px
try 0°, 20px
try 10°, 20px
...
Antworten:
Im Wesentlichen ähnelt dieses Problem einem Problem der Kollisionsvermeidung. Ja, die Flugzeuge können in verschiedenen Höhen fliegen, aber ihre Beschriftungen befinden sich alle auf derselben "Höhe".
Es gibt Algorithmen wie Unaligned Collision Avoidance , die für Sie einen Schritt in die richtige Richtung darstellen. Natürlich sind die Etiketten für Ihre Situation an ihre Ebenen "angebunden", so dass sie einen begrenzten Bewegungsbereich haben.
Wenn Sie sich das Beflockungsverhalten ansehen , möchten Sie die erste "Regel" der Beflockung implementieren: Abstoßung über kurze Entfernungen. Anstatt jedoch in die von den nächsten Nachbarn entfernte Richtung zu "steuern", verwenden Sie den Vektor "away" als Platzierungsort für Ihr Etikett.
Beispielsweise:
Der große schwarze Kreis stellt Ihren Einflussbereich dar, der grüne Kreis stellt die gültigen Platzierungen für das Etikett dar, der mittlere grüne Punkt ist die Ebene, die Sie gerade betrachten, und der kleine grüne Punkt ist der Punkt auf dem Kreis, der für die Platzierung des Etiketts ausgewählt wurde.
Jetzt könnten die schwarzen Punkte entweder andere Bezeichnungen oder andere Ebenen darstellen. Ich bin mir nicht sicher, welches am besten funktioniert. Wenn es sich um andere Labels handelt, kann man das besser vermeiden, aber ich bin mir nicht sicher. Offensichtlich sind die "Kraft" -Pfeile die Richtungsvektoren zwischen Ihrer aktuellen Ebene und den "Einflussobjekten". Schließlich ist die Box das Etikett.
Wenn Sie also Ihr Beispiel oben verwenden, würde dies ungefähr so aussehen:
Wenn Sie diese Methode verwenden, müssen Sie einige Sonderfälle erstellen, z. B. drei Ebenen, die vertikal ausgerichtet sind:
Alle drei Beschriftungen können von rechts nach links umkehren, je nachdem, wie Ihre Beschriftungsecken definiert sind. Grundsätzlich müssen Sie nur auf die Winkel um den Kreis achten, in denen Ihre Beschriftungen umschalten können, von welcher Ecke sie gezeichnet werden: 0, 90, 180, 270.
Ich denke am Ende würde das irgendwie ordentlich aussehen, wenn man beobachtet, wie sich die Labels ausweichen. Wenn es zu ablenkend wird, können Sie möglicherweise für weniger häufige Bewegungen auf die nächsten 10 Grad runden.
Tut mir leid für die seltsamen Details, die meisten Dinge, über die ich nachgedacht habe, als ich ein Radialmenü für mein Spiel erstellt habe, aber ich denke, in dieser "dynamischen" Form würde es ziemlich gut funktionieren.
quelle
Nach einigem Überlegen entschied ich mich schließlich für die Implementierung der spiralförmigen Suchmethode , die ich in der ursprünglichen Frage kurz beschrieben hatte.
Der Grund dafür ist, dass die Methode des Byte56 für bestimmte Bedingungen eine spezielle Behandlung benötigt, während die spiralförmige Suche dies nicht tut, und dass sie sehr kompakt codiert . Auch bei der Spriralling-Suche wird der Schwerpunkt darauf gelegt , den nächstgelegenen Ort zum Fahrzeug zu finden, um das Etikett anzubringen. Dies ist IMO der Hauptfaktor, um die Karte lesbar zu machen.
Bitte stimmen Sie seiner Antwort jedoch weiterhin zu, da sie nicht nur nützlich, sondern auch sehr gut geschrieben ist!
Hier ist ein Screenshot des Ergebnisses, das mit dem Spiralcode erzielt wurde:
Und hier ist der Code, der - obwohl nicht in sich geschlossen - eine Vorstellung davon gibt, wie einfach die Implementierung ist:
Hinweis 1 -
tag.place()
Gibt True zurück, wenn sich das Tag vollständig im sichtbaren Bereich des Bildschirms / Radars befindet. Diese Zeile lautet also: "Schleife weiter, wenn sich das Tag außerhalb des Radars befindet oder etwas anderes überlappt ..."Anmerkung 2 -
tag.connector.update
ist die Methode, mit der die Linie zwischen dem Flugzeugsymbol und dem Etikett mit den Textinformationen gezogen wird.quelle