Problem with balls that must collide each other

edited June 2015 in Questions about Code

I'm trying to make these balls collide each other, using the usual algorithms, and it works well, but, after a while, some of them hook the other ones and "swallow" the other ones.

Here is the code of the Ball class:

class Ball
{
  float x, y;
  int bx = 1, by = 1;
  int r;
  float xt, yt;
  float div = TWO_PI/360;
  float theta;
  color c = color(255,128);

  Ball(float x,float y,int r)
  {
    this.x = x;
    this.y = y;
    this.r = r;
    this.theta = div*random(0,359);

    this.xt = random(-1,1);
    this.yt = random(-1,1);
  }

  void move()
  {
    this.theta += div*random(-5,5)*4;

    //xt = sin(theta)*bx;
    //yt = cos(theta)*by;

    x += xt*bx; y += yt*by;

    if (x < r || x > (width-r))
      bx = -bx;
    if (y < r || y > (height-r))
      by = -by;
  }

  void collide(ArrayList<Ball> o)
  {
    for (int i=0;i<(o.size()-1);i++)
    {
      Ball b1 = o.get(i);
      for (int j=i+1;j<o.size();j++)
      {
        Ball b2 = o.get(j);
        float dx = b2.x - b1.x;
        float dy = b2.y - b1.y;
        float d = sqrt(dx*dx+dy*dy);

        if (d < ((float)b1.r+(float)b2.r))
        {

          float m1 = sqrt(sq(b1.xt)+sq(b1.yt));
          float m2 = sqrt(sq(b2.xt)+sq(b2.yt));
          b2.xt = (m1*dx/d);
          b2.yt = (m1*dy/d);
          b1.xt = -(m2*dx/d);
          b1.yt = -(m2*dy/d);
        }
      }
    }
  }

  void display()
  {
    ellipseMode(RADIUS);
    fill(c); noStroke();
    ellipse(x,y,r,r);
  }
}

Is something wrong in this code?

Answers

  • Code is lacking comments. The block at line 51 needs explaining. It's not obvious what you are trying to do.

    I think, without having run it, that the problem may involve the way you are checking all the balls against all the others whilst also updating them - ball a hits ball b and bounces and the new position means it hits ball c so it bounces back...

  • What you describe usually happens when balls are still overlapping on the next frame: this triggers another 'hit' which reverses their direction again, leaving them stuck. The usual solution is to reposition the balls so they're not overlapping when a collision is detected and then reversing speed.

    As @koogs says: the variables m1 and m2 do look odd...

  • edited June 2015

    @koogs: The algorithm I used is based on the one I found in a thread.

    EDIT: Also, I did something similar to GoToLoop's code, but, when they collide, they go really fast.

    This is the now edited class:

    class Ball
    {
      float x, y;
      int bx = 1, by = 1;
      int r;
      int ID;
      ArrayList<Ball> o;
    
      float xt, yt;
      float div = TWO_PI/360;
      float theta;
      color c = color(255,128);
      float spring = 0.01;
    
      Ball(float x,float y,int r,int ID)
      {
        this.x = x;
        this.y = y;
        this.r = r;
        this.ID = ID;
    
        this.theta = div*random(0,359);
        this.xt = random(-1,1);
        this.yt = random(-1,1);
      }
    
      void loadOthers(ArrayList<Ball> o)
      {
        this.o = new ArrayList<Ball>();
        for (int i=0;i<o.size();i++)
        {
          Ball aux = o.get(i);
          this.o.add(aux);
        }
      }
    
      void collide()
      {
        int k = this.ID+1;
        for (int i=k;i<o.size();i++)
        {
          Ball b = o.get(i);
          float bx = b.x, by = b.y;
          float dx = bx-this.x;
          float dy = by-this.y;
    
          float dist = sqrt(dx*dx+dy*dy);
          float md = (float)b.r+(float)this.r;
    
          if (dist >= md)
            continue;
    
          float ang = atan2(dy,dx);
          float tx = this.x + cos(ang)*md;
          float ty = this.y + sin(ang)*md;
          float ax = (tx-bx)*spring;
          float ay = (ty-by)*spring;
    
          this.xt -= ax; this.yt -= ay;
          b.xt += ax; b.yt += ay;
        }
      }
    
      void move()
      {
        //this.theta += div*random(-5,5)*4;
        //xt = sin(theta)*bx;
        //yt = cos(theta)*by;
    
        x += xt*bx; y += yt*by;
    
        if (x < r || x > (width-r))
          bx = -bx;
        if (y < r || y > (height-r))
          by = -by;
      }
    
      void display()
      {
        ellipseMode(RADIUS);
        fill(c); noStroke();
        ellipse(x,y,r,r);
      }
    }
    
  • Still no real use to us because we can't run it without the rest of the code.

Sign In or Register to comment.