两个球之间的碰撞

时间:2012-01-28 11:05:52

标签: android collision-detection

我想模拟两个球之间的碰撞,一个由加速度计控制,另一个随机移动。 我该如何实现这些碰撞?我已经成功设置了球和碰撞的条件,但除此之外,我不知道如何表示碰撞向量。一个算法或提示将被赞赏:)我有两个球的x和y速度和位置存储在变量中。我还设法使用一些基本的(但是错误的)碰撞机制,随机运动球反转其x和y速度。但是我也有问题,如果球移动得太快,它们会重叠。我该怎么办?

package perseus.gfx.test;

import everything;

public class Ball extends View  {   
RectF lol;
Paint paint, lpaint;
Bitmap bitmap;
Canvas canvas;
private float ballx = 150; 
private float bally = 140;
private double speedx = 0;  
private double speedy = 0; //ignore  
private double accx, accy=0;
private float rad = 15;
private float mult = 0.5f;
private float friction = -0.001f;
private double xv, yv, xS, yS;
private long ltm = -1;
int width, height;
int xmax, ymax;
int xmin, ymin;

public Ball(Context context) {
    super(context);
    lol = new RectF();
    paint = new Paint();
    paint.setColor(Color.CYAN);
    lpaint = new Paint();
    lpaint.setColor(Color.GRAY);                


}
public double getSpeedX()
{
    return this.speedx;
}
public double getSpeedY()
{
    return this.speedy;
}
public void setSpeedX(double x)
{
    this.speedx = x;
}
public void setSpeedY(double y)
{
    this.speedy = y;
}
public void setColor(int c)
{
    paint.setColor(c);
}
public float getRad()
{
    return this.rad;
}
public void setRad(float rad)
{
    this.rad = rad;
}
public void setAX(double accx)
{
    this.accx = accx;
}
public void setAY(double accy)
{
    this.accy = accy;
}
public float getX()
{
    return this.ballx;
}
public void setX(float ballx)
{
    this.ballx = ballx;
}
public float getY()
{
    return this.bally;
}
public void setY(float bally)
{
    this.bally = bally;
}
public void moveBall()  {


    xv = accx * mult;
    yv = accy * mult;

    ballx -= xv * mult;
    bally -= yv * mult;

    ballx +=speedx;
    bally +=speedy;


    /*ballx +=speedx;
    bally +=speedy;*/

    // Collision detection
    if (ballx + rad > xmax) {
         speedx = -speedx;     
         ballx = xmax-rad;
    }         
    else if (ballx - rad < 0) {
         speedx = -speedx;
         ballx = rad;
    }
    if (bally + rad > 2*ymax/3) {
        speedy = -speedy;
        bally = 2*ymax/3 - rad;


    } 

    else if (bally - rad < 0) {
         speedy = -speedy;
         bally =  rad;
    }                           

    try {
        Thread.sleep(20);
    }   catch(InterruptedException e) {}

    invalidate();   

}
@Override
public void onMeasure(int widthM, int heightM)
{
    width = View.MeasureSpec.getSize(widthM);
    height = View.MeasureSpec.getSize(heightM);
    xmax = width-1;
    ymax = height-1;
    xmin = 0;
    ymin = 0;
    setMeasuredDimension(width, height);
    bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    canvas = new Canvas(bitmap);


}
@Override
public void onDraw(Canvas canvas)
{
    canvas.drawBitmap(bitmap, 0, 0, paint);
    lol.set(ballx - rad, bally-rad, ballx + rad, bally+rad);
    canvas.drawLine(0, 2*height/3, width, 2*height/3, lpaint);
    /*canvas.drawOval(lol, paint);*/
    canvas.drawCircle(ballx, bally, rad, paint);
    canvas.drawText(xv + " " + yv, 0, height/2, lpaint);
    canvas.save();
    moveBall();
    canvas.restore();

}



}

这是我的球类,我的主要活动是:

