C#XNA - Ball&砖块连续碰撞检测

时间:2014-04-10 18:00:49

标签: c# xna collision breakout

在我的Breakout克隆中遇到砖块时,我在使用正确的速度变化时遇到了一些麻烦。在之前的一个问题中,我被建议使用连续碰撞检测,以及其他方法,例如在碰到角落时找到球和砖之间的交点,以确定球应该反射的方向。我已将这个应用到我的下面的代码中,但仍然有时候球会完全翻过一堆砖块。当它撞到移动的砖块时,这一点更加明显。

在Level.cs中更新方法:

Bricks.ForEach(brick => Balls.ForEach(ball => ball.Collide(brick)));

在Ball.cs中:

public bool Touching(Brick brick)
{
    var position = Position + (Velocity * Speed);
    return position.Y + Size.Y >= brick.Position.Y &&
              position.Y <= brick.Position.Y + brick.Size.Y &&
              position.X + Size.X >= brick.Position.X &&
              position.X <= brick.Position.X + brick.Size.X && brick.Health > 0 && brick.Lifespan == 1F;
}

public void Collide(Brick brick)
{
    if (!Touching(brick)) return;

    var position = Position + (Velocity * Speed);

    var bounds = new Rectangle((int)position.X, (int)position.Y, Texture.Width, Texture.Height);

    var nonCCDBounds = new Rectangle((int)Position.X, (int)Position.Y, Texture.Width, Texture.Height);

    if (bounds.Intersects(brick.Top) || bounds.Intersects(brick.Bottom))
    {
        var change = new Vector2(Velocity.X, -Velocity.Y);
        if (bounds.Intersects(brick.Left) || bounds.Intersects(brick.Right))
        {
            var intersection = Rectangle.Intersect(bounds, brick.Texture.Bounds);
            var nonCCDIntersection = Rectangle.Intersect(nonCCDBounds, brick.Texture.Bounds);
            if (intersection.Width < intersection.Height || nonCCDIntersection.Width < nonCCDIntersection.Height){
                change = new Vector2(-Velocity.X, Velocity.Y);
            }
        }
        if (bounds.Intersects(brick.Top))
        {
            if (level.GetBrick(new Vector2(brick.GridPosition.X, brick.GridPosition.Y - 1)) != null)
                change = new Vector2(-Velocity.X, Velocity.Y);
            else if ((Position - Velocity).Y > brick.Position.Y)
                change = new Vector2(-Velocity.X, Velocity.Y);
        }
        if (bounds.Intersects(brick.Bottom))
        {
            if (level.GetBrick(new Vector2(brick.GridPosition.X, brick.GridPosition.Y + 1)) != null)
                change = new Vector2(-Velocity.X, Velocity.Y);
            else if ((Position - Velocity).Y < brick.Position.Y + brick.Texture.Bounds.Height)
                change = new Vector2(-Velocity.X, Velocity.Y);
        }
        ReflectBall(brick, change);
        return;
    }

    if (bounds.Intersects(brick.Left) || bounds.Intersects(brick.Right))
    {
        var change = new Vector2(-Velocity.X, Velocity.Y);
        if (bounds.Intersects(brick.Top) || bounds.Intersects(brick.Bottom))
        {
            var intersection = Rectangle.Intersect(bounds, brick.Texture.Bounds);
            var nonCCDIntersection = Rectangle.Intersect(nonCCDBounds, brick.Texture.Bounds);
            if (intersection.Width > intersection.Height || nonCCDIntersection.Width > nonCCDIntersection.Height)
            {
                change = new Vector2(Velocity.X, -Velocity.Y);
            }
        }
        if (bounds.Intersects(brick.Left))
        {
            if (level.GetBrick(new Vector2(brick.GridPosition.X - 1, brick.GridPosition.Y)) != null)
                change = new Vector2(Velocity.X, -Velocity.Y);
            else if ((Position - Velocity).X > brick.Position.X)
                change = new Vector2(Velocity.X, -Velocity.Y);
        }
        if (bounds.Intersects(brick.Right))
        {
            if (level.GetBrick(new Vector2(brick.GridPosition.X + 1, brick.GridPosition.Y)) != null)
                change = new Vector2(Velocity.X, -Velocity.Y);
            else if ((Position - Velocity).X < brick.Position.X + brick.Texture.Bounds.Width)
                change = new Vector2(Velocity.X, -Velocity.Y);
        }
        ReflectBall(brick, change);
    }
}

public void ReflectBall(Brick brick, Vector2 reflection)
{
    Position = Position - Velocity;

    Velocity = reflection;

    if (brick.Health < 9)
    {
        brick.Health--;
        brick.Life --;
    }

    if (brick.Health > 0 && brick.Life > 0)
    {
        brick.Texture = Assets.GetBrick(brick.TextureName, brick.Health);
    }
}

这有点乱,但它是我最接近体面碰撞的地方。如果能够快速找到碰撞点并应用正确的速度变化,那将会容易得多。

0 个答案:

没有答案