2017-02-23 4 views
0

Ich mache einen rudimentären Partikelsimulator in Java. Für jetzt, alles was ich getan habe, ist, dass die Partikel sich gegenseitig mit einem Äquivalent der elektrischen Kraft anziehen. Dieser Teil funktioniert gut (oder zumindest so gut, wie Sie es für ein solches Basismodell erwarten würden).Variable Werte verschwinden in Java

Wenn ich jedoch ein paar Partikel hinzufüge, verliert das Programm seine Werte für Position, Geschwindigkeit und Beschleunigung, verliert aber keine anderen Daten (wie z. B. ihre ID-Nummer). Dies geschieht nicht immer mit der gleichen Menge an Partikeln. Manchmal passiert es, wenn ich das vierte, fünfte, zweite oder dritte Teilchen addiere, aber niemals mit dem ersten. Es passiert immer, wenn ich klicke, um ein Partikel hinzuzufügen, und nachdem es fehlschlägt, kann ich nichts hinzufügen (was ungerade ist), und die Partikel bewegen sich nicht mehr (wie man es erwarten würde, sind ihre Geschwindigkeiten und Beschleunigungen 0).

Ich speichere die Partikel in einer ArrayList. Das Array verliert die Daten nicht (ich habe überprüft, die Objekte sind dort und ich kann sogar ihre toString() -Methode aufrufen und ihre ID abrufen). Das Problem scheint mit der Synchronisation zu tun zu haben (da es nicht immer im selben Moment passiert, scheint es ein bisschen zufällig zu sein), aber ich kann nicht herausfinden, was es ist.

Ich lasse alle relevanten Code unten.

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

gibt es nichts zu synchronisieren. Warum synchronisierst du ParticleLock? Synchronisation spielt hier keine Rolle. Sie synchronisieren PartikelLock, aber Sie verwenden keine Daten von diesem Objekt. Was ist der Zweck von ParticleLock? – hhafeez

+0

@hhafeez Offensichtlich synchronisiert er, so dass er nicht zur gleichen Zeit zum Array hinzufügt, während er es durchläuft, wodurch das Risiko einer ConcurrentModificationException beseitigt wird. –

+0

Aber er synchronisiert nicht das arrya, das die tatsächliche zu synchronisierende Ressource ist – hhafeez

Antwort

0

ich einmal ein ähnliches Problem mit Synchronisation hatte, als ich auf einem Android-Projekt arbeitete, versuchen particleArray flüchtig erklärt, so dass der Compiler weiß, dass particleArray auf andere oder mehrere Threads geändert werden. Wenn das nicht funktioniert, würde ich vorschlagen, eine Warteschlange zu verwenden, um Änderungen aus verschiedenen Threads in das Partikel-Array zu übertragen und dann die beabsichtigten Änderungen in die Array-Liste der Update-Methode zu übernehmen, um Ihre Partikel-Array-Liste zu aktualisieren. Nach meiner Erfahrung verursacht das Ändern von Werten direkt zwischen verschiedenen Threads fast immer Probleme.

+0

Ich sehe keine Thread-Beteiligung in den Code, aber wenn es dann definitiv Array sollte als flüchtig erklärt werden – hhafeez

+0

danke! Ich habe versucht, es volatil zu erklären, aber es hat nicht funktioniert. Ich bin mir nicht sicher, ob ich weiß, wie ich das mache, was du beschreibst. –

+0

@NicolasMartorell Welche Variable haben Sie volatil gemacht? – hhafeez