2016-03-05 61 views
1

我有一個程序,可以獲取關於太空中兩個行星/物體的信息,並且可以實現彼此之間的軌道動畫。它可以工作,但是當我重新繪製時,它會每次清除屏幕並且不會留下蹤跡。如何在我的動畫背後留下蹤跡?

我的問題是,我想留下一條線索,儘管我可以在網上找到的任何答案只解釋如何擺脫線索。但是,我沒有這個問題。

在其他計算機上,我可以在我的paint方法中省略super.paintComponent(),並導致它留下蹤跡,但在此計算機上,它不這樣做,它似乎自動清除屏幕。那麼我怎樣纔能有效地在我的軌道行星後面畫出一條線索呢?我的代碼如下。

JPanel類第一:

import javax.swing.*; 
import java.awt.*; 
/** 
* Created by chris on 3/2/16. 
*/ 
public class SpacePanel2 extends JPanel{ 
private Body2[] planets; 
public static final Dimension SCREENSIZE = Toolkit.getDefaultToolkit().getScreenSize(); 
public static double scale = 5e6; //m/p 
public static Color[] colors = {Color.black, Color.red}; 

public SpacePanel2(Body2[] planets) { 
    this.planets = planets; 
    this.setPreferredSize(SCREENSIZE); 
} 

@Override 
public void paint(Graphics g){ 
    for (int i = 0; i < planets.length; i++) { 
     g.setColor(colors[i]); 
     int r = planets[i].getPixelRadius()/2; 
     int x = planets[i].getPixelX(); 
     int y = planets[i].getPixelY(); 
     g.fillOval(x, y, r, r); 
    } 
} 
} 

體類:

/** 
    * Created by chris on 3/2/16. 
*/ 
public class Body2 { 
private double mass; //in kilograms 
private double radius; //in meters 
private static final double GRAVITATIONAL_CONSTANT = 6.67408e-11; 
private static final double AVERAGE_DENSITY = 5515; //kg/m^3 

/** 
* Movement variables 
*/ 
private double dx; //in m/s 
private double dy; //in m/s 

private double x; //in m 
private double y; //in m 

public Body2() { 
    radius = 1; 
    mass = AVERAGE_DENSITY; 
    x = 0; 
    y = 0; 
    dx = 0; 
    dy = 0; 
} 

public double getX() { 
    return x; 
} 

public double getY() { 
    return y; 
} 

public double getMass() { 
    return mass; 
} 

public double getRadius() { 
    return radius; 
} 


public int getPixelX() { 
    return (int)((this.x-radius)/SpacePanel2.scale); 
} 

public int getPixelY() { 
    return (int)((this.y-radius)/SpacePanel2.scale); 
} 
public int getPixelRadius(){ 
    return (int)(this.radius/SpacePanel2.scale); 
} 

public void setMass(double mass) { 
    this.mass = mass; 
} 

public void setRadius(double radius) { 
    this.radius = radius; 
} 

public void setDx(double dx) { 
    this.dx = dx; 
} 

public void setDy(double dy) { 
    this.dy = dy; 
} 

public void setX(double x) { 
    this.x = x; 
} 

public void setY(double y) { 
    this.y = y; 
} 


public void exertForce2(double diffY, double diffX, double F){ 
    double dist = Math.sqrt(diffY*diffY + diffX*diffX); 
    double ratio = F/dist; 
    this.dy = this.dy + ratio*diffY/this.mass; 
    this.dx = this.dx + ratio*diffX/this.mass; 
} 

public void tick(double timeScale) { 
    x+=(dx/1000.0)*timeScale; 
    y+=(dy/1000.0)*timeScale; 
} 

public static double getForce(Body2 a, Body2 b){ 
    double dX = a.getX() - b.getX(); 
    double dY = a.getY() - b.getY(); 
    double distance = Math.sqrt(Math.pow(dX,2)+Math.pow(dY,2)); 
    return (a.getMass()*b.getMass()*GRAVITATIONAL_CONSTANT)/(distance*distance); 
} 

public static double getStandardMass(double radius){ 
    return (4.0/3.0)*Math.pow(radius, 3) * Math.PI; 
} 

public double getDy() { 
    return dy; 
} 

public double getDx() { 
    return dx; 
} 

public static double predictCentripetalForce(Body2 sun, Body2 planet){ 
    return Math.sqrt(getForce(planet, sun)*(sun.getY()-planet.getY())/planet.mass); 
} 
} 

