台球被困在彼此内

时间:2016-04-14 18:03:19

标签: java processing collision

我正在为我的Java课程设计一个台球游戏。我遇到了撞球碰撞的问题。球碰到了对方,偶尔相互滑动,卡住了。我似乎无法确定此错误的原因。我希望有人能帮助我找到问题的原因。我的代码如下。谢谢。

    float cueX = 200;
    float cueY = 225;
    float cueDeltaX;
    float cueDeltaY;
    float ballWidth = 25;
    float score = 0;

    Billiards[] billiards = new Billiards[3];

    void setup()
    {
      size (850, 450);
      background(0);
      fill(#29B748);
      rect(0, 0, 599, 599);
      billiards[0] = new Billiards(600, 225, 0, 0, false, "", 0);
      billiards[1] = new Billiards(625, 211, 0, 0, false, "", 1);
      billiards[2] = new Billiards(625, 239, 0, 0, false, "", 2);
      //billiards[3] = new Billiards(625, 250, 0, 0, false, "", 2);
    }

    void draw()
    { 
      background(0);
      fill(#FFFFFF);
      stroke(#A6A7A6);
      text("DeltaX: " + cueDeltaX + "  Delta Y: " + cueDeltaY, 20, 20);
      text(score, 500, 20);
      fill(#29B748);
      rect(25, 25, 799, 399);
      poolCueLines();
      drawCue();
      moveCue();
      cueBounce();
      cueFriction();

      drawBilliards();
      billiards[0].collision();
      billiards[0].moveBall();
      billiards[0].billiardBounce();
      billiards[0].billiardFriction();

      billiards[1].collision();
      billiards[1].moveBall();
      billiards[1].billiardBounce();
      billiards[1].billiardFriction();

      billiards[2].collision();
      billiards[2].moveBall();
      billiards[2].billiardBounce();
      billiards[2].billiardFriction();
    }

    void poolCueLines() {
      if (mousePressed)
      {
        stroke(#FFFFFF);
        line(cueX, cueY, mouseX, mouseY);
      }
    }

    void mouseReleased()
    {
      cueDeltaX = (cueX - mouseX)/50;
      cueDeltaY = (cueY - mouseY)/50;
    }

    void drawCue() {
      noStroke();
      fill(0);
      fill(#FFFFFF);
      stroke(#A6A7A6);
      ellipse(cueX, cueY, ballWidth, ballWidth);
      noFill();
    }

    void moveCue() {
      cueX += cueDeltaX;
      cueY += cueDeltaY;
    }

    void cueBounce() {
      if (cueX > width-25-ballWidth/2 || cueX < 25 + ballWidth/ 2) {
        cueDeltaX = -cueDeltaX;
        cueDeltaX = cueDeltaX * 0.6;
        if (cueX < 25+ ballWidth/2) {
          cueX = 26 + ballWidth/2;
        } else {
          cueX = width-26-ballWidth/2;
        }
      }

      if (cueY > height-25-ballWidth/2 || cueY < 25 + ballWidth/ 2) {
        cueDeltaY = -cueDeltaY;
        cueDeltaY = cueDeltaY * 0.6;
        if (cueY < 25+ ballWidth/2) {
          cueY = 26 + ballWidth/2;
        } else {
          cueY = height-26-ballWidth/2;
        }
      }
    }

    void drawBilliards() {

      //Yellow Ball 1
      fill(#ffff00);
      stroke(#A6A7A6);
      ellipse(billiards[0].ballXpos, billiards[0].ballYpos, ballWidth, ballWidth);

      //Blue 2
      fill(#000099);
      stroke(#A6A7A6);
      ellipse(billiards[1].ballXpos, billiards[1].ballYpos, ballWidth, ballWidth);

      //Red 3
      fill(#ff0000);
      stroke(#A6A7A6);
      ellipse(billiards[2].ballXpos, billiards[2].ballYpos, ballWidth, ballWidth);
    }

    void cueFriction() {
      cueDeltaX = cueDeltaX * 0.995;
      cueDeltaY = cueDeltaY * 0.995;
    }

    class Billiards
    {
      float ballXpos;
      float ballYpos;
      float deltaXball;
      float deltaYball;
      int billiardsNum;

      Billiards(float tempXpos, float tempYpos, float deltaXbill, float deltaYbill, boolean stripe, String stripeColor, int billiardNum) {
        ballXpos = tempXpos;
        ballYpos = tempYpos;
        deltaXball = deltaXbill;
        deltaYball = deltaYbill;
        billiardsNum = billiardNum;
      }

      void collision() {
        if (cueX > ballXpos-ballWidth && cueX < ballXpos+ballWidth) {
          if (cueY < ballYpos+ballWidth && cueY > ballYpos-ballWidth) {
            cueDeltaX = -cueDeltaX * 0.8;
            deltaXball = -cueDeltaX * 0.6;
            cueDeltaY = -cueDeltaY * 0.8;
            deltaYball = -cueDeltaY * 0.6;
          }
        }

        int ballNum = 0;
        for (int i=0; i < 3; i++) {
          if (billiards[ballNum].ballXpos > ballXpos-ballWidth && billiards[ballNum].ballXpos < ballXpos+ballWidth) {
            if (billiards[ballNum].ballYpos < ballYpos+ballWidth && billiards[ballNum].ballYpos > ballYpos-ballWidth) {
              if (billiardsNum == ballNum) {
              } else {
                //if (billiards[ballNum].deltaXball < 0.2 || billiards[ballNum].deltaYball < 0.2) {
                  if (deltaXball > 0){
                   billiards[ballNum].ballXpos += -3;
                  }else if (deltaXball < 0){
                   billiards[ballNum].ballXpos += 3;
                  }

                  if (deltaYball > 0){
                   billiards[ballNum].ballXpos += -3;
                  }else if (deltaYball < 0){
                   billiards[ballNum].ballXpos += 3;
                  }
                  billiards[ballNum].deltaXball = -billiards[ballNum].deltaXball * 0.8;
                  deltaXball = -billiards[ballNum].deltaXball * 0.6;
                  billiards[ballNum].deltaYball = -billiards[ballNum].deltaYball * 0.8;
                  deltaYball = -billiards[ballNum].deltaYball * 0.6;
                //}
                //} else {
                //  billiards[ballNum].deltaXball = -billiards[ballNum].deltaXball * 0.8;
                //  deltaXball = -billiards[ballNum].deltaXball * 0.6;
                //  billiards[ballNum].deltaYball = -billiards[ballNum].deltaYball * 0.8;
                //  deltaYball = -billiards[ballNum].deltaYball * 0.6;
                //}
              }
            }
          }
          ballNum += 1;
        }
      }

      void moveBall() {
        ballXpos += deltaXball;
        ballYpos += deltaYball;
      }

      void billiardBounce() {
        if (ballXpos > width-25-ballWidth/2 || ballXpos < 25 + ballWidth/ 2) {
          deltaXball = -deltaXball;
          deltaXball = deltaXball * 0.6;
          if (ballXpos < 25+ ballWidth/2) {
            ballXpos = 26 + ballWidth/2;
          } else {
            ballXpos = width-26-ballWidth/2;
          }
        }

        if (ballYpos > height-25-ballWidth/2 || ballYpos < 25 + ballWidth/ 2) {
          deltaYball = -deltaYball;
          deltaYball = deltaYball * 0.6;
          if (ballYpos < 25+ ballWidth/2) {
            ballYpos = 26 + ballWidth/2;
          } else {
            ballYpos = height-26-ballWidth/2;
          }
        }
      }

      void billiardFriction() {
        deltaXball = deltaXball * 0.995;
        deltaYball = deltaYball * 0.995;
      }
    }

1 个答案:

答案 0 :(得分:1)

嗯,问题在于你的碰撞代码。你在那里有很多神奇的硬编码数字,零评论描述了它们的用途。这将使调试变得非常困难,这很难帮助你。

但有一件事让我感到惊讶的是,你正在与运动分开处理碰撞。这可能没问题,但是你如何做到这一点,你可以让自己陷入这种境地:

  • 想象球A在球B和球C之间。
  • 球A向右移动。
  • 你检查球A的碰撞,它与球B碰撞。现在你告诉球A开始向左移动。
  • 然后你将球A移到左边,但是你没有检查是否会导致碰撞。所以现在球A和球C都在碰撞。
  • 球C向右移动,但是你检查它的碰撞。果然它会与球A碰撞,所以你要告诉它开始向左移动。
  • 现在球A和球C都向左移动,即使它们正在碰撞。

您可能希望仔细阅读并添加注释,直到您完全了解代码的作用。但老实说,这不是一个简单的问题。你可能最好从一个空白的草图开始,并从更简单的东西开始。尝试将问题缩小到MCVE。不要发布整个草图,只需将其缩小到特定情况,两个圆圈使用硬编码值而不是用户输入进行冲突。

您还可以查看Processing编辑器附带的CircleCollision示例。只需转到文件 - &gt;示例 - &gt;主题 - &gt;动作 - &gt; CircleCollision,您将看到一个草图,其中显示了处理圆碰撞的示例。

以下是该示例的碰撞代码:

void checkCollision(Ball other) {

    // get distances between the balls components
    PVector bVect = PVector.sub(other.position, position);

    // calculate magnitude of the vector separating the balls
    float bVectMag = bVect.mag();

    if (bVectMag < r + other.r) {
      // get angle of bVect
      float theta  = bVect.heading();
      // precalculate trig values
      float sine = sin(theta);
      float cosine = cos(theta);

      /* bTemp will hold rotated ball positions. You 
       just need to worry about bTemp[1] position*/
      PVector[] bTemp = {
        new PVector(), new PVector()
        };

        /* this ball's position is relative to the other
         so you can use the vector between them (bVect) as the 
         reference point in the rotation expressions.
         bTemp[0].position.x and bTemp[0].position.y will initialize
         automatically to 0.0, which is what you want
         since b[1] will rotate around b[0] */
        bTemp[1].x  = cosine * bVect.x + sine * bVect.y;
      bTemp[1].y  = cosine * bVect.y - sine * bVect.x;

      // rotate Temporary velocities
      PVector[] vTemp = {
        new PVector(), new PVector()
        };

        vTemp[0].x  = cosine * velocity.x + sine * velocity.y;
      vTemp[0].y  = cosine * velocity.y - sine * velocity.x;
      vTemp[1].x  = cosine * other.velocity.x + sine * other.velocity.y;
      vTemp[1].y  = cosine * other.velocity.y - sine * other.velocity.x;

      /* Now that velocities are rotated, you can use 1D
       conservation of momentum equations to calculate 
       the final velocity along the x-axis. */
      PVector[] vFinal = {  
        new PVector(), new PVector()
        };

      // final rotated velocity for b[0]
      vFinal[0].x = ((m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) / (m + other.m);
      vFinal[0].y = vTemp[0].y;

      // final rotated velocity for b[0]
      vFinal[1].x = ((other.m - m) * vTemp[1].x + 2 * m * vTemp[0].x) / (m + other.m);
      vFinal[1].y = vTemp[1].y;

      // hack to avoid clumping
      bTemp[0].x += vFinal[0].x;
      bTemp[1].x += vFinal[1].x;

      /* Rotate ball positions and velocities back
       Reverse signs in trig expressions to rotate 
       in the opposite direction */
      // rotate balls
      PVector[] bFinal = { 
        new PVector(), new PVector()
        };

      bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
      bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
      bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
      bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;

      // update balls to screen position
      other.position.x = position.x + bFinal[1].x;
      other.position.y = position.y + bFinal[1].y;

      position.add(bFinal[0]);

      // update velocities
      velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
      velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
      other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
      other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
    }
  }

您还可以查看上述示例的基于网络的版本: