Comment puis-je dessiner une flèche sur le bord de l'écran pointant vers un objet hors écran?

12

Je souhaite faire ce qui est décrit dans cette rubrique:

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

J'ai essayé une variété des méthodes mentionnées ici.

J'ai d'abord essayé d'utiliser la méthode décrite par Carrus85:

Prenez simplement le rapport des deux hyponténuses triangulaires (peu importe le triagle que vous utilisez pour l'autre, je suggère le point 1 et le point 2 comme distance que vous calculez). Cela vous donnera le pourcentage d'aspect du triangle dans le coin par rapport au plus grand triangle. Ensuite, vous multipliez simplement la deltaxe par cette valeur pour obtenir le décalage des coordonnées x et le retard par cette valeur pour obtenir le décalage des coordonnées y.

Mais je n'ai pas trouvé de moyen de calculer à quelle distance l'objet est éloigné du bord de l'écran.

J'ai ensuite essayé d'utiliser le lancer de rayons (ce que je n'ai jamais fait auparavant) suggéré par 23yrold3yrold:

Tirez un rayon du centre de l'écran vers l'objet hors écran. Calculez où sur le rectangle le rayon se croise. Voilà vos coordonnées.

J'ai d'abord calculé l'hypoténuse du triangle formé par la différence de positions x et y des deux points. Je l'ai utilisé pour créer un vecteur unitaire le long de cette ligne. J'ai parcouru ce vecteur jusqu'à ce que la coordonnée x ou la coordonnée y soit hors de l'écran. Les deux valeurs x et y actuelles forment alors les x et y de la flèche.

Voici le code de ma méthode de lancer de rayons (écrit en C ++ et 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);
}

Cela a été relativement réussi. Les flèches sont affichées dans la partie inférieure droite de l'écran lorsque les objets sont situés au-dessus et à gauche de l'écran, comme si les emplacements de l'endroit où les flèches étaient dessinées avaient été tournés de 180 degrés autour du centre de l'écran.

J'ai supposé que cela était dû au fait que lorsque je calculais l'hypoténuse du triangle, elle serait toujours positive, que la différence de x ou la différence de y soit négative ou non.

En y réfléchissant, le lancer de rayons ne semble pas être un bon moyen de résoudre le problème (car il implique l'utilisation de sqrt () et d'une grande boucle for).

Adam Henderson
la source

Réponses:

6

Vous avez donc deux coordonnées ou vecteurs, l'un est le centre de l'écran (C à partir de maintenant) et l'autre est votre objet (P à partir de maintenant.)

Si vous connaissez les mathématiques, vous savez peut-être qu'une ligne peut être exprimée comme une origine et un vecteur de direction. L'origine est votre centre d'écran, tandis que le vecteur de direction peut être trouvé en soustrayant C de P. Cette équation peut également être exprimée sous forme paramétrique, qui est essentiellement la même:

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

Tu vois le (P.? - C.?)morceau? C'est votre vecteur de direction (comme je l'ai dit, soustrayez C de P). Le dernier C.?bit est l'origine de la ligne.

test une variable qui peut varier de 0à 1, 0étant l'origine du vecteur (si vous opérez , xet ydeviendrait C.xet C.y), 1étant la coordonnée de votre objet (encore une fois, en fonctionnant, elle deviendrait P.xet P.y, ou la "fin" du vecteur, si vous le souhaitez) et des valeurs intermédiaires entre les deux extrémités de votre segment. Vous pouvez également affecter des valeurs externes: ci-dessous, 0vous inverserez la direction de votre vecteur et au-dessus, 1vous "étirez" votre vecteur plus loin dans la même direction.

Une fois que vous obtenez cela, cela devient assez facile. Votre objectif est de trouver le point de ce vecteur ( xet ypour une valeur donnée de t) où X=WIDTHou Y=HEIGHT, quoi qu'il arrive en premier. Comme vous pouvez le voir, test votre seule variable ici:

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

Ou le ré-exprimer:

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

Cela obtiendra le point de coupe de la ligne définie par votre vecteur sur vos bordures droite et supérieure. Il en va de même pour les bordures gauche et inférieure de votre écran, où vous devez vérifier les 0deux cas, pas WIDTHet HEIGHT.

Puisqu'il finira par couper les frontières, même hors écran, la tvaleur la plus basse sera votre premier point de contact. Inverser l'opération et appliquer votre tvaleur trouvée sur les équations à (0)(la même valeur pour les deux!) Apportera une nouvelle (x,y), qui sera vos coordonnées de coupe.

Il peut y avoir des erreurs mathématiques ou des différences d'implémentation pour votre problème, mais c'est l'idée de base. J'ai également omis certaines parties (il y a toujours quatre cas de coupe, et vous n'en avez besoin que d'un), mais un peu de réflexion vous amènera à une solution finale :)

kaoD
la source
Merci. Je vais essayer. EDIT: Juste par curiosité, pensez-vous que cette méthode est celle que Carrus85 a décrite (en utilisant le rapport de l'hypoténuse)?
Adam Henderson
1
@AdamHenderson, je suis heureux de vous aider :) N'oubliez pas que vous pouvez conserver votre vecteur de direction afin de pouvoir dessiner votre flèche plus tard. Vous pouvez le normaliser pour obtenir votre vecteur de direction unitaire, le soustraire du arrow-lengthtemps du vecteur de coupe "et voila", vous avez une origine et une destination pour votre flèche.
kaoD
1
@AdamHenderson visuellement, c'est la même chose, car votre ligne est l'hypoténuse dont il parle. En pratique, ce n'est pas la même chose, car sa suggestion implique des angles (et donc de la trigonométrie) qui, je pense, sont exagérés pour cela. Cela n'implique pas du tout de triangles (bien que vous puissiez considérer votre vecteur comme un triangle où l'hypoténuse est le vecteur et les deux côtés sont les composants xet y.)
kaoD
Merci encore! Vous avez résolu mon prochain problème de pointage de la flèche dans la bonne direction.
Adam Henderson
1
@AdamHenderson yep, en bas si l'axe est inversé. BTW, je suggère de publier un lien vers cette question dans le forum d'Allegro pour référence future.
kaoD