如何在屏幕边缘绘制一个箭头,使其指向屏幕外的对象?


12

我希望执行本主题中描述的操作:

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

我尝试了这里提到的各种方法。

首先,我尝试使用Carrus85描述的方法:

只需取两个三角形斜边的比率即可(与另一个三角形无关),我建议将点1和点2作为计算的距离。这将为您提供从较大三角形到角落的三角形的长宽比百分比。然后,您只需将deltax乘以该值即可得到x坐标偏移,然后将deltay乘以该值即可得到y坐标偏移。

但是我找不到一种方法来计算对象离屏幕边缘的距离。

然后,我尝试使用23yrold3yrold建议的射线投射(以前从未做过):

从屏幕中心向屏幕外对象发射光线。计算射线在矩形上的相交位置。有你的座标。

我首先计算了由两点的x和y位置差异形成的三角形的斜边。我用它沿着那条线创建了一个单位向量。我遍历该向量,直到x坐标或y坐标不在屏幕上。然后,两个当前的x和y值形成箭头的x和y。

这是我的光线投射方法的代码(用C ++和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);
}

这是相对成功的。当对象位于屏幕的上方和左侧时,箭头会显示在屏幕的右下部分,就像绘制箭头的位置已围绕屏幕中心旋转了180度一样。

我认为这是由于以下事实:当我计算三角形的斜边时,无论x或y的差是否为负,它始终为正。

考虑一下,光线投射似乎不是解决问题的好方法(因为它涉及使用sqrt()和较大的for循环)。

Answers:


6

因此,您有两个坐标或矢量,一个是屏幕的中心(从现在开始为C),另一个是您的对象(从现在开始为P)。

如果您了解一些数学知识,则可能知道一条线可以表示为原点和方向向量。原点是您的屏幕中心,而方向矢量可以从P中减去C。此等式也可以参数形式表示,基本上是相同的:

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

看到(P.? - C.?)位了吗?那就是你的方向向量(正如我所说,从P中减去C)。最后C.?一位是线的起点。

t是一个变量,可以从0到变化10是向量的原点(如果您进行操作,x并且y将变为C.xC.y),1是对象的坐标(再次进行操作,则将成为P.xP.y,或者是向量的“末端”, (如果您愿意的话)以及介于细分的两端之间的值。您还可以分配外部值:下面0将使向量方向反转,而在上面1将沿相同方向进一步“延伸”向量。

一旦掌握了这一点,它将变得非常容易。你的目标是找到这个向量的点(xy对于给定的值t),其中X=WIDTH或者Y=HEIGHT,无论第一个来。如您所见,这t是您唯一的变量:

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

或重新表达它:

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

这将在右侧和顶部边界上获得由矢量定义的线的切割点。屏幕的左边界和底边界也是如此,在0这两种情况下都需要检查,而不是WIDTHHEIGHT

由于它最终会划掉边界,即使在屏幕外也是如此,因此最低t值将是您的第一个联系点。反转操作并将您的发现t值应用于方程式(0)(两个值相同!)将带来一个新的(x,y),这将是您的切削坐标。

您的问题可能存在一些数学错误或实现上的差异,但这是基本思想。我也省略了一些部分(总是有4种切割的情况,而您只需要其中一种),但稍加思考就会使您得到最终的解决方案:)


谢谢。我会去的。编辑:出于好奇,您是否认为此方法是Carrus85描述的方法(使用斜边的比率)?
亚当·亨德森

1
@AdamHenderson我很高兴为您提供帮助:)请记住,您可以保持方向矢量,以便以后可以绘制箭头。您可以对其进行归一化以获得单一方向矢量,然后arrow-length从切削矢量“ et voila”中减去它的倍数,就可以得到箭头的起点和终点。
kaoD 2012年

1
@AdamHenderson在视觉上是同一回事,因为您的台词是他所说的斜边。实际上,这是不一样的,因为他的建议涉及角度(因此也包括三角学),我认为这太过分了。这根本不涉及三角形(尽管您可以将向量看作是三角形,其中斜边是向量,而两侧都是xy。)
kaoD 2012年

再次感谢!您解决了我的下一个将箭头指向正确方向的问题。
亚当·亨德森

1
@AdamHenderson是的,如果轴被翻转,则在底部。顺便说一句,我建议在Allegro的论坛上发布此问题的链接,以备将来参考。
kaoD 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.