Como desenhar uma seta na borda da tela apontando para um objeto que está fora da tela?

12

Desejo fazer o que é descrito neste tópico:

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

Eu tentei uma variedade dos métodos mencionados aqui.

Primeiro, tentei usar o método descrito por Carrus85:

Pegue a razão entre os dois hipontênios do triângulo (não importa qual triagle você usar para o outro, sugiro os pontos 1 e 2 como a distância que você calcula). Isso fornecerá a porcentagem da proporção do triângulo no canto do triângulo maior. Então você simplesmente multiplica o deltax por esse valor para obter o deslocamento da coordenada x e delta por esse valor para obter o deslocamento da coordenada y.

Mas não consegui encontrar uma maneira de calcular a que distância o objeto está da borda da tela.

Tentei então usar o casting de raios (o que nunca fiz antes) sugerido por 23yrold3yrold:

Dispare um raio do centro da tela para o objeto fora da tela. Calcule onde o retângulo cruza o raio. Aqui estão suas coordenadas.

Primeiro calculei a hipotenusa do triângulo formada pela diferença nas posições x e y dos dois pontos. Eu usei isso para criar um vetor de unidade ao longo dessa linha. Passei por esse vetor até que a coordenada x ou a coordenada y estivesse fora da tela. Os dois valores atuais de x e y formam os x e y da seta.

Aqui está o código para o meu método de conversão de raios (escrito em 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);
}

Isso foi relativamente bem-sucedido. As setas são exibidas na seção inferior direita da tela quando os objetos estão localizados acima e à esquerda da tela, como se os locais onde as setas foram desenhadas foram girados 180 graus ao redor do centro da tela.

Supus que isso se devia ao fato de que, ao calcular a hipotenusa do triângulo, sempre seria positivo, independentemente de a diferença em x ou a diferença em y ser negativa.

Pensando nisso, a conversão de raios não parece ser uma boa maneira de resolver o problema (devido ao fato de envolver o uso de sqrt () e um loop for grande).

Adam Henderson
fonte

Respostas:

6

Então você tem duas coordenadas ou vetores, um é o centro da tela (C a partir de agora) e o outro é o seu objeto (P a partir de agora).

Se você conhece um pouco de matemática, talvez saiba que uma linha pode ser expressa como um vetor de origem e direção. A origem é o centro da tela, enquanto o vetor de direção pode ser encontrado subtraindo C de P. Essa equação também pode ser expressa na forma paramétrica, que é essencialmente a mesma:

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

Veja a parte (P.? - C.?)? Esse é o seu vetor de direção (como eu disse, subtraia C de P). O último C.?bit é a origem da linha.

té uma variável que pode variar de 0a 1, 0sendo a origem do vetor (se você operar, xe yse tornaráC.x e C.y), 1sendo a sua coordenada do objeto (novamente, operando, ele se tornaria P.xe P.y, ou o "fim" do vetor, se desejar) e valores entre a interpolação entre as duas extremidades do seu segmento. Você também pode atribuir valores externos: abaixo, 0você inverte a direção do vetor e, acima, 1"estende" o vetor ainda mais na mesma direção.

Depois de conseguir isso, fica muito fácil. Seu objetivo é encontrar o ponto desse vetor ( xe ypara um determinado valor de t) onde X=WIDTHou Y=HEIGHT, o que ocorrer primeiro. Como você pode ver, té sua única variável aqui:

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

Ou re-expressando:

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

Isso obterá o ponto de corte da linha definida pelo seu vetor nas bordas direita e superior. O mesmo vale para as bordas esquerda e inferior da tela, onde você precisa verificar os 0dois casos, não WIDTHe HEIGHT.

Como acabará cortando as bordas, mesmo fora da tela, a menor t valor será o seu primeiro ponto de contato. Inverter a operação e aplicar o tvalor encontrado nas equações em (0)(o mesmo valor para ambos!) Trará um novo (x,y), que serão suas coordenadas de corte.

Pode haver alguns erros matemáticos ou diferenças de implementação para o seu problema, mas essa é a ideia básica. Também deixei algumas peças de fora (sempre há quatro casos de corte e você precisa de apenas um), mas um pouco de reflexão levará você a uma solução final :)

kaoD
fonte
Obrigado. Vou tentar. EDIT: Por curiosidade, você acha que esse método é o descrito por Carrus85 (usando a razão da hipotenusa)?
11132 Adam Henderson
1
@AdamHenderson, fico feliz em ajudar :) Lembre-se de que você pode manter seu vetor de direção para poder desenhar sua flecha mais tarde. Você pode normalizá-lo para obter seu vetor de direção unitária, subtraí-lo várias arrow-lengthvezes do vetor de corte "et voila", você tem uma origem e um destino para sua flecha.
KaoD 11/04/12
1
@AdamHenderson visualmente é a mesma coisa, já que sua linha é a hipotenusa de que ele está falando. Praticamente, não é a mesma coisa, já que a sugestão dele envolve ângulos (e trigonometria, portanto) que eu acho que é um exagero para isso. Isso não envolve triângulos em tudo (embora você pode pensar no seu vector como um triângulo, onde a hipotenusa é o vetor e ambos os lados são os xe ycomponentes.)
kaoD
Obrigado novamente! Você resolveu meu próximo problema de apontar a seta na direção certa.
Adam Henderson
1
@AdamHenderson sim, embaixo se o eixo estiver invertido. BTW, eu sugiro postar um link para esta pergunta no fórum da Allegro para referência futura.
kaoD