在我的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);
}
}
这有点乱,但它是我最接近体面碰撞的地方。如果能够快速找到碰撞点并应用正确的速度变化,那将会容易得多。