如何阻止二维刚体上的法向力太小? (Java 二维)
How to stop the normal force from being too small on a 2D rigidbody? (Java 2D)
我正在尝试使用 LWJGL 3 在 Java 中创建一个 2D 游戏引擎。目前对象只是带有盒子碰撞器的矩形。对于碰撞检测,我将矩形的边缘更改为具有 y = ax + b 结构的线。其中一个矩形具有刚体组件,使其能够移动并与环境交互。现在的想法是在开始时给刚体一个力,重力关闭,没有摩擦,并且完美反弹(弹性= 1)。一切都很好,直到它碰到一个没有垂直和水平边缘的矩形。我发现如果非刚体物体旋转 90 度或 180 度以外的角度,则法向力是错误的(太小),错误程度取决于旋转。刚体的旋转对问题没有贡献。
Vector2 rotSurface = new Vector2(-collision.surface.ToVector().y, collision.surface.ToVector().x).getNormalized();
System.out.println("Angle: "+Physics.Angle(rotSurface, rb.force));
Vector2 normalForce = rotSurface.multiplyBy(rotSurface.multiplyBy(rb.force).getMagnitude());
rb.force = rb.force.add(normalForce).multiplyBy(1f - rb.friction).add(normalForce.multiplyBy(rb.bounciness));
System.out.println("Angle: "+Physics.Angle(rotSurface, rb.force));
System.out.println("===");
我是不是在计算新的刚体力或法向力本身时做错了什么?如果您需要更多信息来帮助我解决这个问题,请询问。
我在上面的代码中使用的 类:
public class Collision {
Collider collider;
ArrayList<Vector2> contactPoints = new ArrayList<Vector2>();
Vector2 center = Vector2.zero;
Line surface;
public Collision(Collider collider, ArrayList<Vector2> contactPoints, Line surface) {
this.collider = collider;
this.contactPoints = contactPoints;
for(int i = 0; i < contactPoints.size(); i++) {
center = contactPoints.get(i).add(center).divideBy(2);
}
this.surface = surface;
}
}
class Line {
Vector2 begin, eind;
public float rc = 0;
public float b = 0;
public float x, y;
public boolean vertical = false;
public boolean horizontal = false;
public Line(Vector2 begin, Vector2 eind) {
this.begin = begin;
this.eind = eind;
if(begin.y == eind.y) {
this.y = begin.y;
this.horizontal = true;
}
else if(begin.x == eind.x){
this.x = begin.x;
this.vertical = true;
} else {
this.rc = (eind.y - begin.y) / (eind.x - begin.x);
this.b = GetB(rc, begin);
}
}
public float GetB(float rc, Vector2 punt) {
return punt.y - (rc * punt.x);
}
public Vector2 GetIntersection(Line l2) {
float x_ = rc - l2.rc;
if(vertical) {
x_ = x;
if(l2.horizontal) {
return new Vector2(x, l2.y);
}
else if(!l2.vertical){
//System.out.println("gert");
return new Vector2(x, l2.rc * x + l2.b);
}
} else if(horizontal) {
if(l2.vertical) {
return new Vector2(l2.x, y);
} else if(!l2.horizontal) {
return new Vector2((y-l2.b) / l2.rc, y);
}
} else {
if(l2.vertical) {
return new Vector2(l2.x, rc * l2.x + b);
} else if(l2.horizontal) {
return new Vector2((l2.y - b) / rc, l2.y);
}
}
if(x_ == 0) {
return null;
}
float getal = l2.b - b;
x_ = getal / x_;
float y_ = rc * x_ + b;
return new Vector2(x_, y_);
}
public Vector2 ToVector() {
return eind.substract(begin);
}
public float GetDisTo(Vector2 point) {
Vector2 point1 = begin.add(eind).divideBy(2);
return (float) Math.sqrt(Math.pow(point1.x - point.x, 2) + Math.pow(point1.y - point.y, 2));
}
public boolean Overlaps(Line line) {
if(horizontal && y == line.y) {
if(((line.begin.x > begin.x && line.begin.x < eind.x) || (line.eind.x > begin.x && line.eind.x < eind.x)) ||
((begin.x > line.begin.x && begin.x < line.eind.x) || (line.eind.x > line.begin.x && eind.x < line.eind.x)))
return true;
} else if(vertical && x == line.x) {
//return true;
}
return false;
}
}
class Vector2 {
float x, y;
public static Vector2 zero = new Vector2(0, 0);
public Vector2(float x, float y) {
this.x = x;
this.y = y;
}
public Vector2 multiplyBy(Vector2 vector) {
return new Vector2(x * vector.x, y * vector.y);
}
public Vector2 multiplyBy(float getal) {
return new Vector2(x * getal, y * getal);
}
public Vector2 divideBy(Vector2 vector) {
return new Vector2(x / vector.x, y / vector.y);
}
public Vector2 divideBy(float getal) {
return new Vector2(x / getal, y / getal);
}
public Vector2 add(Vector2 vector) {
return new Vector2(x + vector.x, y + vector.y);
}
public Vector2 substract(Vector2 vector) {
return new Vector2(x - vector.x, y - vector.y);
}
public float getMagnitude() {
return (float)Math.sqrt(x*x + y*y);
}
public Vector2 getNormalized() {
return divideBy(getMagnitude());
}
}
用鼻窦固定了它。
我替换了
Vector2 normalForce = rotSurface.multiplyBy(rotSurface.multiplyBy(rb.force).getMagnitude());
和
Vector2 normalForce = rotSurface.multiplyBy((float)Math.sin(Math.toRadians((double) (90f - Physics.Angle(rotSurface, force)))) * force.getMagnitude());
我正在尝试使用 LWJGL 3 在 Java 中创建一个 2D 游戏引擎。目前对象只是带有盒子碰撞器的矩形。对于碰撞检测,我将矩形的边缘更改为具有 y = ax + b 结构的线。其中一个矩形具有刚体组件,使其能够移动并与环境交互。现在的想法是在开始时给刚体一个力,重力关闭,没有摩擦,并且完美反弹(弹性= 1)。一切都很好,直到它碰到一个没有垂直和水平边缘的矩形。我发现如果非刚体物体旋转 90 度或 180 度以外的角度,则法向力是错误的(太小),错误程度取决于旋转。刚体的旋转对问题没有贡献。
Vector2 rotSurface = new Vector2(-collision.surface.ToVector().y, collision.surface.ToVector().x).getNormalized();
System.out.println("Angle: "+Physics.Angle(rotSurface, rb.force));
Vector2 normalForce = rotSurface.multiplyBy(rotSurface.multiplyBy(rb.force).getMagnitude());
rb.force = rb.force.add(normalForce).multiplyBy(1f - rb.friction).add(normalForce.multiplyBy(rb.bounciness));
System.out.println("Angle: "+Physics.Angle(rotSurface, rb.force));
System.out.println("===");
我是不是在计算新的刚体力或法向力本身时做错了什么?如果您需要更多信息来帮助我解决这个问题,请询问。
我在上面的代码中使用的类:
public class Collision {
Collider collider;
ArrayList<Vector2> contactPoints = new ArrayList<Vector2>();
Vector2 center = Vector2.zero;
Line surface;
public Collision(Collider collider, ArrayList<Vector2> contactPoints, Line surface) {
this.collider = collider;
this.contactPoints = contactPoints;
for(int i = 0; i < contactPoints.size(); i++) {
center = contactPoints.get(i).add(center).divideBy(2);
}
this.surface = surface;
}
}
class Line {
Vector2 begin, eind;
public float rc = 0;
public float b = 0;
public float x, y;
public boolean vertical = false;
public boolean horizontal = false;
public Line(Vector2 begin, Vector2 eind) {
this.begin = begin;
this.eind = eind;
if(begin.y == eind.y) {
this.y = begin.y;
this.horizontal = true;
}
else if(begin.x == eind.x){
this.x = begin.x;
this.vertical = true;
} else {
this.rc = (eind.y - begin.y) / (eind.x - begin.x);
this.b = GetB(rc, begin);
}
}
public float GetB(float rc, Vector2 punt) {
return punt.y - (rc * punt.x);
}
public Vector2 GetIntersection(Line l2) {
float x_ = rc - l2.rc;
if(vertical) {
x_ = x;
if(l2.horizontal) {
return new Vector2(x, l2.y);
}
else if(!l2.vertical){
//System.out.println("gert");
return new Vector2(x, l2.rc * x + l2.b);
}
} else if(horizontal) {
if(l2.vertical) {
return new Vector2(l2.x, y);
} else if(!l2.horizontal) {
return new Vector2((y-l2.b) / l2.rc, y);
}
} else {
if(l2.vertical) {
return new Vector2(l2.x, rc * l2.x + b);
} else if(l2.horizontal) {
return new Vector2((l2.y - b) / rc, l2.y);
}
}
if(x_ == 0) {
return null;
}
float getal = l2.b - b;
x_ = getal / x_;
float y_ = rc * x_ + b;
return new Vector2(x_, y_);
}
public Vector2 ToVector() {
return eind.substract(begin);
}
public float GetDisTo(Vector2 point) {
Vector2 point1 = begin.add(eind).divideBy(2);
return (float) Math.sqrt(Math.pow(point1.x - point.x, 2) + Math.pow(point1.y - point.y, 2));
}
public boolean Overlaps(Line line) {
if(horizontal && y == line.y) {
if(((line.begin.x > begin.x && line.begin.x < eind.x) || (line.eind.x > begin.x && line.eind.x < eind.x)) ||
((begin.x > line.begin.x && begin.x < line.eind.x) || (line.eind.x > line.begin.x && eind.x < line.eind.x)))
return true;
} else if(vertical && x == line.x) {
//return true;
}
return false;
}
}
class Vector2 {
float x, y;
public static Vector2 zero = new Vector2(0, 0);
public Vector2(float x, float y) {
this.x = x;
this.y = y;
}
public Vector2 multiplyBy(Vector2 vector) {
return new Vector2(x * vector.x, y * vector.y);
}
public Vector2 multiplyBy(float getal) {
return new Vector2(x * getal, y * getal);
}
public Vector2 divideBy(Vector2 vector) {
return new Vector2(x / vector.x, y / vector.y);
}
public Vector2 divideBy(float getal) {
return new Vector2(x / getal, y / getal);
}
public Vector2 add(Vector2 vector) {
return new Vector2(x + vector.x, y + vector.y);
}
public Vector2 substract(Vector2 vector) {
return new Vector2(x - vector.x, y - vector.y);
}
public float getMagnitude() {
return (float)Math.sqrt(x*x + y*y);
}
public Vector2 getNormalized() {
return divideBy(getMagnitude());
}
}
用鼻窦固定了它。 我替换了
Vector2 normalForce = rotSurface.multiplyBy(rotSurface.multiplyBy(rb.force).getMagnitude());
和
Vector2 normalForce = rotSurface.multiplyBy((float)Math.sin(Math.toRadians((double) (90f - Physics.Angle(rotSurface, force)))) * force.getMagnitude());