¿Cómo puedo dibujar una flecha en el borde de la pantalla que apunta a un objeto que está fuera de la pantalla?

12

Deseo hacer lo que se describe en este tema:

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

He intentado una variedad de los métodos mencionados aquí.

Primero intenté usar el método descrito por Carrus85:

Simplemente tome la relación de los dos hipóntenos triangulares (no importa qué triángulo use para el otro, sugiero el punto 1 y el punto 2 como la distancia que calcula). Esto le dará el porcentaje de relación de aspecto del triángulo en la esquina del triángulo más grande. Luego, simplemente multiplique deltax por ese valor para obtener el desplazamiento de la coordenada x, y deltay por ese valor para obtener el desplazamiento de la coordenada y.

Pero no pude encontrar una manera de calcular qué tan lejos está el objeto del borde de la pantalla.

Luego intenté usar el casting de rayos (que nunca había hecho antes) sugerido por 23yrold3yrold:

Dispara un rayo desde el centro de la pantalla al objeto fuera de la pantalla. Calcule dónde en el rectángulo se cruza el rayo. Ahí están tus coordenadas.

Primero calculé la hipotenusa del triángulo formado por la diferencia en las posiciones x e y de los dos puntos. Usé esto para crear un vector unitario a lo largo de esa línea. Recorrí ese vector hasta que la coordenada x o la coordenada y estaban fuera de la pantalla. Los dos valores actuales de x e y luego forman las x e y de la flecha.

Aquí está el código para mi método de emisión de rayos (escrito en C ++ y 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);
}

Esto fue relativamente exitoso. Las flechas se muestran en la sección inferior derecha de la pantalla cuando los objetos se encuentran arriba y a la izquierda de la pantalla como si las ubicaciones del lugar donde se dibujan las flechas se hayan girado 180 grados alrededor del centro de la pantalla.

Supuse que esto se debía al hecho de que cuando calculaba la hipotenusa del triángulo, siempre sería positivo independientemente de si la diferencia en x o la diferencia en y es negativa.

Pensando en ello, la proyección de rayos no parece ser una buena forma de resolver el problema (debido al hecho de que implica el uso de sqrt () y un bucle for grande).

Adam Henderson
fuente

Respuestas:

6

Entonces tiene dos coordenadas o vectores, uno es el centro de la pantalla (C de ahora en adelante) y el otro es su objeto (P de ahora en adelante).

Si conoce algo de matemática, puede saber que una línea se puede expresar como un origen y un vector de dirección. El origen es el centro de la pantalla, mientras que el vector de dirección se encuentra restando C de P. Esta ecuación también se puede expresar en forma paramétrica, que es esencialmente la misma:

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

¿Ves el (P.? - C.?)bit? Ese es su vector de dirección (como dije, reste C de P). El último C.?bit es el origen de la línea.

tes una variable que puede variar de 0a 1, 0siendo el origen del vector (si opera, xy se yconvertiría en C.xy C.y), 1siendo su objeto coordinado (nuevamente, operando, se convertiría en P.xy P.y, o el "fin" del vector, si lo desea) y valores intermedios entre los dos extremos de su segmento. También puede asignar valores externos: debajo 0obtendrá la dirección de su vector invertida y arriba 1"extenderá" su vector más en la misma dirección.

Una vez que obtienes esto, se vuelve bastante fácil. Su objetivo es encontrar el punto de este vector ( xy ypara un valor dado de t) dónde X=WIDTHo Y=HEIGHT, lo que ocurra primero. Como puede ver, tes su única variable aquí:

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

O reexpresándolo:

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

Esto obtendrá el punto de corte de la línea definida por su vector en sus bordes derecho y superior. Lo mismo ocurre con los bordes izquierdo e inferior de su pantalla, donde debe verificar 0en ambos casos, no WIDTHy HEIGHT.

Como eventualmente cortará los bordes, incluso fuera de la pantalla, el tvalor más bajo será su primer punto de contacto. Invertir la operación y aplicar su tvalor encontrado en las ecuaciones en (0)(¡el mismo valor para ambos!) Traerá una nueva (x,y), que serán sus coordenadas de corte.

Puede haber algunos errores matemáticos o diferencias de implementación para su problema, pero esa es la idea básica. También dejé algunas partes (siempre hay cuatro casos de corte, y solo necesitas uno), pero un poco de reflexión te llevará a una solución final :)

kaoD
fuente
Gracias. Voy a darle una oportunidad. EDITAR: Solo por curiosidad, ¿crees que este método es el que describió Carrus85 (usando la relación de la hipotenusa)?
Adam Henderson el
1
@AdamHenderson, me complace ayudar :) Recuerde que puede mantener su vector de dirección para poder dibujar su flecha más tarde. Puede normalizarlo para obtener su vector de dirección unitaria, restarlo arrow-lengthveces del vector de corte "et voila", tiene un origen y un destino para su flecha.
kaoD
1
@AdamHenderson visualmente es lo mismo, ya que tu línea es la hipotenusa de la que está hablando. Prácticamente, no es lo mismo, ya que su sugerencia involucra ángulos (y trigonometría por lo tanto) que creo que es excesivo para esto. Esto no implica triángulos en absoluto (aunque se puede pensar en su vector como un triángulo, donde la hipotenusa es el vector y ambas partes son las xy los ycomponentes.)
kaoD
¡Gracias de nuevo! Resolviste mi próximo problema de apuntar la flecha en la dirección correcta.
Adam Henderson el
1
@AdamHenderson sí, abajo si el eje se voltea. Por cierto, sugeriría publicar un enlace a esta pregunta en el foro de Allegro para referencia futura.
kaoD