XNA冲突 - 对象重叠

时间:2014-01-07 13:14:38

标签: c# xna geometry rectangles collision

在我的程序中,我有一个管道,其中一些圆形颗粒从左向右移动。我应该能够在管道中放置一些障碍物并且必须找到颗粒 绕过它的方式。我试图通过碰撞来实现这一点。

我的问题是,有些粒子进入我的障碍物(管道也是一个障碍物)并留在那里。 Image

我的代码在每个更新周期运行如下:

public void CheckCollisions()
{
    // Variables
    bool blnCollisionOccured = false;
    Vector2 v2OldPosition;

    // Go through particles
    for (int i = 0; i < lstParticles.Count; i++)
    {
        // Move particle
        v2OldPosition = lstParticles[i].v2Position;
        lstParticles[i].v2Position += lstParticles[i].v2Speed;

        // Check all obstacles
        for (int j = 0; j < lstObstacles.Count; j++)
        {
            if (lstObstacles[j].GetType() == typeof(oRectangle))
            {
                blnCollisionOccured = CheckCollisionRectangle(lstParticles[i], (oRectangle)lstObstacles[j]);
            }
            else if (lstObstacles[j].GetType() == typeof(oCircle))
            {
                blnCollisionOccured = CheckCollisionCircle(lstParticles[i], (oCircle)lstObstacles[j]);
            }
            /* else if (lstObstacles[j].GetType() == typeof(oTriangle))
            {
                blnCollisionOccured = CheckCollisionTriangle(lstParticles[i], new oTriangle(lstObstacles[j]));
            } */
        }

        // Check all particles
        if (i != lstParticles.Count - 1)
        {
            for (int j = i + 1; j < lstParticles.Count; j++)
            {
                blnCollisionOccured = CheckCollisionParticle(lstParticles[i], lstParticles[j]);
            }
        }

        // If collision, go back and add new speed (no hanging inside objects)
        if (blnCollisionOccured)
        {
            lstParticles[i].v2Position = v2OldPosition;
            lstParticles[i].v2Position += lstParticles[i].v2Speed;
        }
    }
}

private bool CheckCollisionRectangle(Particle p, oRectangle o)
{
    // Check Collision
    if (p.GetRectancle().Intersects(o.GetRectangle()))
    {
        Vector2[] v2Corners = o.GetCorners();

        // Go through corners and check collision with corner
        for (int i = 0; i < v2Corners.Length; i++)
        {
            if (Vector2.Distance(p.GetCenterPoint(), v2Corners[i]) < p.GetRadius())
            {
                Vector2 normal = v2Corners[i] - p.GetCenterPoint();
                normal.Normalize();
                p.v2Speed = Vector2.Reflect(p.v2Speed, normal);
                return true;
            }
        }

        // Go through corners to check lines between 2 corners
        for (int i = 0; i < v2Corners.Length; i++)
        {
            // Save 2nd corner
            Vector2 v2Corner2;
            // If not last corner
            if (i != v2Corners.Length - 1)
            {
                // Next corner
                v2Corner2 = v2Corners[i + 1];
            }
            else
            {
                // First corner
                v2Corner2 = v2Corners[0];
            }

            // Check collision
            if (DistanceToLine(p.GetCenterPoint(), v2Corners[i], v2Corner2) <= p.GetRadius())
            {
                Vector2 normal = RightAngle(v2Corners[i] - v2Corner2);
                normal.Normalize();
                p.v2Speed = Vector2.Reflect(p.v2Speed, normal);
                return true;
            }
        }
    }
    return false;
}

private bool CheckCollisionCircle(Particle p, oCircle o)
{
    // Check Collision
    if (Vector2.Distance(p.GetCenterPoint(), o.GetCenterPoint()) <= p.GetRadius() + o.GetRadius())
    {
        Vector2 normal = o.GetCenterPoint() - p.GetCenterPoint();
        normal.Normalize();
        p.v2Speed = Vector2.Reflect(p.v2Speed, normal);

        return true;
    }
    return false;
}

private bool CheckCollisionParticle(Particle p1, Particle p2)
{
    // Check Collision
    if (Vector2.Distance(p1.GetCenterPoint(), p2.GetCenterPoint()) <= p1.GetRadius() + p2.GetRadius())
    {
        // Source: http://stackoverflow.com/questions/6216884/how-does-this-bouncing-off-object-after-collision-detection-code-work
        Vector2 cOfMass = (p1.v2Speed + p2.v2Speed) / 2;
        Vector2 normal1 = p2.GetCenterPoint() - p1.GetCenterPoint();
        normal1.Normalize();
        Vector2 normal2 = p1.GetCenterPoint() - p2.GetCenterPoint();
        normal2.Normalize();

        p1.v2Speed -= cOfMass;
        p1.v2Speed = Vector2.Reflect(p1.v2Speed, normal1);
        p1.v2Speed += cOfMass;

        p2.v2Speed -= cOfMass;
        p2.v2Speed = Vector2.Reflect(p2.v2Speed, normal2);
        p2.v2Speed += cOfMass;

        return true;
    }
    return false;
}

private Vector2 RightAngle(Vector2 v2)
{
    return new Vector2(v2.Y, -v2.X);
}

// Distance vector to line Source: http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
private double DistanceToLine(Vector2 point, Vector2 corner1, Vector2 corner2)
{
    // Source: http://geomalgorithms.com/a02-_lines.html
    //return ((corner1.Y - corner2.Y) * point.X + (corner2.X - corner1.X) * point.Y + (corner1.X * corner2.Y - corner2.X * corner1.Y)) / Math.Sqrt(Math.Pow(corner2.X - corner1.X, 2) + Math.Pow(corner2.Y - corner1.Y, 2));

    float l2 = Vector2.DistanceSquared(corner1, corner2);
    if (l2 == 0) return (float)Math.Sqrt(Vector2.DistanceSquared(point, corner1));
    float t = ((point.X - corner1.X) * (corner2.X - corner1.X) + (point.Y - corner1.Y) * (corner2.Y - corner1.Y)) / l2;
    if (t < 0) return (float)Math.Sqrt(Vector2.DistanceSquared(point, corner1));
    if (t > 1) return (float)Math.Sqrt(Vector2.DistanceSquared(point, corner2));
    return (float)Math.Sqrt(Vector2.DistanceSquared(point, new Vector2(corner1.X + t * (corner2.X - corner1.X), corner1.Y + t * (corner2.Y - corner1.Y))));
}

我希望你能以某种方式帮助我找到解决方案。

0 个答案:

没有答案