2
votes

I am creating a project of bouncing balls.

The only problem with my project is with collision resolution when two balls intersect with each other.Collision detection is fine as when two balls intersect they bounce back but then they keep colliding again and again.When the balls collide with the walls they bounce correctly but I don't know why when they collide with each other there is a problem.

I have tried various code but still can't get it.

How can i do this ?

You can take help of this link as did I..

Ball to Ball Collision - Detection and Handling

Here is my code :

package com.example.bouncer;


import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.provider.SyncStateContract.Constants;
public class Ball {

private Point p;   //Point p:Represents the x and y position of the Ball
private int c;     //Represents the color of the Ball
private int r;      //Represents the Radius of the Ball.
private int dx;             //Integer dx:Represents the change in x position of ball  
                            // Integer dy:Represents the change in y position of ball
private int dy;
private Paint paint;      //Android Object holding the color for drawing on the canvas
public Ball(int x,int y,int col,int radius)
{
    p=new Point(x,y);
    c=col;
    r=radius;
    paint=new Paint();
    dx=0;
    dy=0;
}
public int getX()
{return p.x;
}
public int getY()
{
    return p.y;
}
public int getRadius()
{return r;
}
public Paint getPaint()
{return paint;
}
public void setColor(int col)
{c=col;
}
public void goTo(int x,int y)
{p.x=x;
p.y=y;
}
public void setDX(int speed)
{dx=speed;
}
public void setDY(int speed)
{
    dy=speed;
}
public void move()
{
    p.x=p.x+dx;
    p.y=p.y+dy;
}
public void bounce(Canvas canvas)       //COLLISION DETECTION AND RESOLUTION WITH WALLS
{
    move();
    if(p.x>canvas.getWidth()|| p.x<0)
    {

        dx=dx * -1;
    }
    if(p.y>canvas.getWidth()|| p.y<0)
    {

        dy=dy * -1;
    }


    }


    public void bounceoff(Ball b)          //BALL TO BALL COLLSION DETECTION
    {
       float x = b.getX() - p.x;
       float y = b.getY() - p.y;
       float distanceSquared = x*x + y*y;
       float radius = b.getRadius()+r;
       float radiusSquared = radius*radius;
       if (distanceSquared <= radiusSquared)
       {
            dx=dx * -1;
            dy=dy * -1;

       }
    }
}

AnimationView.java

package com.example.bouncer;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
public class AnimationView extends View{
  private final int FRAME_RATE=15;
  private Paint paint;
  private Handler h;
  Ball myball;
  Ball greenball;
  Ball redball;
    public AnimationView(Context context,AttributeSet attrs) {
        super(context,attrs);
        // TODO Auto-generated constructor stub
        h=new Handler();
        paint=new Paint();
        paint.setColor(Color.BLUE);
        myball=new Ball(100,100,Color.BLUE,50);
        greenball=new Ball(200,200,Color.GREEN,50);
        redball=new Ball(50,400,Color.RED,50);
        myball.setDX(10);
        myball.setDY(10);
        greenball.setDX(-20);
        greenball.setDY(-15);
        redball.setDX(5);
        redball.setDY(-5);

    }
    protected void onDraw(Canvas c)
    {
        myball.bounce(c);
        greenball.bounce(c);
        redball.bounce(c);
        myball.bounceoff(myball);
        greenball.bounceoff(greenball);
        redball.bounceoff(redball);
        c.drawCircle(myball.getX(), myball.getY(),myball.getRadius(), myball.getPaint());
        c.drawCircle(greenball.getX(), greenball.getY(),greenball.getRadius(), greenball.getPaint());
        c.drawCircle(redball.getX(), redball.getY(),redball.getRadius(), redball.getPaint());

        h.postDelayed(r, FRAME_RATE);

    }
    private Runnable r=new Runnable()
    { public void run()
    { invalidate();
    }
    };
    }

If you want my complete project code check out the link.. https://stackguides.com/questions/22892736/balls-keep-colliding-again-and-again-android

4
If you want my complete project code check out the link... stackoverflow.com/questions/22892736/…user3503165

4 Answers

0
votes

I think that you can get false collisions with the criteria you use to detect ball to ball collision. If AB is the vector between the centers of balls A and B and rA is the radius of A and rB the radius of B then you can use this criteria to check if the balls collide

|AB| < rA + rB

Where |AB| means the length of the vector AB

An optimized way to calculate this (avoiding the costly square root calculation) is