主要類:

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.KeyEvent; 
import java.awt.event.KeyListener; 

/** 
* Created by chris on 3/2/16. 
*/ 
public class MainSpace2 { 
static JFrame frame; 
static SpacePanel2 panel; 

static int fps = 60; 
static boolean getLarger = false; 
static boolean getSmaller = false; 
static Dimension size = Toolkit.getDefaultToolkit().getScreenSize(); 

public static void main(String[] args) { 

    Body2[] test = new Body2[2]; 

    Body2 sun = new Body2(); 
    sun.setRadius(696300000); 
    sun.setMass(1.989e30); 
    sun.setX(getScope('x')/2); 
    sun.setY(getScope('y')/2); 
    sun.setDx(0); 
    sun.setDy(0); 
    test[0] = sun; 
    int literalSizeSun = (int)(sun.getRadius()/SpacePanel2.scale); 

    Body2 mercury = new Body2(); 
    mercury.setRadius(24400000); 
    mercury.setMass(Body2.getStandardMass(mercury.getRadius())); 
    mercury.setDx(Body2.predictCentripetalForce(sun, mercury)*2); 
    mercury.setDy(0); 
    mercury.setX(sun.getX()); 
    mercury.setY(sun.getY() + 2 * sun.getRadius()); 
    test[1] = mercury; 
    int literalSizeMercury = (int)(mercury.getRadius()/SpacePanel2.scale); 


    frame = new JFrame(); 
    frame.setPreferredSize(size); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    panel = new SpacePanel2(test); 

    frame.addKeyListener(new KeyListener() { 
     @Override 
     public void keyTyped(KeyEvent e) { 

     } 

     @Override 
     public void keyPressed(KeyEvent e) { 
      switch (e.getKeyChar()) { 
       case '-': 
        getSmaller = true; 
        getLarger = false; 
        break; 
       case '=': 
        getLarger = true; 
        getSmaller = false; 
        break; 
      } 
     } 

     @Override 
     public void keyReleased(KeyEvent e) { 
      switch (e.getKeyChar()) { 
       case '-': 
        getSmaller = false; 
        break; 
       case '=': 
        getLarger = false; 
        break; 
      } 
     } 
    }); 

    double timeScale = 60*24; 
    Timer time = new Timer((int) (1000.0/fps), new ActionListener() { 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      double F = Body2.getForce(test[0], test[1]); 
      double dY = test[1].getY() - test[0].getY(); 
      double dX = test[1].getX() - test[0].getX(); 
      test[0].exertForce2(dY, dX, F); 
      test[1].exertForce2(-dY, -dX, F); 
      for (int j = 0; j < test.length; j++) { 
       test[j].tick(timeScale); 
      } 
      panel.repaint(sun.getPixelX(), sun.getPixelY(), literalSizeSun, literalSizeSun); 
      panel.repaint(mercury.getPixelX(), mercury.getPixelY(), literalSizeMercury, literalSizeMercury); 
     } 
    }); 

    frame.add(panel); 
    frame.pack(); 
    frame.setVisible(true); 
    time.start(); 
} 

public static double getScope(char k) { 
    switch (k) { 
     case 'x': 
      return size.width * SpacePanel2.scale; 
     case 'y': 
      return size.height * SpacePanel2.scale; 
     default: 
      return 0; 
    } 
} 
} 

回答

2
  1. 風俗畫是通過覆蓋paintComponent()方法進行,而不是油漆()。

  2. 如果你離開一個連續的線索,一旦你做轉動360°,你不會看到任何更多的動畫,所以我會認爲你需要最終清除屏幕。

如果您想留下足跡,您可以保留要繪製的對象的ArrayList。然後在paintComponent()方法中,您可以遍歷List。這將允許您從列表中添加/刪除對象,以便您可以控制要繪製每個動畫的對象的數量。

有關此方法的示例,請查看Custom Painting ApproachesDrawOnComponent示例。因此,您的動畫邏輯基本上會添加一個新的對象(並且可能會在您達到某個限制時將其刪除)。然後你只需在面板上調用repaint(),所有的對象都會被繪製。

你已經有列表來繪製每個星球。因此,每個動畫都需要將每個星球的新位置添加到列表中。

或者,鏈接顯示如何繪製到BufferedImage。但是這種方法不允許你在完成繪畫後刪除繪畫。所以這取決於你的確切需求你使用哪種方法。