package perseus.gfx.test;
import everything;
public class GfxActivity extends Activity implements OnSeekBarChangeListener, OnItemSelectedListener, SensorEventListener {

ViewGroup.LayoutParams vg = new ViewGroup.LayoutParams(-1, -1);
double velx, vely;
double x, y;
float radi;
double finx, finy;
float finrad;

long lastSensorUpdate = -1;
SensorManager sm;
static double ux, uy;   //initial ball velocity
SeekBar velo, rad;
Spinner colour;
Ball ball, tester;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);  

    ball = new Ball(this);
    tester = new Ball(this);
    setContentView(R.layout.main);
    addContentView(ball, vg);

    addContentView(tester, vg);
    sm = (SensorManager)getSystemService(SENSOR_SERVICE);
    sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_GAME);
    colour = (Spinner)findViewById(R.id.color);
    colour.setOnItemSelectedListener(this);
    ArrayAdapter<CharSequence> aa = ArrayAdapter.createFromResource(this, R.array.colors, android.R.layout.simple_spinner_item);
    aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    colour.setAdapter(aa);
    velo = (SeekBar)findViewById(R.id.vel);
    velo.setOnSeekBarChangeListener(this);  
    rad = (SeekBar)findViewById(R.id.rad);
    rad.setOnSeekBarChangeListener(this);
    ux = ball.getSpeedX();
    uy = ball.getSpeedY();   
    radi = ball.getRad();
    tester.setSpeedX(5);
    tester.setSpeedY(3);
    tester.setX(0);
    tester.setY(0);
    tester.setColor(Color.DKGRAY);
}
@Override
public void onProgressChanged(SeekBar seeker, int arg1, boolean arg2) {       
    switch(seeker.getId())
    {
    case R.id.vel:
        x = ball.getSpeedX();
        y = ball.getSpeedY();

        if(x<0)
            finx = -ux-arg1;            
        else if(x >= 0)
            finx = ux+arg1; 

        if(y<0) 
            finy = -uy-arg1;        
        else if(finy>=0)
            finy = uy+arg1;

        ball.setSpeedX(finx);
        ball.setSpeedY(finy);
        break;

    case R.id.rad:          
        finrad = radi + arg1;
        ball.setRad(finrad);
        break;
    }   
}
@Override
public void onStartTrackingTouch(SeekBar arg0) {
    //nothing lol
}
@Override
public void onStopTrackingTouch(SeekBar arg0) {
    //nothing lol
}

@Override
public void onItemSelected(AdapterView<?> parent, View v, int position,
        long id) {
    switch(position)
    {
    case 0:
        ball.setColor(Color.CYAN);
        break;
    case 1:
        ball.setColor(Color.RED);
        break;
    case 2:
        ball.setColor(Color.BLUE);
        break;
    case 3:
        ball.setColor(Color.GREEN);
        break;
    }

}
@Override
public void onNothingSelected(AdapterView<?> arg0) {

}
@Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
    // TODO Auto-generated method stub

}
@Override
public void onSensorChanged(SensorEvent sensorevent) {
    if(sensorevent.sensor.getType() == Sensor.TYPE_ORIENTATION)
    {
            ball.setAX(sensorevent.values[2]);
            ball.setAY(sensorevent.values[1]);                          
    }

        if((Math.pow(ball.getX() - tester.getX(), 2) + Math.pow(ball.getY() - tester.getY(), 2)) <= (ball.getRad() + tester.getRad())*(ball.getRad() + tester.getRad()))
        {

                /*tester.setSpeedX(-1*tester.getSpeedX());
                tester.setSpeedY(-1*tester.getSpeedY());*/
        }
    }

}

Ball and Tester是我的两个球,Ball由加速度计控制。我知道代码效率不高,但我想我会先实现碰撞。

2 个答案:

答案 0 :(得分:0)

在优化碰撞算法之前,你需要考虑几件事 - 碰撞是弹性碰撞吗?你能把这两个球当作点源吗?无论哪种方式,您的动量矢量都将被保存,因此您可以使用Newton的P initial = P final来确定新的矢量。

两个球可能重叠,因为你运行碰撞检测算法的速度比你改变球的位置的速度慢。

如果您发布代码示例,我们可以为您提供更好的帮助。

答案 1 :(得分:0)

考虑到你有xVel1,yVel1,xVel2,yVel2; xPos1,yPos1,xPos2,yPos2; mass1,mass2;检测到碰撞后:

double theta = Math.atan2(yPos1-yPos2, xPos1-xPos2);
double c = Math.cos(theta);
double s = Math.sin(theta);
double xVel1prime = xVel1*c+yVel1*s;
double xVel2prime = xVel2*c+yVel2*s;
double yVel1prime = yVel1*c-xVel1*s;
double yVel2prime = yVel2*c-xVel2*s;
double P = (mass1*xVel1prime+mass2*xVel2prime);
double V = (xVel1prime-xVel2prime);
double v2f = (P+mass1*V)/(mass1+mass2);
double v1f = v2f-xVel1prime+xVel2prime;
xVel1prime = v1f;
xVel2prime = v2f;

xVel1 = xVel1prime*c-yVel1prime*s;
xVel2 = xVel2prime*c-yVel2prime*s;
yVel1 = yVel1prime*c+xVel1prime*s;
yVel2 = yVel2prime*c+xVel2prime*s;
//velocities updated