2012-01-28 18 views
0

2つのボールの衝突をシミュレートします。一方は加速度計で制御され、もう一方はランダムに動きます。 これらの衝突を実装するにはどうすればよいですか?私はボールと衝突の条件を設定することができましたが、それを超えて、どのようにして衝突ベクトルを表現できるか分かりません。アルゴリズムやヒントが分かるでしょう:)私はxとyの速度と変数に格納された2つのボールの位置を持っています。私はまた、いくつかの基本的な(しかし間違った)衝突メカニズムを使用することに成功しました。ランダムな動きのボールは、そのxとyの速度を逆転させます。しかし、ボールがあまりに速く動いていると、ボールが重なってしまっても問題は発生しています。私は何をしますか?2つのボールの衝突

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());*/ 
     } 
    } 

} 

ボールとテスターは、私の2つのボール、ボールが加速度計によって制御されています。私はこのコードがあまり効率的ではないことを知っていますが、私はまず衝突を実装するつもりだと思っています。

答えて

0

あなたは衝突アルゴリズムを改良する前に、いくつかのことを考慮する必要があります - 衝突が弾性衝突であるか? 2つの球を点源として扱うことができますか?いずれにせよ、あなたの運動量ベクトルは保存されるので、NewtonのP initial = P finalを使って新しいベクトルを決定することができます。

2つのボールが重なっている可能性があります。これは、衝突検出アルゴリズムを実行している速度が、ボールの位置を変更する速度よりも遅いためです。

コードサンプルを投稿すると、より良いお手伝いをすることができます。

+0

まあ、私はそれらを両方とも同じ質量として扱いたいと言っていたことを忘れていました。私は自分のコードを投稿しました。 –

+0

質量を同じように扱うと、運動量方程式の保存が簡単になりますが、運動エネルギーが保存されているかどうかにかかわらず、弾性または非弾性のどちらの衝突であるかを決定する必要があります。 衝突検出の他の問題について、私が気づく最初のことは、ボールを移動した後に衝突検出を行うことです。これは、問題の一部である可能性があります.2つのボールがちょうど交差するときに、それらを互いに近づけると衝突する可能性があります。 – ose

+0

私は弾性衝突を望んでいました。私は衝突検出コードをどこに置くことをお勧めしますか? –

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

それは動作していないように見えますが、両方のボールがコーナー間で非常に速く移動を開始します。私は言及することを忘れて、私は両方の質量を検討している。私は自分のコードを投稿しました。 –

+0

これはボールが速度を変えた直後に何度も何度も衝突が検出されたためです。 「衝突が検出されました - > 100 ms待つ - >新しい衝突を探す」のようなものを追加してみてください –