2012-01-28 117 views
0

我想模拟两个球之间的碰撞,一个由加速度计控制,另一个随机移动。 如何实现这些碰撞?我设法设定了球和碰撞的条件,但除此之外,我不知道如何表示碰撞向量。算法或提示将不胜感激:)我有两个球存储在变量中的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());*/ 
     } 
    } 

} 

球和检测仪是我的两个球,球被加速计控制。我知道代码不是非常高效,但我认为我会先着手实现碰撞。

回答

0

在改进碰撞算法之前,您需要考虑几件事情 - 碰撞是弹性碰撞吗?你能把这两个球当作点源吗?无论哪种方式,你的动量向量将被保留,所以你可以使用牛顿的P initial = P final来确定新的向量。

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

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

+0

嗯,我忘了提及,我想把他们都视为平等的群众(现在)。我已经发布了我的代码。 – 2012-01-28 13:40:03

+0

如果将质量同等对待将简化动量守恒方程,但仍然需要确定它们是弹性碰撞还是非弹性碰撞(无论动能是否守恒)。 关于碰撞检测的其他问题,我注意到的第一件事是在移动球之后进行碰撞检测。这可能是问题的一部分,因为当两个球正要相交时,您可能会将它们靠得更近,因此在您有机会测试碰撞之前它们看起来会重叠。 – ose 2012-01-28 23:15:27

+0

我想要一个弹性碰撞。你建议我把我的碰撞检测代码放在哪里? – 2012-01-29 09:38:06

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 
+0

这似乎不起作用,两个球开始在角落之间非常快速的旅行。我忘了提及,我正在考虑单位群众。我已经发布了我的代码。 – 2012-01-28 13:39:28

+0

这可能是因为撞球在球变速后一次又一次检测到。尝试添加“碰撞检测 - >等待100毫秒 - >开始寻找新的碰撞” – 2012-01-28 15:53:20