物理引擎中的摩擦力有帮助
好吧,我知道这是一个非具体问题,但我正在为类似于《愤怒的小鸟》的游戏制作 Verlet 集成物理引擎。我正在编写一个练习引擎只是为了了解它的要点(更简单的 C++ 版本的学分请参阅 Benedikt Bitterli),无论我做什么,我都无法弄清楚如何实现摩擦。我在下面发布了主要的碰撞和计算方法,如果有人至少可以告诉我应该在哪里或在哪种方法中添加一些东西以及技术或东西的名称。
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;
}
Ok i know this is sort of a non specific question but i am making a verlet integration physics engine for a game similar to, for example angry birds. I am writing a practice engine just to get the jist of it (credits for simpler c++ version go to Benedikt Bitterli) and no matter what i do i cant figure out how to implement friction. I posted the main collision and caluculation methods below if someone could at least tell me where or in which method i should add something and the name of the techneque or 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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
试试这个代码,底部世界边界上的摩擦力
对于每个粒子,限制水平运动。
try this code, friction on the bottom world boundary
for every particle, limit horizontal movement.