包围矩形碰撞-球从球拍错误的一侧跳出

5
我正在制作一个乒乓球游戏,但遇到了一个问题。当球(一个矩形)与球拍(或球棒)在下面或上面发生碰撞时,会出现一个奇怪的错误:球会进入矩形并左右移动,速度越来越快(因为我添加了加速度),最后从相反的一侧弹出。我知道这个错误出现的原因:
if (ballrec.Intersects(player1rec)
        && ball.x <= 20
        && ball.y + 20 >= player.y
        && ball.y <= player.y + 100) //checks the front rebound-here's the bug
{
    ball.vx *= -1; //changes x-direction
    if (ball.vx < 0)
        ball.vx -= 1; //increases x-velocity
    effect.Play();
    if (R.Next(4) == 0)
    {
        if (ball.vy < 0) ball.vy--;
        else ball.vy++; //increases y-velocity on a special occasion
    }
}
else
{
    if (ballrec.Intersects(player1rec))
    {
        ball.vy *= -1;
        effect.Play();
    }
}

球的vy代表速度y轴方向的值,我将其乘以-1来改变方向。

效果为声音。

问题在于:为了使球在球拍前的任何位置反弹,代码表示球的下侧(即+20)不能高于球拍的上侧,而球的上侧不能低于球拍的下侧。但是由于x坐标(ball.x<=20,20为球拍的宽度),前面的反弹效果使用了球拍的上下两侧,因此无法工作。

我尝试解决它,我的最佳简单解决方案(因为明年我就要开始初中了,不会很多高深数学知识)没有得到好的解决方案(请查看下面)。

我的解决方案(我不满意):我降低了需要前面反弹的区域,即 ball.y>=player.y 且 ball.y+20<=player.y+100(长度),这样上下反弹就可以了,但如果球撞击球拍的角落,同样的问题就出现了,此时球会上下移动。

我的问题是:如何解决这个问题?

谢谢你的时间!希望这不算太长!

目前的解决方案(不完美):

if (ballrec.Intersects(player1rec)
        && ball.x <= 20
        && ball.y >= player.y
        && ball.y + 20 <= player.y + 100)
{
    ball.vx *= -1;
    if (ball.vx < 0)
        ball.vx -= 1;
    effect.Play();
    if (R.Next(4) == 0)
    {
        if (ball.vy < 0) ball.vy--;
        else ball.vy++;
    }
}
else
{
    if (ballrec.Intersects(player1rec))
    {
        ball.vy *= -1;
        effect.Play();
    }
}

这是一个矩形“跳过”另一个的情况 - 然后在新位置进行命中检测。处理此交互的简单方法是使用球的运动向量和挡板进行线多边形相交测试。 - user2864740
如果需要上传任何东西,比如图片、视频或更多的代码,我愿意这样做! - TheGeniusDev
谢谢您的快速回复,但是简单地说,我不知道怎么做:D 您能否请发一个链接让我学习一下呢? - TheGeniusDev
2
这个有帮助吗:http://stackoverflow.com/questions/21238792/java-pong-ball-glides-on-paddle - Goose
简而言之,您的错误发生是因为在检测到碰撞后,存在无法解决碰撞的情况。您需要确保在再次执行结果代码路径之前解决碰撞。相关的,在gamedev.se上:http://gamedev.stackexchange.com/questions/54603/breakout-style-ball-paddle-bounce-error-at-corner/54608#54608 - Seth Battin
显示剩余6条评论
1个回答

0

解决方案1:检查速度向量

一个解决方案是考虑运动速度向量的方向(ball.vx)。 如果速度为负(即朝左移动),则允许player1翻转球的x速度,反之亦然。 如果这是一个简单的乒乓球游戏,则完全可以这样做:

// Player 1
if (ballrec.Intersects(player1rec)
    && ball.x <= 20
    && ball.y >= player.y
    && ball.y + 20 <= player.y + 100
    && ball.vx <= 0 ) //<--- Here
{
// .....
}

// Player 2
if (ballrec.Intersects(player2rec)
    // ....
    && ball.vx >= 0 ) //<--- Here
{
// .....
}

方案二:保存小球的碰撞状态

另一种解决方法是保存当前的碰撞状态(碰撞或未碰撞),并且只有在状态从未碰撞切换到碰撞时才翻转速度:

public class Ball
{
    public bool colliding = false;
}

//In Update of Ball/Game
bool player1Collision = ballrec.Intersects(player1rec)
    && ball.x <= 20
    && ball.y >= player.y
    && ball.y + 20 <= player.y + 100;
if( player1Collision && !ball.colliding )
{
    // Set state here, so reduce issues when there is a chance that different players can overlap
    ball.colliding = true;
    // .....
}

// Same for player 2,3,4,5 .....

//Update state for next frame
ball.colliding = player1Collision || player2Collision /* .... */;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接