以与不在矩形中间的点成一定角度的角度找到矩形边界点 [英] Find rectangle boundary point at an angle from point that is not in the middle of the rectangle

查看:105
本文介绍了以与不在矩形中间的点成一定角度的角度找到矩形边界点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图显示玩家在我的游戏中瞄准的矩形区域.他在这样的广场上:

I am trying to display where, in a rectangle, is player aiming in my game. He's in such a square:

我发现了一个逐点查找矩形的算法,将其应用并且结果是错误的(真实游戏截图) :

I found an algorithm to find rectangle point by angle, applied it and the results were wrong (real game screenshot):

我很快意识到这是因为播放器不在矩形的中心.因此,我用我的点替换了算法中的中心点.但是结果只是将点移动了恒定的距离:

I soon realized this is because player is not in the center of the rectangle. So I replaced the center point in the algorighm with my point. But the result is just shifted point by constant distance:

因此,我想我目前的算法不仅需要更改一项.我的代码:

So I guess my current algorithm needs more than just one change. My code:

  function boudaryatangle(theta, point) {
    // reduce the theta  
    theta =  theta % 360; 
    // force it to be the positive remainder, so that 0 <= theta < 360  
    theta = (theta + 360) % 360;  
    // force into the minimum absolute value residue class, so that -180 < theta <= 180  
    if (theta > 180)  
        theta -= 360;  
    // Convert to radians
    theta = (theta * Math.PI / 180);
    // Get a rectangle that has width and height properties
    var rect = this.game.pixels;
    var width = rect.width;
    var height = rect.height;
    // If refference point wasn't provided as second argument
    //TODO: MAKE IT WORK WITH OTHER THEN RECTANGLE CENTRE POINT!
    if(typeof point=="undefined") {
      point = new Float32Array(2);
      point[0] = width/2;
      point[1] = height/2;
    }
    // Here be mysterious math and stuff - all bellow explained here
    var rectAtan = Math.atan2(height, width);
    var tanTheta = Math.tan(theta);
    // By default, region 1 and 3
    var region = true;

    var xFactor = 1;
    var yFactor = 1;

    if ((theta > -rectAtan) && (theta <= rectAtan)) {
        yFactor = -1;  // REGION 1
    } else if ((theta > rectAtan) && (theta <= (Math.PI - rectAtan))) {
        yFactor = -1;  // REGION 2
        region = false;
    } else if ((theta > (Math.PI - rectAtan)) || (theta <= -(Math.PI - rectAtan))) {
        xFactor = -1;  // REGION 3
    } else {
        xFactor = -1;  // REGION 4
        region = false;
    }

    // If region 1, 3
    if (region) {
      point[0] += xFactor * (width / 2.);                                     // "Z0"
      point[1] += yFactor * (width / 2.) * tanTheta;
    } else {
      point[0] += xFactor * (height / (2. * tanTheta));                        // "Z1"
      point[1] += yFactor * (height /  2.);
    }
    return point;
  }

我还必须在什么地方应用参考点位置才能使其正常工作? 不需要,如果点超出矩形,则此函数返回合理的结果.

Where else do I have to apply refference point location to get it to work? It's not required that this function returns sane results if point is out of the rectangle.

推荐答案

玩家看见"了各个角落,并且根据他瞄准的角落的哪一侧,碰撞发生在垂直或水平侧.

The player "sees" on of the corners, and depending on which side of the corner he is aiming at, the collision occurs on the vertical or horizontal side.

让我们表示c = cos Θs = sin Θ.从(x, y)(c, s)方向的直线方程为(X - x) s - (Y - y) c = 0.左侧的表达式在该行的一侧为正,而在另一侧为负.

Let us denote c = cos Θ, s = sin Θ. The equation of the line from (x, y) in the direction (c, s) is (X - x) s - (Y - y) c = 0. The expression on the left-hand side is positive on a side of the line and negative on the other side.

在第一象限(c, s > 0)中,拐角为(w, h),并且V/H决定取决于(w - x) s - (h - y) c的符号.如果相交处是垂直边,我们有

In the first quadrant (c, s > 0), the corner is (w, h), and the V/H decision depends on the sign of (w - x) s - (h - y) c. If the intersection is with the vertical side, we have

X = w, (w - x) s - (Y - y) c = 0, or Y = y + (w - x) s / c.

对于水平方向,

Y = h, (X - x) s - (h - y) c = 0, or X = x + (h - y) c / s.

我们可以写

Corner (w, h):
    if (w - x) s < (h - y) c:
        X= w; Y= y + (w - x) s / c
    else:
        X= x + (h - y) c / s; Y= h

请注意,如果使用c==0s==0,该解决方案仍然有效,因为将采用的分支不会出现被零除的情况.比较中使用<还是<=都没有区别(在相等的情况下,发现拐角本身,双向).

Notice that if c==0 or s==0, the solution is still valid because the branch that will be taken is such that no division by zero can arise. Whether < or <= is used in the comparison makes no difference (in case of equality the corner itself is found, both ways).

可以将其微优化为

Corner (w, h):
    S= (w - x) s; C= (h - y) c
    if S < C:
        X= w; Y= y + S / c
    else:
        X= x + C / s; Y= h

可以对四个象限重复相同的讨论,用0替换w和/或h.最终的代码结构是

The same discussion can be repeated for the four quadrants, replacing w and/or h by 0. The final code structure is

if s >= 0:
    if c >= 0:
        Corner (w, h)
    else:
        Corner (0, h)
else:
    if c >= 0:
        Corner (w, 0)
    else:
        Corner (0, 0)

请注意正确调整四个象限的比较方向.

Take care to adjust the direction of the comparison correctly for the four quadrants.

选择该公式的目的是为了尽量减少计算量,同时保持数值上的可靠性.我们列出

This formulation was chosen to try to reach a minimum amount of computation, while remaining numerically reliable. We list

  • 两个象限选择象限测试,
  • 一个比较,涉及两个产品和两个添加项,
  • 相交计算的一加一除.

这篇关于以与不在矩形中间的点成一定角度的角度找到矩形边界点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