2017-02-23 19 views
0

我正在Java中製作一個基本的粒子模擬器。就目前而言,我所做的一切就是讓粒子彼此以相當於電力的方式相互碰撞。這部分工作正常(或至少如你所期望的這樣的基本模型)。但是,當我添加一些粒子時,程序會丟失它們的位置,速度和加速度值,但不會丟失其他數據(例如它們的ID號)。對於相同數量的粒子,這並不總是會發生。有時會發生,當我添加第四,第五,第二或第三個粒子,但從來沒有與第一個粒子。它總是發生在我點擊添加一個粒子時,並且在它失敗後,我不能再添加任何東西(這是奇怪的),並且粒子不再移動(如你所期望的那樣,它們的速度和加速度爲0)。變量值在Java中消失

我將粒子存儲在ArrayList中。該數組不會丟失數據(我檢查過,對象在那裏,我甚至可以調用它們的toString()方法並檢索它們的ID)。這個問題似乎與同步有關(因爲它不總是同時發生,似乎有點隨機),但我無法弄清楚它是什麼。

我在下面留下了所有相關的代碼。

public class Scene implements KeyListener, MouseListener, MouseMotionListener{ 

    public static ArrayList<Particle> particleArray = new ArrayList<Particle>(); 

    public static Object particleLock = new Object(); 

    public void update() { 

     synchronized(particleLock) { 
      for(Particle particle: particleArray) { 
       double resultX = 0; 
       double resultY = 0; 

       for(int i = 0; i<particleArray.size(); i++) { 
        if(i != particleArray.indexOf(particle)) { 
         double[] result = PhysicsEngine.applyElectircalForce(particle, particleArray.get(i)); 
         resultX += result[0]; 
         resultY += result[1]; 
        } 
       } 

       particle.netForceX = resultX; 
       particle.netForceY = resultY; 

       particle.update(); 
      } 
     } 
    } 

public void mousePressed(MouseEvent e) { 
     int mouseX = e.getX(); 
     int mouseY = e.getY(); 
     boolean positive = true; 

     if(e.getButton() == MouseEvent.BUTTON1) { 
      positive = true; 
     } else if(e.getButton() == MouseEvent.BUTTON3) { 
      positive = false; 
     } 


     synchronized(particleLock){ 
      particleArray.add(new Particle(mouseX, mouseY, positive)); 
      System.out.println("New particle added at " + mouseX + ", " + mouseY); 
     } 
    } 
} 

public class Particle{ 

public double x; 
    public double y; 

    public Point2D position; 

    public double velX; 
    public double velY; 

    public double acX; 
    public double acY; 

    private Color particleColor; 
    private int radius = 10; 


    // PHYSICS 
    public double mass; 
    public double charge; 
    public double netForceX; 
    public double netForceY; 

    private boolean positive; 

public Particle(double x, double y, boolean positive) { 
     this.x = x - radius; 
     this.y = y - radius; 

     this.velX = 3; 
     this.velY = 2; 

     this.acX = 0; 
     this.acY = 0; 

     this.mass = 100; 
     this.positive = positive; 

     if(positive) { 
      this.charge = defaultCharge; 
     } else { 
      this.charge = defaultCharge*(-1); 
     } 

     this.position = new Point2D.Double(x, y); 

     particleColor = Color.WHITE; 
} 

public void update() { 

     acX = netForceX/mass; 
     acY = netForceY/mass; 

     velX += acX; 
     velY += acY; 

     if(x<=0 || x>=Simulation.WIDTH - 23){ 
      velX = velX * -1; 
      x+= velX; 
     } 

     if(y<=0 || y>=Simulation.HEIGHT - 35){ 
      velY = velY * -1; 
      y+= velY; 
     } 

     synchronized(Scene.particleLock) { 
      for(Particle otherPart: Scene.particleArray) { 

       if(otherPart.equals(this)) { 
        continue; 
       } 

       double distance = otherPart.position.distance(position); 


       if(distance <= radius + otherPart.radius) { 
        //aplicar lo que sé de choques de alguna manera 
       } 
      } 
     } 

     x+= velX; 
     y+= velY; 

     position.setLocation(x, y); 
    } 
} 

public class PhysicsEngine { 

    static double electricalConstant = 100000; 

    public static double[] applyElectircalForce(Particle thisPart, Particle otherPart) { 

     double distance = otherPart.position.distance(thisPart.position); 

     double angle = Math.asin(Math.abs(thisPart.y - otherPart.y)/distance); 

     double force = (electricalConstant * thisPart.charge * otherPart.charge)/Math.pow(distance, 2); 

     double forceX = force * Math.cos(angle); 
     double forceY = force * Math.sin(angle); 

     if(otherPart.x < thisPart.x) { 
      forceX = forceX*(-1); 
     } 

     if(otherPart.y < thisPart.y) { 
      forceY = forceY*(-1); 
     } 

     double[] result = {forceX, forceY}; 

     return result; 
    } 
} 
+0

沒有什麼要同步的。你爲什麼要同步particleLock?同步在這裏沒有任何作用。您正在同步particleLock,但您沒有使用此對象的任何數據。 particleLock的目的是什麼? – hhafeez

+0

@hhafeez顯然,他正在進行同步,因此他不會在迭代數組的同時添加到數組中,從而消除了ConcurrentModificationException的風險。 –

+0

但他沒有同步作爲實際資源的arrya要同步 – hhafeez

回答

0

我曾經與當時我正致力於在Android項目同步類似的問題,嘗試宣告particleArray揮發性的,以便編譯器知道particleArray將在其他或多個線程改變。如果這不起作用,我會建議使用隊列將更改推送到來自不同線程的粒子陣列,然後將更改的方法中的預期更改拖到陣列列表中以更新粒子陣列列表。根據我的經驗,直接在不同線程間改變值幾乎總是會導致問題。

+0

我沒有看到代碼中有任何線程參與,但是如果有肯定的數組應該聲明爲volatile – hhafeez

+0

謝謝!我試圖宣佈它不穩定,但沒有奏效。我不知道我知道如何去做你所描述的。 –

+0

@NicolasMartorell你製作的變量是什麼變量? – hhafeez