Wie kann ich überprüfen, ob eine vom Spieler gezogene Linie einem Pfad folgt?

8

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.

Beispielverfolgung

if((traitSprite.getX()<=Invisible.X  && traitSprite.getX()>=Invisible.X )){...}

( traitSpriteist ein Sprite.)

Android
quelle
Wie speichern Sie den Pfad, dem die gezeichnete Linie des Spielers folgen soll? Ist das das Sprite?
Anko
Nein, sind Punkte, die ich manuell eingegeben habe. Es ist eine schlechte Idee, aber ich denke, die Verwendung von "Vector2" wird eine effektive Lösung sein, aber ich weiß nicht wirklich, wie ich es verwenden soll.
Android

Antworten:

12

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.

Liniensegmente, die einen Buchstaben darstellen

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.

"aufgeblasene" Liniensegmente Vom Benutzer gezeichneter Pfad über dem Buchstaben mit Fehlerrändern

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:

schlechte Zeichnungen

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:

Coverage-Check durch Vektorprojektion

Um einen Vektor aauf einen anderen Vektor zu projizieren b, gehen Sie wie folgt vor

projection = dotProduct(a, b) / lengthSquared(b) * b

Dabei wird dotProductdas Punktprodukt der beiden Vektoren berechnet und lengthSquaredwie es sich anhört. Dies ermittelt im Wesentlichen den Skalarwert, wie viel ain bdie 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).

Buchstabe P mit Liniensegmenten angenähert Buchstabe O mit Liniensegmenten angenähert

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.

ein Buchstabe H, der fälschlicherweise als A erkannt wurde

Schleifen und Überlappungen

Schleife und Überlappung in (möglicherweise) erkanntem Buchstaben

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.

Schleifen und Überlappungen ablehnen

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 .

Trolololol

Obwohl man das eine Funktion nennen könnte! :) :)

Anko
quelle
Danke, was schlagen Sie vor, um nicht außerhalb des Briefes zu zeichnen?
Android
@Android Die orangefarbenen "Fehlerränder" sind dafür. Sie könnten Linien ablehnen , die außerhalb ihnen gehen: wie dies zum Beispiel.
Anko
Ich möchte den Buchstaben als SpriteBatch erstellen. Der einzige Bereich, in dem ich zeichnen kann, ist der Sprite-Stapel, der entweder die Form A oder B, X haben kann. Ist dies möglich? Wenn ja, wie kann ich eine Textur wie ein SpriteBatch erstellen? und danke im voraus.
Android
2

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.

AturSams
quelle
1

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.

Alexsey Shestacov
quelle
Danke, aber was ist mit Buchstaben wie "C" "O"? ... es gibt keinen festen Abstand zwischen Punkten ..
Android
Sie können "C" und "O" aus 6-8 Liniensegmenten machen, genau wie andere, aber die Mathematik wird in Bezug auf die Fehlermessung etwas anders sein
Alexsey Shestacov