检测对象是否将在二维空间中发生碰撞

本文关键字:空间 二维 碰撞 是否 对象 检测 | 更新日期: 2023-09-27 18:28:12

我一直在尝试为小行星游戏制作AI,但被卡住了。游戏中的其他一切都是设置好的(即创建并向随机方向移动的小行星、碰撞检测、飞船和子弹。)AI每150毫秒循环一次,只能告诉飞船向左、向右、向上移动并射击。

以下是我目前使用的代码片段:

                // Convert points to positive
                float asteroid_x = Math.Abs(asteroid.X);
                float asteroid_y = Math.Abs(asteroid.Y);
                float ship_x = Math.Abs(ship.X);
                float ship_y = Math.Abs(ship.Y);
                // Calculate difference in X and Y using positive values
                float dx = asteroid_x - ship_x;
                float dy = asteroid_y - ship_y;
                // Get velocities of asteroid
                float vx = asteroid.VX;
                float vy = asteroid.VY;

使用这些变量(dx,dy,vx,vy),我需要计算小行星是否会撞上飞船。我一直在尝试使用三角法,但它一直认为它会成功,而事实并非如此。我一直在尝试使用的方程式是:

            float equation1a = (dy / vy) - (dx / vx);
            float equation1 = ((dy / dx) - (vy / vx));

然后我一直在尝试使用IF语句来确定它是否会命中,但我不确定如何正确执行。在这个IF声明之后,我想进入AI,要么转身射击小行星,要么躲避它

谢谢你的帮助。

编辑:飞船或小行星的X和Y值也可以为负值,飞船从原点开始(0,0)。

第二版:现在更进一步,想出这个:

// Determine if asteroid will collide
int turns_ahead = 100;
bool collision = false;
int least_turns = 500;
for (int i = 0; i < turns_ahead; i++)
{
    PointF asteroid_pos_next = NextPosition(new PointF(asteroid.X, asteroid.Y), new PointF(asteroid.VX, asteroid.VY), i);
    if (asteroid.CollidesWith(asteroid_pos_next.X, asteroid_pos_next.Y, ship.R))
    {
        collision = true;
    }
}

下一个位置是用这个函数计算出来的:

    // -----------------------------------------------------------------
    // Function to find position of object in X turns (turns_ahead)
    // -----------------------------------------------------------------
    private static PointF NextPosition(PointF current_pos, PointF velocity, int turns_ahead)
    {
        float next_x_pos = current_pos.X + (velocity.X * turns_ahead);
        float next_y_pos = current_pos.Y + (velocity.Y * turns_ahead);
        // IFs to deal with screen wrap-around
        if (next_x_pos < -Form1.maxX)
        {
            next_x_pos = Form1.maxX;
            if (next_y_pos < 0)
                next_y_pos += Form1.maxY;
            else
                next_y_pos -= Form1.maxY;
        }
        else if (next_x_pos > Form1.maxX)
        {
            next_x_pos = -Form1.maxX;
            if (next_y_pos < 0)
                next_y_pos += Form1.maxY;
            else
                next_y_pos -= Form1.maxY;
        }
        if (next_y_pos < -Form1.maxY)
        {
            next_y_pos = Form1.maxY;
            if (next_x_pos < 0)
                next_x_pos += Form1.maxX;
            else
                next_x_pos -= Form1.maxX;
        }
        else if (next_y_pos > Form1.maxY)
        {
            next_y_pos = -Form1.maxY;
            if (next_x_pos < 0)
                next_x_pos += Form1.maxX;
            else
                next_x_pos -= Form1.maxX;
        }
        PointF next_pos = new PointF(next_x_pos, next_y_pos);
        return next_pos;
    }

collapsWith是小行星类的一个函数,在其他地方用于检测子弹/飞船是否撞上了小行星。我不确定我的下一个位置函数是否正确,尽管就好像小行星确实围绕着X/Y值,似乎被困在了最大X/maxY值?

检测对象是否将在二维空间中发生碰撞

考虑以下内容:在任何时候,你都有小行星和飞船的位置及其速度。然后,在时间t(间隔150ms),小行星的位置将是

asteroid_x + asteroid.vx * t
asteroid_y + asteroid.vy * t

船的位置将是

ship_x + ship.vx * t
ship_y + ship.vy * t

因此,你可以迭代t(0到100),检查小行星和飞船是否在任何时候都在彼此的某个距离内(例如它们的半径之和),这意味着碰撞。

p.s.距离由给出

sqrt( (asteroid_x - ship_x)^2 + (astroid_y - ship_y)^2 )

我建议您阅读更多关于碰撞检测的一般信息以及

这里没有足够的上下文,需要查看更多的代码。不过,我正在研究的非常高级的概念是两个步骤-1。移动小行星物体(在与移动飞船的用户/AI不同的线程上),2。在每次移动(事件处理程序)时,检查小行星的位置与船只的位置(碰撞)的比较。此外,你提到"会撞到它",你是否试图在碰撞发生之前预测碰撞?如果是这样的话,你需要考虑小行星和飞船以前/最近的运动来"预测"它们未来的运动。

想象一下你的物体在三维空间中的运动,其中第三个是时间;如果3D中的这些线足够靠近(假设物体都是圆,则小于它们半径的总和),它们最终会碰撞。

这两条3D线可以由点(x,y,0)和方向矢量(vx,vy,1)来定义;然后,您可以应用众所周知的几何图形来找到两条"偏斜"三维线之间的最接近距离;我现在还不知道,但这里有一篇文章给出了

D=|c·(a×b)|/|a×b|

其中小写变量是矢量,c是位置之间的差,ab是两个方向矢量。

请注意,如果的对象在过去的当前轨迹上发生碰撞,这将产生误报;我不知道如何解决这个问题,但即使你把它留在里面,也可能不会对你的人工智能产生太大干扰。也许有一种方法可以测试"绝对分开",或者这个公式中分子的符号是有意义的。