物理引擎中的摩擦有帮助

时间:2011-06-08 01:42:40

标签: java collision-detection physics

好吧我知道这是一个非特定的问题,但我正在为一个类似于愤怒的小鸟的游戏制作一个verlet集成物理引擎。我正在编写一个练习引擎,只是为了获得它的精神(更简单的c ++版本归功于Benedikt Bitterli),无论我做什么,我都无法弄清楚如何实现摩擦。我发布了下面的主要碰撞和计算方法,如果有人至少可以告诉我应该在哪里或在哪种方法中添加一些东西以及技术名称或者somthing。

private void updateVerlet() {
    float tempX;
    float tempY;

    for (int b = 0; b < bodies.size(); b++) {
        for (int i = 0; i < bodies.get(b).vertices.size(); i++) {
            Vertex v = bodies.get(b).vertices.get(i);
            tempX = v.x;
            tempY = v.y;
            v.x += v.x - v.ox + v.accx * timestep * timestep;
            v.y += v.y - v.oy + v.accy * timestep * timestep;
            v.ox = tempX;
            v.oy = tempY;
        }
    }
}



private void updateEdges() {
    for (int b = 0; b < bodies.size(); b++) {
        for (int i = 0; i < bodies.get(b).edges.size(); i++) {
            Edge e = bodies.get(b).edges.get(i);

            float distX = e.v2.x - e.v1.x;
            float distY = e.v2.y - e.v1.y;

            float dist = (float)Math.hypot(distX, distY);
            float diff = dist - e.length;

            float len = 1f / (float)Math.hypot(distX, distY);// Normalize with (float)Math.hypot(distX, distY); again????
            distX *= len;
            distY *= len;

            e.v1.x += distX * diff * 0.5;
            e.v1.y += distY * diff * 0.5;
            e.v2.x -= distX * diff * 0.5;
            e.v2.y -= distY * diff * 0.5;
        }
    }
}
private void iterateCollisions() {
    for (int iteration = 0; iteration < iterations; iteration++) {

        // Temporary solution to prevent bodies from falling out of the screen
        for (int b = 0; b < bodies.size(); b++) {
            for (int i = 0; i < bodies.get(b).vertices.size(); i++) {
                bodies.get(b).vertices.get(i).x = Math.max(Math.min(bodies.get(b).vertices.get(i).x, (float)screenWidth), 0.0f);
                bodies.get(b).vertices.get(i).y = Math.max(Math.min(bodies.get(b).vertices.get(i).y, (float)screenHeight), 0.0f);
            }
        }

        updateEdges();

        for (int b = 0; b < bodies.size(); b++) {
            bodies.get(b).calculateCenter();
        }

        for (int b1 = 0; b1 < bodies.size(); b1++) {
            for (int b2 = 0; b2 < bodies.size(); b2++) {
                if (bodies.get(b1) != bodies.get(b2)) {
                    if (bodiesOverlap(bodies.get(b1), bodies.get(b2))) {
                        if (detectCollision(bodies.get(b1), bodies.get(b2))) {
                            processCollision();
                        }
                    }
                }
            }
        }

    }
}
private boolean bodiesOverlap(PhysicsBody b1, PhysicsBody b2) {
    return
    (b1.minX <= b2.maxX) &&
    (b1.minY <= b2.maxY) &&
    (b1.maxX >= b2.minX) &&
    (b2.maxY >= b1.minY);
}

private boolean detectCollision(PhysicsBody b1, PhysicsBody b2) {
    float minDistance = 10000.0f;
    Edge e;

    for (int i = 0; i < b1.edges.size() + b2.edges.size(); i++) {
        if (i < b1.edges.size()) {
            e = b1.edges.get(i);
        } else {
            e= b2.edges.get(i - b1.edges.size());
        }

        if (!e.boundary)
            continue;

        axis.x = e.v1.y - e.v2.y;
        axis.y = e.v2.x - e.v1.x;

        float len = 1f / (float)Math.hypot(axis.x, axis.y);
        axis.x *= len;
        axis.y *= len;

        MinMax dataA = b1.projectToAxis(axis);
        MinMax dataB = b2.projectToAxis(axis);

        float distance = intervalDistance(dataA, dataB);

        if (distance > 0f)
            return false;
        else if (Math.abs(distance) < minDistance) {
            minDistance = Math.abs(distance);

            CollisionInfo.normalX = axis.x;
            CollisionInfo.normalY = axis.y;
            CollisionInfo.e = e;
        }
    }

    CollisionInfo.depth = minDistance;

    if (CollisionInfo.e.parent != b2) {
        PhysicsBody temp = b2;
        b2 = b1;
        b1 = temp;
    }

    float diffX = b1.centerX - b2.centerX;
    float diffY = b1.centerY - b2.centerY;
    float mult = CollisionInfo.normalX * diffX + CollisionInfo.normalY * diffY;

    if (mult < 0) {
        CollisionInfo.normalX = 0 - CollisionInfo.normalX;
        CollisionInfo.normalY = 0 - CollisionInfo.normalY;
    }

    minDistance = 10000.0f;

    for (int i = 0; i < b1.vertices.size(); i++) {
        diffX = b1.vertices.get(i).x - b2.centerX;
        diffY = b1.vertices.get(i).y - b2.centerY;
        float distance = CollisionInfo.normalX * diffX + CollisionInfo.normalX * diffY;

        if (distance < minDistance) {
            minDistance = distance;
            CollisionInfo.v = b1.vertices.get(i);
        }
    }
    return true;
}

private void processCollision() {
    Vertex v1 = CollisionInfo.e.v1;
    Vertex v2 = CollisionInfo.e.v2;

    float collisionVectorX = CollisionInfo.normalX * CollisionInfo.depth;
    float collisionVectorY = CollisionInfo.normalY * CollisionInfo.depth;

    float t;
    if (Math.abs(v1.x - v2.x) > Math.abs(v1.y - v2.y)) {
        t = (CollisionInfo.v.x - collisionVectorX - v1.x) / (v2.x - v1.x);
    }
    else {
        t = (CollisionInfo.v.y - collisionVectorY - v1.y) / (v2.y - v1.y);
    }

    float lambda = 1.0f / (t * t + (1 - t) * (1 - t));
    float edgeMass = t * v2.parent.mass + (1f - t) * v1.parent.mass;
    float invCollisionMass = 1.0f / (edgeMass + CollisionInfo.v.parent.mass);

    float ratio1 = CollisionInfo.v.parent.mass * invCollisionMass;
    float ratio2 = edgeMass*invCollisionMass;

    v1.x -= collisionVectorX * ((1 - t) * ratio1 * lambda);
    v1.y -= collisionVectorY * (( 1 - t) * ratio1 * lambda);
    v2.x -= collisionVectorX * (t * ratio1 * lambda);
    v2.y -= collisionVectorY * (t * ratio1 * lambda);

    CollisionInfo.v.x += collisionVectorX * ratio2;
    CollisionInfo.v.y += collisionVectorY * ratio2;
}

1 个答案:

答案 0 :(得分:0)

尝试此代码,摩擦底部世界边界 对于每个粒子,限制水平移动。

if(Particle.Y >= world_height) { Particle.OldX = Particle.OldX - (Particle.OldX - Particle.X)/2; }