Ich möchte einen unsichtbaren Pfad zeichnen, dem der Benutzer folgen muss. Ich habe diesen Pfad als Punkte gespeichert. Wie kann ich testen, ob ein Spieler dem gespeicherten Pfad folgt, wenn er eine Linie zieht?
Hier ist ein Beispiel für die Verfolgung des Buchstabens A.
if((traitSprite.getX()<=Invisible.X && traitSprite.getX()>=Invisible.X )){...}
( traitSprite
ist ein Sprite.)
libgdx
algorithm
vector
hand-drawn
Android
quelle
quelle
Antworten:
Hier ist eine vektorbasierte Lösung. Ich habe es nicht ausprobiert, aber konzeptionell scheint es in Ordnung zu sein.
Theorie
Ich nehme an, Sie haben die Form als Liniensegmente gespeichert. Hier ist der Buchstabe A mit drei Liniensegmenten dargestellt.
Ich habe angenommen, dass Pfade in der Zeichnung des Benutzers als Punktelisten gespeichert sind.
Wir können diese Liniensegmente "aufblasen", um einen Fehlerbereich bei der Überprüfung der Nähe zu ermöglichen : ob der vom Benutzer gezeichnete Pfad in der Nähe des korrekten Zeilenfehlerbereichs liegt.
Das allein reicht jedoch nicht aus. Wir müssen auch auf Abdeckung prüfen : ob die Zeichnung des Benutzers einen großen Teil der Form "bedeckt". Diese Zeichnungen sind schlecht, denn obwohl sie in die Fehlergrenze passen, fehlt ihnen ein Teil des Buchstabens:
Wenn wir beide Dinge überprüfen, können wir annähern, ob die Zeichnung des Spielers gut ist.
Implementierung
Das Überprüfen der Nähe bedeutet nur für jeden Benutzerpfadpunkt, den Abstand zwischen diesem und jeder Linie, aus der der Buchstabe besteht, zu ermitteln, den niedrigsten zu nehmen und zu überprüfen, ob er unter der Fehlergrenze liegt.
Das Überprüfen der Abdeckung ist komplizierter, aber Sie können mit der Vektormathematik eine sehr gute Annäherung erhalten, wenn Sie für jedes Liniensegment den nächsten vom Benutzer gezeichneten Pfad (grün) finden und seine Teile (dunkelgrün) auf dieses Liniensegment (schwarz) projizieren. Überprüfen Sie dann, wie gut die projizierten Vektoren (blau) sie abdecken:
Um einen Vektor
a
auf einen anderen Vektor zu projizierenb
, gehen Sie wie folgt vorDabei wird
dotProduct
das Punktprodukt der beiden Vektoren berechnet undlengthSquared
wie es sich anhört. Dies ermittelt im Wesentlichen den Skalarwert, wie viela
inb
die Richtung geht , und multipliziert damit den Wertb
, um einen Vektor in die gleiche Richtung zu erhalten. (Das Tutorial A zur Kollisionserkennung von Metanet Software zeigt dies in Anhang A § Projektion .)Die Richtung des projizierten Vektors ist möglicherweise nicht wirklich wichtig. Wenn Sie nur die Längen der projizierten Vektoren addieren und sie mit der Gesamtlänge des Liniensegments vergleichen, erfahren Sie, welcher Teil davon abgedeckt ist. (Außer in ungeraden Fällen - siehe § Einschränkungen unten).
Im obigen Bild würde der Pfad etwa die Hälfte des Segments abdecken. Sie können einen beliebigen Toleranzwert auswählen.
Einschränkungen
Gebogene Buchstaben
Liniensegmente sind nicht ideal: Viele Buchstaben sind gekrümmt! Wie repräsentieren Sie ein 'P' oder ein 'O'?
Sie könnten viele Liniensegmente verwenden (möglicherweise mit einer größeren Fehlergrenze).
Sie könnten auch könnten mit starten Bézier - Kurven für eine engere Passform anstelle von Linien, aber beachten Sie, dass auf einem Bézier den nächsten Punkt zu finden , ist viel komplexer-wie viele andere Messvorgänge sind.
Nichtübereinstimmungen
Zu lockere Toleranzgrenzen für den Abstand zu den Linien und die Abdeckung des Briefes können unbeabsichtigte Folgen haben.
Zum Beispiel könnte der Spieler versucht haben, hier ein 'H' zu zeichnen.
Schleifen und Überlappungen
Schleifen oder Überlappungen im vom Spieler gezeichneten Pfad können dazu führen, dass einige Teile der Zeichnung zweimal gezählt werden, wenn sie auf das nächste Liniensegment projiziert werden.
Dies könnte umgangen werden, indem die projizierten Vektoren ausgefallener verarbeitet werden und möglicherweise genau dort gespeichert werden, wo sich der projizierte Vektor befinden würde (speichern Sie auch die Richtung der Projektion und den Punkt auf dem Liniensegment, der dem Punkt auf der vom Spieler gezeichneten Linie am nächsten liegt). und dann neue ablehnen, die sich überlappen.
Wenn der Spieler einen einzelnen Pfad gezeichnet hat und dieser ab dem mit dem blauen Kreis markierten Ende verarbeitet wurde, werden die grünen Teile dieses Pfades akzeptiert und die roten abgelehnt, da sich ihre Projektion mit einigen zuvor verarbeiteten Teilen überschneidet.
Die Implementierung hat viele technische Feinheiten, die wahrscheinlich in eine andere Frage gehören würden.
Unvorhersehbar abenteuerlustige Spieler
Ein Spieler könnte etwas Seltsames zeichnen, das immer noch passt .
Obwohl man das eine Funktion nennen könnte! :) :)
quelle
Ich schlage vor, die Pinselfarbe der Spieler zu einer sichtbaren (oder unsichtbaren) 2D-Ebene zu machen. Diff das gemalte Bild des Benutzers mit dem Ursprung (der gewünschten Silhouette oder dem 2D-Modell). Wenn Sie die Genauigkeit erhöhen möchten, machen Sie die Führungslinien und den Pinsel schmaler, um mehr Fehler zu vermeiden, machen Sie Pinsel und Design dicker.
Andernfalls können Sie den Abstand jedes (x, y) messen, auf den der Benutzer vom Spline aus klickt / berührt, indem Sie den Abstand von Punkt zu Segment berechnen. Anschließend können Sie die Entfernungen mitteln, um ein Maß für Genauigkeit und Effizienz zu erhalten. Es wird mehr Arbeit erfordern, um ein aussagekräftiges Maß für die Fertigstellung zu erhalten und zu erkennen, wie effektiv der Benutzer gearbeitet hat.
Überlegung: Ich schlage vor, dies nicht zu tun (direkt prüfen, ob eine Linie einem Pfad folgt). Dies ist möglicherweise eine schlechte Idee. Anscheinend möchten Sie, dass der Benutzer eine Silhouette ausfüllt. Der Pfad selbst ist ein (Skelett-) Spline, der die Silhouette darstellt.
Wenn Sie einfach den Pinsel des Spielers dazu bringen, eine breiige monochrome Pixelmasse auf die 2D-Ebene aufzutragen, können Sie im Hintergrund einen Prozess ausführen, der überprüft, wie viele Pixel sich innerhalb der Silhouette befinden und wie viele sich außerhalb befinden. Dies kann leicht zu% des Erfolgs führen, wobei wie viel% des Musters gefüllt sind, eine Statistik von Interesse ist und eine andere, wie viel% außerhalb der Grenzen des Modells liegt. Wenn Sie nach Abständen zwischen den Segmenten suchen, ist die Arbeit der Benutzer nicht sehr genau.
quelle
Die beste Lösung, überhaupt keine Grafiken zu verwenden, machen Sie es mit Mathe!
Sie können leicht verstehen, wie viel jeder Punkt (vom Benutzer gemalt) weit vom Segment /programming/849211/shortest-distance-between-a-point-and-a-line-segment entfernt ist
Damit Sie den durchschnittlichen Fehler berechnen können, messen Sie, wie viel Benutzer korrekt ist.
quelle