Comment puis-je vérifier si une ligne dessinée par un joueur suit un chemin?

8

Je veux dessiner un chemin invisible que l'utilisateur doit suivre. J'ai enregistré ce chemin sous forme de points. Lorsqu'un joueur trace une ligne, comment puis-je tester si elle suit le chemin que j'ai enregistré?

Voici un exemple de traçage de la lettre A.

exemple de trace

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

( traitSpriteest un sprite.)

Android
la source
Comment stockez-vous le chemin que la ligne dessinée du joueur doit suivre? C'est ça le sprite?
Anko
non, sont des points que j'ai entrés manuellement. c'est une mauvaise idée, mais je pense que l'utilisation de "Vector2" sera une solution efficace mais je ne sais pas vraiment comment l'utiliser.
Android

Réponses:

12

Voici une solution vectorielle. Je ne l'ai pas essayé, mais cela semble bien conceptuellement.

Théorie

Je suppose que vous avez stocké la forme sous forme de segments de ligne. Voici la lettre A représentée par trois segments de ligne.

segments de ligne représentant une lettre

J'ai supposé que les chemins dans le dessin de l'utilisateur sont stockés sous forme de listes de points.

Nous pouvons «gonfler» ces segments de ligne pour permettre une marge d'erreur lors de la vérification de la proximité : si le chemin tracé par l'utilisateur est proche de la marge d'erreur de lignes correcte.

segments de ligne "gonflés" chemin tracé par l'utilisateur en haut de la lettre avec des marges d'erreur

Mais cela ne suffit pas. Nous devons également vérifier la couverture : si le dessin de l'utilisateur "recouvre" une grande partie de la forme. Ces dessins sont mauvais, car même s'ils s'inscrivent dans la marge d'erreur, il leur manque une partie de la lettre:

mauvais dessins

Si nous vérifions ces deux choses, nous pouvons approximer si le dessin du joueur est bon.

la mise en oeuvre

Vérifier la proximité signifie simplement pour chaque point de chemin utilisateur, trouver la distance entre cela et chaque ligne constituant la lettre, prendre le plus bas et vérifier qu'elle est inférieure à la marge d'erreur.

La vérification de la couverture est plus compliquée, mais vous pouvez obtenir une très bonne approximation avec les mathématiques vectorielles si pour chaque segment de ligne, vous trouvez le chemin dessiné par l'utilisateur le plus proche (vert) et projetez ses parties (vert foncé) sur ce segment de ligne (noir), puis vérifiez si les vecteurs projetés (en bleu) le couvrent:

contrôle de couverture par projection vectorielle

Pour projeter un vecteur asur un autre vecteur b, faites

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

