我正在尝试进行2D绳索仿真,但是它的行为很奇怪,在运行时会跳来跳去。即使我有摩擦系数,它也永远不会安定下来,好像它永远不会失去动能。

public class Rope {

    private static final double FRICTION_COEF = 0.9;

    public double maxStretchLength;

    private Vec2D gravity = new Vec2D();
    private final List<Node> nodes = new ArrayList<>();

    public Rope(final int nodes, final int length, final Vec2D startingLocation) {
        for (int i = 0; i < nodes; i++) {
            final Node node = new Node();
            node.location = startingLocation;
            node.velocity = new Vec2D();
            if (i != 0) {
                node.above = getNodes().get(i - 1);
                getNodes().get(i - 1).below = node;
            }
            getNodes().add(node);
        }
        maxStretchLength = length / nodes;
    }

    public void draw(final Graphics g) {
        final int radius = 5;
        for (final Node n : getNodes()) {
            g.setColor(Color.RED);
            g.fillOval((int) n.location.x - radius, (int) n.location.y - radius, radius * 2, radius * 2);
            if (n.above != null) {
                g.setColor(Color.BLUE);
                g.drawLine((int) n.location.x, (int) n.location.y, (int) n.above.location.x, (int) n.above.location.y);
            }
        }
    }

    public void update() {
        for (final Node n : getNodes()) {
            Vec2D force = gravity;

            if (!n.isFixed()) {
                force = force.plus(n.above.location.minus(n.location).multiply(FRICTION_COEF));
                // equal and opposite force
                if (!n.above.isFixed()) {
                    n.above.velocity = n.above.velocity.plus(force.multiply(-1));
                }
            }

            n.velocity = n.velocity.plus(force);
            if (n.isFixed()) {
                n.velocity = new Vec2D(0, 0);
            }
        }
        for (final Node n : getNodes()) {
            n.location = n.location.plus(n.velocity);
        }
    }

    public void applyGravity(final Vec2D v) {
        gravity = gravity.plus(v);
    }

    public List<Node> getNodes() {
        return nodes;
    }

    public static class Node {
        public Vec2D location;
        public Vec2D velocity;
        public Node above;
        public Node below;

        public double distance(final Node other) {
            return other.location.distance(location);
        }

        public boolean isFixed() {
            return above == null;
        }
    }
}
public class Vec2D extends Point2D.Double {

    /*
     * (non-Javadoc)
     *
     * @see java.awt.geom.Point2D.Double#Point2D.Double()
     */
    public Vec2D() {
    super();
    }

    /*
     * (non-Javadoc)
     *
     * @see java.awt.geom.Point2D.Double#Point2D.Double()
     */
    public Vec2D(final double x, final double y) {
    super(x, y);
    }

    /**
     * Copy constructor
     */
    public Vec2D(final Vec2D v) {
    x = v.x;
    y = v.y;
    }

    /**
     * @return the radius (length, modulus) of the vector in polar coordinates
     */
    public double getR() {
    return Math.sqrt(x * x + y * y);
    }

    /**
     * @return the angle (argument) of the vector in polar coordinates in the
     *         range [-pi/2, pi/2]
     */
    public double getTheta() {
    return Math.atan2(y, x);
    }

    /*
     * (non-Javadoc)
     *
     * @see java.awt.geom.Point2D.Double#setLocation(double, double)
     */
    public void set(final double x, final double y) {
    super.setLocation(x, y);
    }

    /**
     * Sets the vector given polar arguments.
     *
     * @param r
     *            The new radius
     * @param t
     *            The new angle, in radians
     */
    public void setPolar(final double r, final double t) {
    super.setLocation(r * Math.cos(t), r * Math.sin(t));
    }

    /** Sets the vector's radius, preserving its angle. */
    public void setR(final double r) {
    final double t = getTheta();
    setPolar(r, t);
    }

    /** Sets the vector's angle, preserving its radius. */
    public void setTheta(final double t) {
    final double r = getR();
    setPolar(r, t);
    }

    /** The sum of the vector and rhs */
    public Vec2D plus(final Vec2D rhs) {
    return new Vec2D(x + rhs.x, y + rhs.y);
    }

    /** The difference of the vector and rhs: this - rhs */
    public Vec2D minus(final Vec2D rhs) {
    return new Vec2D(x - rhs.x, y - rhs.y);
    }

    public boolean equals(final Vec2D rhs) {
    return x == rhs.x && y == rhs.y;
    }

    /** Product of the vector and scalar */
    public Vec2D multiply(final double scalar) {
    return new Vec2D(scalar * x, scalar * y);
    }

    /** Dot product of the vector and rhs */
    public double dotProduct(final Vec2D rhs) {
    return x * rhs.x + y * rhs.y;
    }

    /**
     * Since Vector2D works only in the x-y plane, (u x v) points directly along
     * the z axis. This function returns the value on the z axis that (u x v)
     * reaches.
     *
     * @return signed magnitude of (this x rhs)
     */
    public double crossProduct(final Vec2D rhs) {
    return x * rhs.y - y * rhs.x;
    }

    /** Product of components of the vector: compenentProduct( <x y>) = x*y. */
    public double componentProduct() {
    return x * y;
    }

    /** Componentwise product: <this.x*rhs.x, this.y*rhs.y> */
    public Vec2D componentwiseProduct(final Vec2D rhs) {
    return new Vec2D(x * rhs.x, y * rhs.y);
    }

    /**
     * An alias for getR()
     *
     * @return the length of this
     */
    public double length() {
    return getR();
    }

    /**
     * Returns a new vector with the same direction as the vector but with
     * length 1, except in the case of zero vectors, which return a copy of
     * themselves.
     */
    public Vec2D unitVector() {
    double length = getR();
    if (length != 0)
        return new Vec2D(x / length, y / length);
    return new Vec2D(0, 0);
    }

    /** Polar version of the vector, with radius in x and angle in y */
    public Vec2D toPolar() {
    return new Vec2D(Math.sqrt(x * x + y * y), Math.atan2(y, x));
    }

    /** Rectangular version of the vector, assuming radius in x and angle in y */
    public Vec2D toRect() {
    return new Vec2D(x * Math.cos(y), x * Math.sin(y));
    }

    /** @return Standard string representation of a vector: "<x, y>" */
    @Override
    public String toString() {
    return "<" + x + ", " + y + ">";
    }
}

最佳答案

force.plus(n.above.location.minus(n.location).multiply(FRICTION_COEF));

您只需按摩擦系数来缩放力。那不是摩擦的原理。您必须要么根据节点间速度(而不是距离)计算阻尼力,然后将其从弹力中减去,要么通过从弹力中减去固定量来施加静摩擦。

09-25 20:58