Come posso disegnare una freccia sul bordo dello schermo che punta a un oggetto fuori dallo schermo?


12

Desidero fare ciò che è descritto in questo argomento:

http://www.allegro.cc/forums/print-thread/283220

Ho tentato una varietà di metodi citati qui.

Per prima cosa ho provato ad usare il metodo descritto da Carrus85:

Prendi semplicemente il rapporto tra i due triangoli ipoontusi (non importa quale triagle usi per l'altro, suggerisco il punto 1 e il punto 2 come distanza calcolata). Questo ti darà la percentuale di proporzioni del triangolo nell'angolo rispetto al triangolo più grande. Quindi moltiplica semplicemente il deltax per quel valore per ottenere l'offset delle coordinate xe deltay per quel valore per ottenere l'offset delle coordinate y.

Ma non sono riuscito a trovare un modo per calcolare la distanza dell'oggetto dal bordo dello schermo.

Ho quindi provato a utilizzare il ray casting (che non avevo mai fatto prima) suggerito da 23yrold3yrold:

Spara un raggio dal centro dello schermo sull'oggetto fuori schermo. Calcola dove sul rettangolo si interseca il raggio. Ecco le tue coordinate.

In primo luogo ho calcolato l'ipotenusa del triangolo formato dalla differenza nelle posizioni xey dei due punti. L'ho usato per creare un vettore unitario lungo quella linea. Ho passato in rassegna quel vettore fino a quando la coordinata x o la coordinata y erano fuori dallo schermo. I due valori xey attuali formano quindi la x e la y della freccia.

Ecco il codice per il mio metodo di casting ray (scritto in C ++ e Allegro 5)

void renderArrows(Object* i)
{
    float x1 = i->getX() + (i->getWidth() / 2);
    float y1 = i->getY() + (i->getHeight() / 2);

    float x2 = screenCentreX;
    float y2 = ScreenCentreY;

    float dx = x2 - x1;
    float dy = y2 - y1;
    float hypotSquared = (dx * dx) + (dy * dy);
    float hypot = sqrt(hypotSquared);

    float unitX = dx / hypot;
    float unitY = dy / hypot;

    float rayX = x2 - view->getViewportX();
    float rayY = y2 - view->getViewportY();
    float arrowX = 0;
    float arrowY = 0;

    bool posFound = false;
    while(posFound == false)
    {
        rayX += unitX;
        rayY += unitY;

        if(rayX <= 0 ||
            rayX >= screenWidth ||
            rayY <= 0 ||
            rayY >= screenHeight)
        {
            arrowX = rayX;
            arrowY = rayY;
            posFound = true;
        }               
    }

    al_draw_bitmap(sprite, arrowX - spriteWidth, arrowY - spriteHeight, 0);
}

Questo ha avuto relativamente successo. Le frecce vengono visualizzate nella sezione in basso a destra dello schermo quando gli oggetti si trovano sopra e a sinistra dello schermo come se le posizioni in cui sono disegnate le frecce fossero ruotate di 180 gradi attorno al centro dello schermo.

Supponevo che ciò fosse dovuto al fatto che quando stavo calcolando l'ipotenusa del triangolo, sarebbe sempre positivo indipendentemente dal fatto che la differenza in x o la differenza in y sia negativa.

A pensarci bene, il ray casting non sembra un buon modo per risolvere il problema (a causa del fatto che implica l'uso di sqrt () e un grande for loop).

Risposte:


6

Quindi hai due coordinate o vettori, uno è il centro dello schermo (C d'ora in poi) e l'altro è il tuo oggetto (P d'ora in poi.)

Se conosci un po 'di matematica, potresti sapere che una linea può essere espressa come vettore di origine e direzione. L'origine è il centro dello schermo, mentre il vettore di direzione può essere trovato sottraendo C da P. Questa equazione può anche essere espressa in forma parametrica, che è essenzialmente la stessa:

x = (P.x - C.x)t + C.x;
y = (P.y - C.y)t + C.y;

Vedi un (P.? - C.?)po '? Questo è il tuo vettore di direzione (come ho detto, sottrai C da P). L'ultimo C.?bit è l'origine della linea.

tè una variabile che può variare da 0a 1, 0essendo l'origine del vettore (se operi, xe ydiventerai C.xe C.y), 1essendo la coordinata dell'oggetto (di nuovo, operando, diventerebbe P.xe P.y, o "la fine" del vettore, se lo desideri) e i valori tra l'interpolazione tra le due estremità del segmento. Puoi anche assegnare valori esterni: sotto 0vedrai la tua direzione vettoriale invertita e sopra 1"estendi" ulteriormente il tuo vettore nella stessa direzione.

Una volta ottenuto questo, diventa abbastanza facile. Il tuo obiettivo è trovare il punto di questo vettore ( xe yper un dato valore di t) dove X=WIDTHo Y=HEIGHT, qualunque cosa venga prima. Come puoi vedere, tè l'unica variabile qui:

(0)
WIDTH = (P.x - C.x)t + C.x;
and
HEIGHT = (P.y - C.y)t + C.y;

O riesprimendolo:

(1)
t = (WIDTH - C.x)/(P.x - C.x)
and
t = (HEIGHT - C.y)/(P.y - C.y)

Questo otterrà il punto di taglio della linea definita dal tuo vettore sui bordi destro e superiore. Lo stesso vale per i bordi sinistro e inferiore dello schermo, in cui è necessario verificare 0per entrambi i casi, non WIDTHe HEIGHT.

Dal momento che alla fine taglierà i bordi, anche fuori dallo schermo, il tvalore più basso sarà il tuo primo punto di contatto. Invertire l'operazione e applicare il tvalore trovato sulle equazioni (0)(lo stesso valore per entrambi!) Porterà un nuovo (x,y), che sarà le coordinate di taglio.

Potrebbero esserci alcuni errori matematici o differenze di implementazione per il tuo problema, ma questa è l'idea di base. Ho lasciato fuori anche alcune parti (ci sono sempre quattro casi di taglio, e ne hai bisogno solo uno) ma un po 'di pensiero ti porterà a una soluzione finale :)


Grazie. Ci proverò. EDIT: Solo per curiosità, pensi che questo metodo sia quello descritto da Carrus85 (usando il rapporto dell'ipotenusa)?
Adam Henderson,

1
@AdamHenderson Sono felice di aiutarti :) Ricorda che puoi mantenere il tuo vettore di direzione in modo da poter disegnare la freccia in seguito. Puoi normalizzarlo per ottenere il vettore di direzione unitario, sottrarlo arrow-lengthtempi dal vettore di taglio "et voila", hai un'origine e una destinazione per la tua freccia.
Kaao

1
@AdamHenderson è visivamente la stessa cosa, poiché la tua linea è l'ipotenusa di cui sta parlando. In pratica, non è lo stesso, dal momento che il suo suggerimento riguarda angoli (e quindi la trigonometria) che ritengo eccessivi per questo. Questo non comporta triangoli a tutti (anche se si può pensare del vostro vettore come un triangolo in cui l'ipotenusa è il vettore ed entrambi i lati sono le xe ycomponenti.)
kaoD

Grazie ancora! Hai risolto il mio prossimo problema di puntare la freccia nella giusta direzione.
Adam Henderson,

1
@AdamHenderson sì, in basso se l'asse viene capovolto. A proposito, suggerirei di pubblicare un link a questa domanda nel forum di Allegro per riferimento futuro.
Kaao,
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.