dotProductcalcule le produit scalaire des deux vecteurs et lengthSquaredcorrespond à ce à quoi il ressemble. Essentiellement, cela trouve la valeur scalaire de combien ava dans bla direction de et multiplie bpar celle-ci pour obtenir un vecteur dans la même direction. (Le didacticiel A sur la détection des collisions de Metanet Software en offre une belle visualisation dans l' annexe A § projection .)

La direction du vecteur projeté peut ne pas être réellement importante. Si vous additionnez simplement les longueurs des vecteurs projetés et les comparez à la longueur totale du segment de ligne, cela vous indiquera quelle fraction est couverte. (Sauf dans les cas étranges - voir § Limitations ci-dessous).

Dans l'image ci-dessus, le chemin couvrirait environ la moitié du segment. Vous pouvez choisir n'importe quelle valeur de tolérance que vous souhaitez.

Limites

Lettres courbes

Les segments de ligne ne sont pas idéaux: de nombreuses lettres sont courbes! Comment représentez-vous un «P» ou un «O»?

Vous pouvez utiliser de nombreux segments de ligne (peut-être avec une marge d'erreur plus importante).

lettre P approximée avec des segments de ligne lettre O rapprochée avec des segments de ligne

Vous aussi pouvez commencer à utiliser des courbes de Bézier au lieu de lignes pour un plus en forme, mais notez que trouver le point le plus proche sur un Bézier est beaucoup plus que complexe plus a beaucoup d' autres opérations de mesure.

Inadéquations

Des marges de tolérance trop détendues pour la distance des lignes et la couverture de la lettre pourraient avoir des conséquences inattendues.

Par exemple, le joueur a peut-être essayé de dessiner un «H» ici.

une lettre H reconnue à tort comme A

Boucles et chevauchements

boucle et chevauchement dans une lettre (éventuellement) reconnue

Les boucles ou les chevauchements dans le chemin tracé par le joueur peuvent entraîner le comptage double de certaines parties du dessin lors de leur projection sur le segment de ligne le plus proche.

Cela pourrait être contourné en effectuant un traitement plus sophistiqué sur les vecteurs projetés, peut-être en stockant exactement où le vecteur projeté serait (stockez également la direction de la projection et le point le plus proche sur le segment de ligne au point sur la ligne dessinée par le joueur) , puis en rejeter de nouveaux qui le chevauchent.

Si le joueur dessinait un seul chemin et que celui-ci était traité en commençant à la fin marquée par le cercle bleu, les parties vertes de ce chemin seraient acceptées et les rouges rejetées, car leur projection chevaucherait certaines parties traitées auparavant.

rejet des boucles et des chevauchements

L'implémentation a de nombreuses subtilités techniques qui appartiendraient probablement à une question différente.

Joueurs imprévisiblement aventureux

Un joueur peut dessiner quelque chose de bizarre qui passe toujours .

trolololol

Bien que vous puissiez appeler cela une fonctionnalité! :)

Anko
la source
merci, que proposez-vous de ne pas tirer en dehors de la lettre?
Android
@Android Les "marges d'erreur" orange sont pour cela. Vous pouvez rejeter les lignes qui les dépassent: comme ceci par exemple.
Anko
Ce que je veux, c'est faire la lettre en tant que SpriteBatch, alors la seule zone où je peux dessiner est ce lot de sprites, qui peut prendre la forme de A ou B, X .... est-ce possible? si c'est le cas, comment puis-je faire une texture comme un SpriteBatch? et merci d'avance.
Android
2

tl; dr Je suggère de faire de la peinture au pinceau des joueurs un plan 2D visible (ou invisible). Différez l'image peinte des utilisateurs avec l'origine (la silhouette souhaitée ou le modèle 2D). Si vous souhaitez augmenter la précision, rendez les lignes de guidage et la brosse plus étroites, pour laisser plus de place à l'erreur, rendez la brosse et le design plus épais.

Sinon, vous pouvez mesurer la distance de chacun (x, y) sur lequel les utilisateurs cliquent / touchent depuis la spline en calculant la distance point à segment. Ensuite, vous pouvez faire la moyenne des distances pour composer une mesure de précision et d'efficacité. Il faudra plus de travail pour obtenir une mesure significative de l'achèvement et réaliser l'efficacité de l'utilisateur.


Considération: je suggère de ne pas le faire (vérifier directement si une ligne suit un chemin). C'est peut-être une mauvaise idée. Il semble que vous souhaitiez que l'utilisateur remplisse une silhouette. Le chemin lui-même est une spline (squelettique) représentant la silhouette.

Si vous faites simplement appliquer au pinceau des joueurs une masse pulpeuse de pixels monochromes sur le plan 2D, vous pouvez exécuter un processus en arrière-plan qui vérifie combien de pixels se trouvent à l'intérieur de la silhouette et combien d'entre eux sont à l'extérieur. Cela peut facilement entraîner un% de réussite, où% du motif est rempli est une statistique intéressante et une autre est combien% est en dehors des frontières du modèle. Si vous vérifiez les distances des sous-segments, il n'est pas très clair de la précision du travail des utilisateurs.

AturSams
la source
1

La meilleure solution n'est pas du tout d'utiliser des graphiques, faites-le avec les mathématiques!

Vous pouvez facilement comprendre combien chaque point (peint par l'utilisateur) est éloigné du segment /programming/849211/shortest-distance-between-a-point-and-a-line-segment

Que vous pouvez calculer l'erreur moyenne, alors mesurez combien d'utilisateurs sont corrects.

Alexsey Shestacov
la source
merci, mais pour les lettres comme "C" "O"? ... il n'y a pas de distance fixe entre les points ..
Android
Vous pouvez faire "C" et "O" à partir de segments de 6-8 lignes, tout comme les autres, mais les mathématiques seront légèrement différentes, en termes de mesure d'erreur
Alexsey Shestacov