int xDiff = b.getX()-p.x;
int yDiff = b.getY()-p.y;
int radii = b.getRadius() + r;
if ( ( xDiff * xDiff + yDiff * yDiff ) < radii * radii ) {
    // Collision response. Change the balls velocity

Also, a couple of side notes.

  1. I think it would be best to take move out of bounce so that you first move all the balls and then check if any of them collodied either with another ball or with a wall.

  2. Your collision response (what happens when the balls collide) i.e. just reversing the direction of the balls will only work correctly if the balls velocities are the same except for the sign (e.g. vA = 1m/s, vB = -1m/s). In other cases the balls won't bounce as expected.

0
votes

I will look at it properly later on, but at first glance I don't like:

if((Math.abs(b.getX()-p.x)<b.getRadius()+r)&& (Math.abs(b.getY()-p.y)<b.getRadius()+r))

You need something like:

diffX = b.getX() - p.x;
diffY = b.getY() - p.y;
rad1 = this.getRadius();
rad2 = b.getRadius();
if((diffX * diffX + diffY * diffY) < (rad1 * rad1 + rad2 * rad2))

[Edited because balls have different radii]

0
votes

The problem is that when you detect balls collision, you move both balls a point up and left. This causes the balls to move together and not to bounce off.

To achive the desired effect the ball on the left should go -1 and the one on the right +1. Same thing applies for vertical axis, the upper ball should get -1 and the bottom one +1

public void bounceoff(Ball b)          //BALL TO BALL COLLSION DETECTION
{
   float x = b.getX() - p.x;
   float y = b.getY() - p.y;
   float distanceSquared = x*x + y*y;
   float radius = b.getRadius()+r;
   float radiusSquared = radius*radius;
   if (distanceSquared <= radiusSquared)
   {
       dx=dx * -1;
       dy=dy * -1;
       b.setDY(b.getDX()*-1);
       b.setDY(b.getDY()*-1);

       if (x<b.getX()){
           x = x-1;
           b.setX(b.getX()+1);
       }else{
           x = x+1;
           b.setX(b.getX()-1);
       }     
       if (y<b.gety()){
           y = y-1;
           b.setY(b.getY()+1);
       }else{
           y = y+1;
           b.setY(b.getY()-1);
       }     

   }
}

You should also add 2 setters in the Ball class:

public void setX(int x)
{
    p.x = x;
}
public void setY(int y)
{
    p.y = y;
}

public int getDX()
{
    return dx;
}
public int getDY()
{
    return dy;
}

And the onDraw needs some work:

protected void onDraw(Canvas c)
{
    // ball bouncing on walls
    myball.bounce(c);
    greenball.bounce(c);
    redball.bounce(c);

    // balls bouncing on each other
    myball.bounceoff(redball);
    myball.bounceoff(greenball);
    redball.bounceoff(greenball);

    // draw balls
    c.drawCircle(myball.getX(), myball.getY(),myball.getRadius(), myball.getPaint());
    c.drawCircle(greenball.getX(), greenball.getY(),greenball.getRadius(), greenball.getPaint());
    c.drawCircle(redball.getX(), redball.getY(),redball.getRadius(), redball.getPaint());

    h.postDelayed(r, FRAME_RATE);
}
-1
votes

BALL CLASS

    package com.example.bagoriya.bball;

/**
 * Created by Bagoriya on 27/02/2015.
 */

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;

public class Ball {
    private Point point;
    private int c;
    private int r;
    private int dx;
    private int dy;
    private Paint paint;

    public Ball(int x, int y, int col, int radius) {
        point = new Point(x, y);
        c = col;
        r = radius;
        paint = new Paint();
        dx = 0;
        dy = 0;
    }

    public int getX() {
        return point.x;
    }

    public int getY() {
        return point.y;
    }

    public int getRadius() {
        return r;
    }

    public Paint getPaint() {
        paint.setColor(c);
        return paint;
    }

    public void goTo(int x, int y) {
        point.x = x;
        point.y = y;
    }

    public void setDX(int speed) {
        dx = speed;
    }

    public void setDY(int speed) {
        dy = speed;
    }

    public void move() {
        point.x = point.x + dx;
        point.y = point.y + dy;
    }

    public void bounce(Canvas canvas) {
        move();
        if (point.x > canvas.getWidth() - r || point.x - r < 0) {
            dx = dx * -1;
        }
        if (point.y > canvas.getHeight() - r || point.y - r < 0) {
            dy = dy * -1;
        }

    }

    public void bounceoff(Ball b) {
        float dist = b.getX() - point.x;
        float rad = b.getRadius() + r;
        float dif = b.getY() - point.y;
            if ((dist * dist) + (dif * dif) <= (rad * rad)) {
            dx = dx * -1;
            dy = dy * -1;
        }
    }

}

ANIMATIONVIEW CLASS

 package com.example.bagoriya.bball;

/**
 * Created by Bagoriya on 27/02/2015.
 */

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.view.View;

public class AnimationView extends View {
    private final int FRAME_RATE = 15;
    private Paint paint;
    private Handler h;
    Ball myball;
    Ball greenball;
    Ball redball;

    public AnimationView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        h = new Handler();
        paint = new Paint();
        myball = new Ball(100, 100, Color.BLUE, 50);
        greenball = new Ball(200, 200, Color.CYAN, 50);
        redball = new Ball(50, 400, Color.RED, 50);
        myball.setDX(1);
        myball.setDY(1);
        greenball.setDX(-2);
        greenball.setDY(-1);
        redball.setDX(1);
        redball.setDY(-5);

    }

    protected void onDraw(Canvas c) {
        c.drawColor(Color.WHITE);
        myball.bounce(c);
        greenball.bounce(c);
        redball.bounce(c);
        myball.bounceoff(greenball);
        myball.bounceoff(redball);
        greenball.bounceoff(redball);
        greenball.bounceoff(myball);
        redball.bounceoff(myball);
        redball.bounceoff(greenball);
//        myball.bounceoff(myball);
//        greenball.bounceoff(greenball);
//        redball.bounceoff(redball);
        c.drawCircle(myball.getX(), myball.getY(), myball.getRadius(), myball.getPaint());
        c.drawCircle(greenball.getX(), greenball.getY(), greenball.getRadius(), greenball.getPaint());
        c.drawCircle(redball.getX(), redball.getY(), redball.getRadius(), redball.getPaint());
        h.postDelayed(r, FRAME_RATE);

    }

    private Runnable r = new Runnable() {
        public void run() {
            invalidate();
        }
    };
}