我正在尝试进行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));
您只需按摩擦系数来缩放力。那不是摩擦的原理。您必须要么根据节点间速度(而不是距离)计算阻尼力,然后将其从弹力中减去,要么通过从弹力中减去固定量来施加静摩擦。