Processing 碰撞后反弹不起作用,对象剪辑穿过地形

Processing 碰撞后反弹不起作用,对象剪辑穿过地形,processing,game-physics,collision,Processing,Game Physics,Collision,编辑我将代码更改为下面的代码,但有时它仍然会在地形中剪辑。它也喜欢在应该滑落的角落反弹。 我试着为我正在做的一个小游戏实现我自己的碰撞。这是我的球类课程的代码 class Ball { //config float gforce = 1; float friction = 0.8; float elasticity = 0.5; //vars PVector position; PVector velocity = new PVector(0, 0); Ball

编辑我将代码更改为下面的代码,但有时它仍然会在地形中剪辑。它也喜欢在应该滑落的角落反弹。 我试着为我正在做的一个小游戏实现我自己的碰撞。这是我的球类课程的代码

class Ball {
  //config
  float gforce = 1;
  float friction = 0.8;
  float elasticity = 0.5;
  //vars
  PVector position;
  PVector velocity = new PVector(0, 0);

  Ball(PVector p) {position = p;}

  void render(){fill(255, 255, 0); noStroke(); circle(position.x, height-position.y, 16);}

  PVector bounce(PVector v, PVector n){  //calculate velocity after bounce
    PVector u = PVector.mult(n,v.dot(n)/n.dot(n));
    PVector w = PVector.sub(v, u);
    return PVector.sub(PVector.mult(w, friction), PVector.mult(u, elasticity));
  }
  Boolean intersect(PVector c, PVector p1, PVector p2, float r){
    if (c.dist(p1)<=r || c.dist(p2)<=r){return true;}
    float len = p1.dist(p2);
    float dot = ( ((c.x-p1.x)*(p2.x-p1.x)) + ((c.y-p1.y)*(p2.y-p1.y)) )/(len*len);
    PVector closest = PVector.add(p1, PVector.mult(PVector.sub(p2, p1), dot));
    float d1 = closest.dist(p1);
    float d2 = closest.dist(p2);
    if (d1+d2>=len-0.1 && d1+d2<=len+0.1){if(closest.dist(c)<=r){return true;}}
    return false;
  }
  Boolean intersect(PVector p1, PVector p2, PVector p3, PVector p4){  //if the line p1p2 intersects line p3p4
    float uA = ((p4.x-p3.x)*(p1.y-p3.y) - (p4.y-p3.y)*(p1.x-p3.x))/((p4.y-p3.y)*(p2.x-p1.x) - (p4.x-p3.x)*(p2.y-p1.y));
    float uB = ((p2.x-p1.x)*(p1.y-p3.y) - (p2.y-p1.y)*(p1.x-p3.x))/((p4.y-p3.y)*(p2.x-p1.x) - (p4.x-p3.x)*(p2.y-p1.y));
    if (uA>=0 && uA<=1 && uB>=0 && uB<=1){return true;}else{return false;}
  }

  void moveBall(){
    //if the ball is stationary
    if(velocity.mag()==0 || velocity.mag()==1 || velocity.mag()==2){
      PVector v = new PVector(min(280, max(-280, mX-mouseX)), min(280, max(-280, mouseY-mY))).div(28);
      int n = int(max(abs(v.x), abs(v.y)));
      v.normalize().mult(25);
      //render arrow
      if(mX!=0 && mousePressed){
        strokeWeight(5); stroke(#75D5FD); line(mX, mY, mouseX, mouseY);
        for (int i=0; i<n+1; i++){
          noStroke(); fill(510*(float)i/12, 510*(1-(float)i/12), 0, 55+200*(1-(float)i/12)); circle(mX+(v.x*i), mY-(v.y*i), 15);
        }
      }
      if(mX==0 && mouseP){mX=mouseX; mY=mouseY; mouseP=false;} 
      if(mX!=0 && mouseR){b.velocity = new PVector(min(280, max(-280, mX-mouseX)), min(280, max(-280, mouseY-mY))).div(8); mX=0; mouseR=false;}  //apply velocity
    }else {
      //if the ball is still, do not allow additional movement
      if(mX!=0 && mousePressed){stroke(200); line(mX, mY, mouseX, mouseY);}
      if(mX==0 && mouseP){mX=mouseX; mY=mouseY; mouseP=false;} 
      if(mX!=0 && mouseR){mX=0; mouseR=false;}
    }
  }

  void collision(){
    //test collision with terrain
    for (int i=1; i<l.points.length; i++){
      PVector centerout = PVector.div(velocity, velocity.mag()).mult(8);
      strokeWeight(5); stroke(255,0,0); line(position.x, height-position.y, position.x+centerout.x+velocity.x, height-position.y-centerout.y-velocity.y);
      if(intersect(position, l.points[i-1], l.points[i], 7) || intersect(position, PVector.add(position,velocity,centerout), l.points[i-1], l.points[i])){
        velocity = bounce(velocity, l.normals[i-1]);
      }
    }
  }

  void move() {
    moveBall();
    collision();
    position.add(velocity);
    if(velocity.y>-10){velocity.y-=gforce;}
    if(velocity.mag()<0.5){velocity.x=0; velocity.y=0;}
  }
}
班级舞会{
//配置
浮球力=1;
浮子摩擦力=0.8;
浮动弹性=0.5;
//瓦尔斯
PVector位置;
PVector速度=新PVector(0,0);
球(PVector p){position=p;}
void render(){fill(255,255,0);noStroke();circle(position.x,height-position.y,16);}
PVector反弹(PVector v,PVector n){//计算反弹后的速度
PVector u=PVector.mult(n,v.dot(n)/n.dot(n));
PVector w=PVector.sub(v,u);
返回PVector.sub(PVector.mult(w,摩擦力),PVector.mult(u,弹性));
}
布尔相交(PVector c、PVector p1、PVector p2、float r){

如果(c.dist(p1)关于您当前的问题,我实际上有两个不同的建议,我在考虑后决定只提供第一个,因为第二个建议可能会让您陷入递归疯狂,但如果需要,我愿意对此进行扩展。但是,如果没有工作示例,我无法真正测试它们或提供真正的代码,因此我将停留在伪代码级别

解决方案1:简单而健壮 这一点非常简单:保存反弹前向量。当球实际反弹时,如果反弹有剪切,则忽略它并反转初始向量。因为球来自这个确切的方向,所以你可以非常确定它可以以这种方式返回

算法将如下所示:

if ValidateMove(CurrentVector):
  Move(CurrentVector)
else:
  NewVector = CalculateNewVector
  if ValidateMove(NewVector):
    Move(NewVector)
  else:
    Move(CurrentVector.Invert)
不过,有一个可能存在问题的边缘情况。如果另一个物体在移动,它可能会阻挡球的反向路径。老实说,我不在乎发生这种情况的可能性,除非你的游戏特别容易发生这种情况


希望这会有所帮助!

您似乎在计算球相交时的碰撞。这可能是问题的一部分。一旦球位于与其碰撞的对象内,如果新向量在1帧内无法从中取出,您可能会遇到碰撞循环。我曾经在calc的类似arkanoid的程序中处理过类似的问题在碰撞发生之前就计算出碰撞的可能性。当以这种方式预测碰撞时,我分割运动,这样球就不会真正进入另一个物体,而是在它进入之前在它上面反弹,所以它们从来没有真正相交。上面的新代码应该解决这个问题。当我到达时,它仍然会通过剪辑非常接近一个角点并反弹到角点。新向量可能是这里的问题。如果没有正常移动的剪辑,但新向量没有验证,可能会导致此问题。顺便说一句,祝贺这一改进!非常感谢!我现在看到了问题,但我不知道如何解决它,因为程序将如果新的反弹速度发生碰撞,或者该速度的反弹速度发生碰撞等等,我必须无限向前看。你有什么建议吗?谢谢,我尝试过了,但问题仍然存在。我尝试过降低帧速率并逐帧查看,但我不知道为什么它只是剪辑。我应该继续发送我的全部代码吗ce我回家了吗?当然,我会看看我是否能帮上忙。非常感谢您抽出时间!我仍然不在家,但这是我的代码。我现在没有级别文件,但如果您将以下内容保存在/LevelEditor/levels.dat下,并将代码中的currentlevel更改为0,它应该加载:100200:800800:0150300150300100350100350150500,20500150,600150700300::::我让它工作起来了。我没有反转向量,而是简单地将速度设置为0,因为它在反复弹跳后最终将为0。这似乎解决了剪辑问题。还有一些其他问题,但我稍后会解决。我喜欢你跳过这个,而不是进入重新计算兔子洞。很好胡思乱想!