27.直线上的第一个:只获取直线上第一个被碰撞的物体

27.First In Line: taking only the first item that a line collides with.

In our last post we added a laser to our spaceship that shot asteroids. It was a very powerful laser, because it would shoot absolutely everything in its path, effectively shooting through all the asteroids in one go. Often in a game, you don’t want this: you want to shoot only the first thing that the laser hits. We can implement this by continuing our maths from last post.

在我们上篇帖子中我们为飞船添加一个激光发射器来射击行星。它是一个非常强大的激光发射器,因为它可以扫除所到之处所有障碍,实际上是一口气打掉了所有的行星。通常在游戏中,你不希望这样:你希望只打掉激光击中的第一个物体。我们可以通过继续改进上篇帖子中提到的数学公式来实现这个目标。

Our last post finished with this quadratic equation:

我们上篇帖子里完成了如下的二次方程:

(\text{dirX}^2 + \text{dirY}^2) \times \text{scalar}^2 + ((2\times\text{distX}\times\text{dirX}) + (2\times\text{distY}\times\text{dirY}))\times\text{scalar} + \text{distX}^2 + \text{distY}^2 - \text{radius}^2 = 0

The variable of interest there was  scalar, which is, in effect, a distance along the line. We have a direction vector for the laser (the pink arrow below), and to make up the line for the laser, we effectively lay an infinite amount of these arrows end-to-end, like in the diagram below. The scalar variable keeps track of how many of these pink arrows we are from the origin of the line (the centre of the spaceship):

我们关注的变量是scalar,实际上它是沿着直线的距离。我们获取激光的方向向量(下图中的粉红色箭头),去形成激光的直线,我们实际上首尾相连地放置了无限个这样的箭头,就像下图所示。scalar变量保持追踪我们从直线的起点(飞船的中心)开始拥有多少个这样的粉色箭头。

 

So if we actually finish calculating the value for  scalar  where each asteroid is hit by the line, then the asteroid that we hit with the lowest associated positive scalar  value is the first one along the line of the laser (in this diagram, 1.7):

于是如果我们确实完成了行星与直线相撞处的scalar值的计算,那么我们所撞击的拥有与之相关的最小正salar值的行星便是沿着激光直线的第一个行星(如同,1.7)。

Note that we don’t want to allow negative scalar  values, because then we would shoot asteroids that were behind the ship! So, back to our maths equation — we saw last post that a quadratic can be rearranged to:

注意一下我们不允许负的scalar值,因为这样一来我们可能会射到飞船后面的行星!因此,回到我们的数学方程式——我们在上篇帖子中看到的二次方程可以变形为:

x = \displaystyle\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}

Where, for us:

x = \text{scalar}
a = \text{dirX}^2 + \text{dirY}^2
b = (2\times\text{distX}\times\text{dirX}) + (2\times\text{distY}\times\text{dirY})
c = \text{distX}^2 + \text{distY}^2 - \text{radius}^2

The quadratic equation gives two solutions: this will be the value of scalar where the line enters the circle, and a second solution for the value of scalar where the line exits the circle (think about it: an infinite straight line can’t enter a circle without leaving it again). We don’t need to worry about which is which, we are just interested in the lowest scalar value that we find, as that will be the nearest one. All this comes out in the code that we need:

这个二次方程有两个解:一个scalar值表示直线从那儿进入圆,而另一个scalar值表示直线从那儿离开圆(思考一下:一条无限长度的直线不可能只进入圆而不出来)。我们无需担心谁是谁,我们仅仅关心所得到的最小的scalar值,那将是最近的一个行星。所有这些可用如下代码表示:

        Asteroid nearest = null;
        double nearestScalar = 1000; //huge value
        
        for (Asteroid asteroid : (List<Asteroid>)getWorld().getObjects(Asteroid.class))
        {
            double distX = getX() - asteroid.getX();
            double distY = getY() - asteroid.getY();
            
            double a = dirX * dirX + dirY * dirY;
            double b = 2 * distX * dirX + 2 * distY * dirY;
            double c = distX * distX + distY * distY - asteroid.getRadius() * asteroid.getRadius();
            
            if (b * b - 4 * a * c >= 0)
            {
                double scalarA = (-b + Math.sqrt(b * b - 4 * a * c)) / (2*a);
                double scalarB = (-b - Math.sqrt(b * b - 4 * a * c)) / (2*a);
                
                if (scalarA >= 0 && scalarA < nearestScalar)
                {
                    nearestScalar = scalarA;
                    nearest = asteroid;
                }
                
                if (scalarB >= 0 && scalarB < nearestScalar)
                {
                    nearestScalar = scalarB;
                    nearest = asteroid;
                }
            }
        }
        
        if (nearest != null)
        {
            if (nearest.hit(30))
            {
                destroyedAsteroid();
            }
        }

So there it is — the quadratic formula actually implemented and used in code.You can have a play with the scenario (and download the full source) on the Greenfoot site.

因此这儿就是——二次方程式实际上被实现并使用在了代码中。你可以在Greenfoot网站上玩一下游戏剧本(同时下载完整的代码)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值