简体   繁体   English

如何在乒乓球比赛中预测球的轨迹,用于 AI 桨预测?

[英]How to predict trajectory of ball in a ping pong game, for AI paddle prediction?

This might be a more mathematical question, but I'm trying to get my head around how I can program an unbeatable AI for a ping pong game.这可能是一个更数学的问题,但我正试图弄清楚如何为乒乓球比赛编写无与伦比的人工智能。 From what I have read so far, it would be to simulate the trajectory of a ball when it is moving in the direction towards the AI Paddle.从我目前所读到的内容来看,它将模拟一个球在朝着 AI Paddle 的方向移动时的轨迹。

In this game I have a ball and I can read its x and y position on the board, and then read it again in the next iteration which will allow me to calculate the velocity in the x and y direction.在这个游戏中,我有一个球,我可以在板上读取它的 x 和 y position,然后在下一次迭代中再次读取它,这将允许我计算 x 和 y 方向的速度。

But I'm not sure how to program how and where the ball will reach the AI paddle's goal position, and consider how many times the ball will bounce off the walls will requires me to use some geometry.但我不确定如何编程球将如何以及在何处到达 AI 桨的目标 position,并且考虑球会从墙壁反弹多少次将需要我使用一些几何图形。 But I can't get my head around it and how I will be programming it.但我无法理解它以及我将如何对其进行编程。

So far what I have thought of is the variables I've been given: the size of the table in x and y direction, the position of the ball "currently" and before in order to get its velocity in x and y direction.到目前为止,我想到的是给定的变量:桌子在 x 和 y 方向上的大小,球“当前”和之前的 position 以获得它在 x 和 y 方向上的速度。 My first assumption is to find out a way to calculate whether the ball will hit the walls or the AI goal side instead?我的第一个假设是找到一种方法来计算球是否会撞到墙壁或 AI 球门侧?

There is a more direct way of doing this instead of repeated "raycasting":有一种更直接的方法可以代替重复的“光线投射”:

def predict(x, y, vx, vy, h, b):
    """
    :param x: ball x position
    :param y: ball y position
    :param vx: ball x velocity
    :param vy: ball y velocity
    :param h: the field height
    :param b: the y position the prediction is for
    :return: ball x position at y = b
    """
    m = vy / vx # slope
    c = -x * m + y # y-intercept
    val = (m * b + c) % (2 * h)
    return min(val, 2 * h - val)

Now, step by step现在,一步一步

m = vy / vx # slope
c = -x * m + y # y-intercept
val = (m * b + c)

A simple linear function showing the ball's current path.一个简单的线性 function 显示了球的电流路径。

This works, but only if the ball never hits a side wall.这有效,但前提是球永远不会撞到侧壁。

A Model A Model

Imagine there were fields with the same height on both sides of the original one, stretching into infinity.想象一下,原来的两边都有相同高度的田地,一直延伸到无穷大。

Now 'the number of bounces' has become 'the number of cells the ball travels'.现在“反弹次数”变成了“球移动的单元数”。

Additionally, if the number of bounces is even, the distance from the lower border of the cell it hits to the point of impact is the same as the height the actual ball would hit at in the real cell.此外,如果反弹次数是偶数,则从它击中的单元格的下边界到撞击点的距离与实际球在真实单元格中击中的高度相同。

Therefore所以

(m * b + c) % (2 * h)

To cover odd bounces as well, you need to mirror the graph around h .为了覆盖奇数反弹,您需要围绕h镜像图形。

Here is a graphic explanation:这是一个图形解释:

图解说明

And since the irrelevant graph is the one with values above h , you take the minimum.并且由于不相关的图是值高于h的图,因此您取最小值。

Possible Problems可能的问题

In some languages, the % is a remainder operator, though not python.在某些语言中, %是余数运算符,但不是 python。

If the predictions are negative in some cases add this.如果在某些情况下预测是否定的,请添加此项。

val = ((m * b + c) % (2 * h) + 2 * h) % (2 * h)

This function depends on 'accurate' collision.此 function 取决于“准确”碰撞。

So if the bounces are handled in a way similar to this,因此,如果以与此类似的方式处理反弹,

if y not in range(0, y_max):
    vy *= -1

the predictions will be slightly off.预测会略有偏差。

If you can change the core game, use如果您可以更改核心游戏,请使用

if y < 0:
    y *= -1
    vy *= -1
elif y > y_max:
    y = 2 * y_max - y
    vy *= -1

A divide by zero exception will be thrown if vx is 0, but since the ball will never hit a wall in this case, this should be handled by the ball movement logic.如果vx为 0,则会抛出divide by zero exception ,但由于在这种情况下球永远不会撞到墙壁,这应该由球运动逻辑处理。

Snippets are cool, but functions are better.片段很酷,但功能更好。 I can't prove this works, but it seems to.我无法证明这是可行的,但似乎可行。

float pong_get_ball_endpoint(float xpos, float ypos, float xspeed, float yspeed)
{
    // In the following, the fabs() mirrors it over the bottom wall.  The fmod wraps it when it exceeds twice
    // the top wall.  If the ball ends up in the top half of the double height section, we reflect it back 
    
    auto deltaX = (xspeed > 0) ? (BAT2_X - xpos) : -(xpos - BAT1_X);        // How far from ball to opponent bat
    auto slope = yspeed / xspeed;                                           // Rise over run, ie: deltaY per X
    float newY = fmod(fabs(ypos + deltaX * slope), (2 * MATRIX_HEIGHT));    // New Y, but wrappped every 2*height
    if (newY > MATRIX_HEIGHT)                                               // If in top half, reflect to bottom
        newY = 2 * MATRIX_HEIGHT - newY;
    return newY;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM