【问题标题】:How do I leave a trail behind my animation? [duplicate]如何在动画后面留下痕迹? [复制]
【发布时间】:2016-03-06 01:36:01
【问题描述】:

我有一个程序,它获取空间中两个行星/天体的信息,并逼真地动画它们围绕彼此的轨道。它可以工作,但是当我重新绘制时,它每次都会清除屏幕并且不会留下痕迹。

我的问题是我想留下痕迹,尽管我可以在网上找到的任何答案都只能说明如何摆脱痕迹。不过,我没有这个问题。

在其他计算机上,我可以在我的绘制方法中省略 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;
    }
}
}

【问题讨论】:

    标签: java swing animation


    【解决方案1】:
    1. 自定义绘制是通过覆盖paintComponent() 方法完成的,而不是paint()。

    2. 如果你留下一条连续的轨迹,一旦你进行 360 度旋转,你将看不到任何动画,所以我认为你最终需要清除屏幕。

    如果您想留下痕迹,您可以保留要绘制的对象的ArrayList。然后在paintComponent() 方法中,您可以遍历List。这将允许您从列表中添加/删除对象,以便您可以控制要绘制每个动画的对象数量。

    查看Custom Painting Approaches 中的DrawOnComponent 示例,了解此方法的示例。所以你的动画逻辑基本上会添加一个新的对象(一旦达到一定的限制,可能会删除一个?)到列表中。然后你只需在面板上调用 repaint(),所有的对象都会被绘制。

    您已经有 List 来绘制每个星球。因此,每个动画都需要将每个行星的新位置添加到列表中。

    或者,该链接显示了如何绘制到 BufferedImage。但是这种方法不允许您在完成后删除绘画。因此,这取决于您使用哪种方法的确切要求。

    【讨论】:

      猜你喜欢
      • 2023-04-05
      • 2015-07-08
      • 1970-01-01
      • 2019-05-07
      • 2019-06-09
      • 1970-01-01
      • 1970-01-01
      • 2010-11-04
      • 2011-12-30
      相关资源
      最近更新 更多