26

在实现 Pacman 和 Snake 之后,我正在实现下一个非常经典的游戏:Pong。

实现非常简单,但我只剩下一个小问题。当其中一个桨(我不确定它是否称为桨)由计算机控制时,我很难将它定位在正确的位置。

球有一个当前位置、一个速度(现在是恒定的)和一个方向角。所以我可以计算出它会碰到电脑控制的桨的位置。所以我可以把桨放在那里。但是在真正的比赛中,电脑的球拍有可能会错过球。我怎样才能实现这个概率?

如果我只使用计算机的球拍击球的概率假设为 0.5,那么问题就解决了,但我认为并不是那么简单。

从最初的游戏来看,我认为概率取决于当前桨位置与球击中边界的位置之间的距离。

有人知道这是如何计算的吗?

4

7 回答 7

31

引用非常有趣的书“Racing the Beam”(Google 图书: http: //books.google.co.uk/books ?id=DqePfdz_x6gC&lpg=PP1&dq=racing%20the%20beam&pg=PA40#v=onepage&q&f=false )原始技术是:

为了帮助模拟精确桨定位中固有的人为错误,人工智能桨每八帧跳过一次调整。由此产生的行为是明显不明显的,但它允许计算机玩家的目标漂移到足以使其偶尔错过球。它在技术上实现起来也很简单,只需要一个掩码和二进制 AND 操作,为此存在相应的 6502 指令。程序员可以使用另一个单独的操作码测试结果是否为零,如果需要则进行分支以跳过移动桨的指令。

即使是这种行为也必须稍作修改才能使游戏完全正常运行。如果 AI 球员每 8 帧就停止跟踪球,那么它会在几秒钟内失去同步,这是无可救药的。为了防止这种情况发生,AI 在球场顶部和底部附近遵循辅助球跟踪方案。如果球与其中一个墙壁发生碰撞,而桨也与之对齐,则桨会重新调整,从球上次撞击墙壁以来积累的任何漂移中恢复。结果是计算机桨和球的随机错位和重新对准。

于 2011-01-02T10:50:50.087 回答
22

我们为我们的高中 CS 课制作了一个(伪)3D 乒乓球游戏。我们所做的是,我们让计算机始终将球拍向球移动,但以最大速度移动——这样,如果球太远,它可能会错过球,但它仍然很聪明。这有帮助吗?

于 2011-01-02T09:29:32.583 回答
5

我认为您应该让桨始终从其当前位置移动到特定点,这将是预计球与桨垂直对齐的位置。然后,您可能有 50% 的机会让球拍移动到这个确切的点并偏转球,有 25% 的机会它会过冲,可能会超过一些 X 像素,还有 25% 的机会会过冲。一个更好的方法可能是让它移动到钟形曲线上的那个位置,这样它每次都会错过不同的数量。

于 2011-01-02T09:24:42.613 回答
5

其他答案讨论了如何在不同的情况下决定正确的前进方向。您还可以通过开始朝这个方向移动来在计算机玩家“做出反应”之前添加延迟时间——这反映了人类玩家的典型反应。

于 2011-01-02T09:48:50.760 回答
4

我不确定这样做的“官方”方式是什么,但我一直只是使用(伪代码)

if (ball is above paddle) {
    move paddle up
}
if (ball is below paddle) {
    move paddle down
}

然后我给了桨一个稍微变化的速度,这个速度足够慢,以至于它不能总是跟上球。有点粗糙,但它有效。

这个线程也有一些你可能想看看的有趣想法:http ://www.gamedev.net/community/forums/topic.asp?topic_id=439576

于 2011-01-02T09:35:41.077 回答
4

碰巧我前几天写了一个乒乓克隆只是为了好玩。

您可以在此处播放并此处查看源代码。

AI 获取球的当前速度并将距离墙的 x 距离相乘。然后,它以上限速度向计算出的位置移动。它不考虑垂直反弹,但这是有意的(使 AI 可击败)。

这是相关的片段:

/* Update enemy based on simple AI */
enemy.update = function (delta) {
    var impactDistance, impactTime, targetY, speed;
    speed = .25; // a little slower than the human player

    if (ball.vx < 0) {
        // Ball is moving away, AI takes a nap ..
        return;
    }

    // Figure out linear trajectory ..
    impactDistance = width - ball.width - ball.x;
    impactTime = impactDistance / (ball.vx * .25 * 1000);
    targetY = ball.y + (ball.vy * .25 * 1000) * impactTime;

    if (Math.abs(targetY - (this.y + this.height/2)) < 10) {
        // AI doesn't need to move
        return;
    }

    if (targetY < this.y + (this.height / 2)) {
        // Move up if ball is going above paddle
        speed = -speed;
    }

    this.y += speed * delta;
    this.keepInBounds();
};
于 2011-01-02T15:34:38.387 回答
2

经过几次迭代后,如果您的桨(即您的桨或 AI 取决于您的视角)太靠近屏幕的顶部或底部,则根本不可能覆盖所需的距离。桨可以很容易地跟随球的 y 值。如果你太远,你会错过。

或者,您可以在每次击球后将 AI 重置为中心,或者只要球在远离(即朝向对手)移动,就向中心移动

或更简单地说:
- 在球离开时向中心移动 - 在球接近时模仿球的 y 坐标。

从这里您可以通过使 y 坐标模仿机制比球慢(更一致,可能是原始实现的样子;因为困难被抽象为简单的速度系数)来改变难度,或者为每个动作添加随机误差或除此以外。

于 2011-01-02T09:35:37.437 回答