Come posso verificare se una linea disegnata dal giocatore segue un percorso?


8

Voglio disegnare un percorso invisibile che l'utente deve seguire. Ho memorizzato quel percorso come punti. Quando un giocatore disegna una linea, come posso verificare se segue il percorso che ho memorizzato?

Ecco un esempio per tracciare la lettera A.

traccia di esempio

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

( traitSpriteè uno sprite.)


Come stai memorizzando il percorso che la linea disegnata del giocatore dovrebbe seguire? È questo lo sprite?
Anko,

no, sono punti che ho inserito manualmente. è una cattiva idea, ma penso che l'uso di "Vector2" sarà una soluzione efficace ma non so davvero come usarlo.
Android

Risposte:


12

Ecco una soluzione basata su vettori. Non l'ho provato, ma concettualmente sembra bene.

Teoria

Ho capito che hai memorizzato la forma come segmenti di linea. Ecco la lettera A rappresentata con tre segmenti di linea.

segmenti di linea che rappresentano una lettera

Ho assunto che i percorsi nel disegno dell'utente siano memorizzati come elenchi di punti.

Possiamo "gonfiare" quei segmenti di linea per consentire un margine di errore quando si verifica la vicinanza : se il percorso disegnato dall'utente è vicino al margine di errore di linee corretto.

segmenti di linea "gonfiati" percorso disegnato dall'utente in cima alla lettera con margini di errore

Tuttavia, questo da solo non è abbastanza. Dobbiamo anche verificare la copertura : se il disegno dell'utente "copre" gran parte della forma. Questi disegni sono sbagliati, perché anche se rientrano nel margine di errore, mancano alcune parti della lettera:

cattivi disegni

Se controlliamo entrambe queste cose, possiamo approssimare se il disegno del giocatore è buono.

Implementazione

Controllare la vicinanza significa solo per ogni punto del percorso dell'utente, trovare la distanza tra quella e ogni linea che compone la lettera, prendere il minimo e verificare che sia inferiore al margine di errore.

Il controllo della copertura è più complicato, ma puoi ottenere un'approssimazione molto buona con la matematica vettoriale se per ogni segmento di linea, trovi il percorso disegnato dall'utente più vicino (verde) e proietti le sue parti (verde scuro) su quel segmento di linea (nero), quindi controlla quanto bene coprono i vettori proiettati (blu):

controllo di copertura mediante proiezione vettoriale

Per proiettare un vettore asu un altro vettore b, fare

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

dove dotProductcalcola il prodotto punto dei due vettori ed lengthSquaredè quello che sembra. In sostanza, questo trova il valore scalare di quanto ava nella bdirezione e si moltiplica bper quello per ottenere un vettore nella stessa direzione. (Il tutorial A sul rilevamento delle collisioni del software Metanet ha una buona visualizzazione di questo nell'Appendice A § proiezione .)

La direzione del vettore proiettato potrebbe in realtà non essere importante. Se sommi semplicemente le lunghezze dei vettori proiettati e le confronti con la lunghezza totale del segmento di linea, ciò ti dirà quale frazione di esso è coperta. (Tranne in casi dispari, vedere § Limitazioni di seguito).

Nell'immagine sopra, il percorso coprirebbe circa la metà del segmento. È possibile selezionare qualsiasi valore di tolleranza desiderato.

limitazioni

Lettere curve

I segmenti di linea non sono ideali: molte lettere sono curve! Come si rappresenta una 'P' o una 'O'?

È possibile utilizzare molti segmenti di linea (magari con un margine di errore maggiore).

lettera P approssimata con segmenti di linea lettera O approssimata con segmenti di linea

È inoltre potrebbe iniziare a usare le curve di Bézier , invece di linee per una calzata più stretta, ma nota che trovare il punto più vicino su un Bézier è molto più complessa, come molte altre operazioni di misurazione.

disallineamenti

I margini di tolleranza troppo rilassati per la distanza dalle linee e la copertura della lettera potrebbero avere conseguenze indesiderate.

Ad esempio, il giocatore potrebbe aver provato a disegnare una "H" qui.

una lettera H erroneamente riconosciuta come A

Anelli e sovrapposizioni

loop e sovrapposizione in (possibilmente) lettera riconosciuta

I loop o le sovrapposizioni nel percorso disegnato dal giocatore potrebbero comportare il conteggio di alcune parti del disegno due volte quando vengono proiettate sul segmento di linea più vicino.

Questo potrebbe essere aggirato eseguendo elaborazioni più elaborate sui vettori proiettati, magari memorizzando esattamente dove sarebbe il vettore proiettato (memorizzare anche la direzione della proiezione e il punto più vicino sul segmento di linea al punto sulla linea disegnata dal giocatore) , quindi rifiutando quelli nuovi che si sovrappongono.

Se il giocatore ha tracciato un singolo percorso ed è stato elaborato a partire dalla fine segnata con il cerchio blu, le parti verdi di quel percorso sarebbero accettate e quelle rosse rifiutate, perché la loro proiezione si sovrapponerebbe con alcune parti elaborate prima.

rifiuto di loop e sovrapposizioni

L'implementazione ha molte sottigliezze tecniche che probabilmente rientrerebbero in una domanda diversa.

Giocatori imprevedibilmente avventurosi

Un giocatore potrebbe pescare qualcosa di strano che ancora passa .

trolololol

Anche se potresti chiamarlo una caratteristica! :)


grazie, cosa proponi di non trarre fuori dalla lettera?
Android

@Android I "margini di errore" arancioni sono per questo. Si potrebbe rifiutare linee che vanno al di fuori di loro: in questo modo , per esempio.
Anko,

Quello che voglio è fare la lettera come SpriteBatch, quindi l'unica area in cui posso disegnare è quel batch di sprite, che può assumere la forma di A o B, X .... è possibile? se è come posso creare una trama come uno SpriteBatch? E grazie in anticipo.
Android

2

tl; dr Suggerisco di far dipingere il pennello dei giocatori su un piano 2D (visibile o invisibile). Diffondi l'immagine dipinta dagli utenti con l'origine (la sagoma desiderata o il modello 2d). Se si desidera aumentare la precisione, rendere le linee guida e il pennello più stretti, per lasciare più spazio agli errori, rendere il pennello e il design più spessi.

Altrimenti, è possibile misurare la distanza di ogni (x, y) su cui gli utenti fanno clic / toccano dalla spline calcolando la distanza tra punto e segmento. Quindi è possibile calcolare la media delle distanze per comporre una misura di precisione ed efficienza. Richiederà più lavoro per ottenere una misura significativa del completamento e rendersi conto dell'efficacia eseguita dall'utente.


Considerazione: suggerisco di non farlo (controllando direttamente se una linea segue un percorso). Questa è probabilmente una cattiva idea. Sembra che tu voglia che l'utente riempia una silhouette. Il percorso stesso è una spline (scheletrica) che rappresenta la silhouette.

Se fai semplicemente in modo che il pennello dei giocatori applichi una massa poligonale monocromatica di pixel sul piano 2d, puoi eseguire un processo in background che controlla quanti pixel sono all'interno della silhouette e quanti di essi sono all'esterno. Ciò può facilmente comportare una percentuale di successo, in cui la percentuale del pattern riempita è una statistica di interesse e un'altra è la percentuale che si trova al di fuori dei confini del modello. Se si controllano le distanze dei sotto-segmenti, non è molto preciso il lavoro degli utenti.


1

La migliore soluzione non usa affatto la grafica, fallo con la matematica!

Puoi facilmente capire quanto ogni punto (dipinto dall'utente) è lontano dal segmento /programming/849211/shortest-distance-b Between-a- point-and-a- line- segment

Che puoi calcolare l'errore medio, quindi misura la quantità di utenti corretta.


grazie, ma per lettere come "C" "O"? ... non c'è una distanza fissa tra i punti ..
Android

Puoi fare "C" e "O" da 6-8 segmenti di linea, proprio come gli altri, ma la matematica sarà leggermente diversa, in termini di misurazione dell'errore
Alexsey Shestacov
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.